001    /*
002     * SonarQube, open source software quality management tool.
003     * Copyright (C) 2008-2013 SonarSource
004     * mailto:contact AT sonarsource DOT com
005     *
006     * SonarQube is free software; you can redistribute it and/or
007     * modify it under the terms of the GNU Lesser General Public
008     * License as published by the Free Software Foundation; either
009     * version 3 of the License, or (at your option) any later version.
010     *
011     * SonarQube is distributed in the hope that it will be useful,
012     * but WITHOUT ANY WARRANTY; without even the implied warranty of
013     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014     * Lesser General Public License for more details.
015     *
016     * You should have received a copy of the GNU Lesser General Public License
017     * along with this program; if not, write to the Free Software Foundation,
018     * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
019     */
020    
021    package org.sonar.api.utils.internal;
022    
023    import com.google.common.annotations.VisibleForTesting;
024    import org.apache.commons.lang.builder.ToStringBuilder;
025    import org.apache.commons.lang.builder.ToStringStyle;
026    
027    import javax.annotation.Nullable;
028    
029    import java.io.Serializable;
030    
031    /**
032     * Please do not use this class, it will be refactored in 4.3
033     *
034     * @since 4.2
035     */
036    public class WorkDuration implements Serializable {
037    
038      static final int DAY_POSITION_IN_LONG = 10000;
039      static final int HOUR_POSITION_IN_LONG = 100;
040      static final int MINUTE_POSITION_IN_LONG = 1;
041    
042      public static enum UNIT {
043        DAYS, HOURS, MINUTES
044      }
045    
046      private int hoursInDay;
047    
048      private long durationInSeconds;
049      private int days;
050      private int hours;
051      private int minutes;
052    
053      private WorkDuration(long durationInSeconds, int days, int hours, int minutes, int hoursInDay) {
054        this.durationInSeconds = durationInSeconds;
055        this.days = days;
056        this.hours = hours;
057        this.minutes = minutes;
058        this.hoursInDay = hoursInDay;
059      }
060    
061      public static WorkDuration create(int days, int hours, int minutes, int hoursInDay) {
062        long durationInSeconds = 3600L * days * hoursInDay;
063        durationInSeconds += 3600L * hours;
064        durationInSeconds += 60L * minutes;
065        return new WorkDuration(durationInSeconds, days, hours, minutes, hoursInDay);
066      }
067    
068      public static WorkDuration createFromValueAndUnit(int value, UNIT unit, int hoursInDay) {
069        switch (unit) {
070          case DAYS:
071            return create(value, 0, 0, hoursInDay);
072          case HOURS:
073            return create(0, value, 0, hoursInDay);
074          case MINUTES:
075            return create(0, 0, value, hoursInDay);
076          default:
077            throw new IllegalStateException("Cannot create work duration");
078        }
079      }
080    
081      static WorkDuration createFromLong(long duration, int hoursInDay) {
082        int days = 0, hours = 0, minutes = 0;
083    
084        long time = duration;
085        Long currentTime = time / WorkDuration.DAY_POSITION_IN_LONG;
086        if (currentTime > 0) {
087          days = (currentTime.intValue());
088          time = time - (currentTime * WorkDuration.DAY_POSITION_IN_LONG);
089        }
090    
091        currentTime = time / WorkDuration.HOUR_POSITION_IN_LONG;
092        if (currentTime > 0) {
093          hours = currentTime.intValue();
094          time = time - (currentTime * WorkDuration.HOUR_POSITION_IN_LONG);
095        }
096    
097        currentTime = time / WorkDuration.MINUTE_POSITION_IN_LONG;
098        if (currentTime > 0) {
099          minutes = currentTime.intValue();
100        }
101        return WorkDuration.create(days, hours, minutes, hoursInDay);
102      }
103    
104      static WorkDuration createFromSeconds(long seconds, int hoursInDay) {
105        int days = (int) (seconds / hoursInDay / 60f / 60f);
106        long currentDurationInSeconds = seconds - (3600L * days * hoursInDay);
107        int hours = (int) (currentDurationInSeconds / 60f / 60f);
108        currentDurationInSeconds = currentDurationInSeconds - (3600L * hours);
109        int minutes = (int) (currentDurationInSeconds / 60f);
110        return new WorkDuration(seconds, days, hours, minutes, hoursInDay);
111      }
112    
113      /**
114       * Return the duration in number of working days.
115       * For instance, 3 days and 4 hours will return 3.5 days (if hoursIndDay is 8).
116       */
117      public double toWorkingDays() {
118        return durationInSeconds / 60d / 60d / hoursInDay;
119      }
120    
121      /**
122       * Return the duration using the following format DDHHMM, where DD is the number of days, HH is the number of months, and MM the number of minutes.
123       * For instance, 3 days and 4 hours will return 030400 (if hoursIndDay is 8).
124       */
125      public long toLong() {
126        int workingDays = days;
127        int workingHours = hours;
128        if (hours >= hoursInDay) {
129          int nbAdditionalDays = hours / hoursInDay;
130          workingDays += nbAdditionalDays;
131          workingHours = hours - (nbAdditionalDays * hoursInDay);
132        }
133        return workingDays * DAY_POSITION_IN_LONG + workingHours * HOUR_POSITION_IN_LONG + minutes * MINUTE_POSITION_IN_LONG;
134      }
135    
136      public long toSeconds() {
137        return durationInSeconds;
138      }
139    
140      public WorkDuration add(@Nullable WorkDuration with) {
141        if (with != null) {
142          return WorkDuration.createFromSeconds(this.toSeconds() + with.toSeconds(), this.hoursInDay);
143        } else {
144          return this;
145        }
146      }
147    
148      public WorkDuration subtract(@Nullable WorkDuration with) {
149        if (with != null) {
150          return WorkDuration.createFromSeconds(this.toSeconds() - with.toSeconds(), this.hoursInDay);
151        } else {
152          return this;
153        }
154      }
155    
156      public WorkDuration multiply(int factor) {
157        return WorkDuration.createFromSeconds(this.toSeconds() * factor, this.hoursInDay);
158      }
159    
160      public int days() {
161        return days;
162      }
163    
164      public int hours() {
165        return hours;
166      }
167    
168      public int minutes() {
169        return minutes;
170      }
171    
172      @VisibleForTesting
173      int hoursInDay() {
174        return hoursInDay;
175      }
176    
177      @Override
178      public boolean equals(Object o) {
179        if (this == o) {
180          return true;
181        }
182        if (o == null || getClass() != o.getClass()) {
183          return false;
184        }
185    
186        WorkDuration that = (WorkDuration) o;
187        if (durationInSeconds != that.durationInSeconds) {
188          return false;
189        }
190    
191        return true;
192      }
193    
194      @Override
195      public int hashCode() {
196        return (int) (durationInSeconds ^ (durationInSeconds >>> 32));
197      }
198    
199      @Override
200      public String toString() {
201        return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
202      }
203    }