1import { diffByUnit, diffDay, diffDayTime } from '../../util'
2import EventDateProfile from './EventDateProfile'
3
4
5export default class EventDefDateMutation {
6
7  clearEnd: boolean = false
8  forceTimed: boolean = false
9  forceAllDay: boolean = false
10
11  // Durations. if 0-ms duration, will be null instead.
12  // Callers should not set this directly.
13  dateDelta: any
14  startDelta: any
15  endDelta: any
16
17
18  static createFromDiff(dateProfile0, dateProfile1, largeUnit) {
19    let clearEnd = dateProfile0.end && !dateProfile1.end
20    let forceTimed = dateProfile0.isAllDay() && !dateProfile1.isAllDay()
21    let forceAllDay = !dateProfile0.isAllDay() && dateProfile1.isAllDay()
22    let dateDelta
23    let endDiff
24    let endDelta
25    let mutation
26
27    // subtracts the dates in the appropriate way, returning a duration
28    function subtractDates(date1, date0) { // date1 - date0
29      if (largeUnit) {
30        return diffByUnit(date1, date0, largeUnit) // poorly named
31      } else if (dateProfile1.isAllDay()) {
32        return diffDay(date1, date0) // poorly named
33      } else {
34        return diffDayTime(date1, date0) // poorly named
35      }
36    }
37
38    dateDelta = subtractDates(dateProfile1.start, dateProfile0.start)
39
40    if (dateProfile1.end) {
41      // use unzonedRanges because dateProfile0.end might be null
42      endDiff = subtractDates(
43        dateProfile1.unzonedRange.getEnd(),
44        dateProfile0.unzonedRange.getEnd()
45      )
46      endDelta = endDiff.subtract(dateDelta)
47    }
48
49    mutation = new EventDefDateMutation()
50    mutation.clearEnd = clearEnd
51    mutation.forceTimed = forceTimed
52    mutation.forceAllDay = forceAllDay
53    mutation.setDateDelta(dateDelta)
54    mutation.setEndDelta(endDelta)
55
56    return mutation
57  }
58
59
60  /*
61  returns an undo function.
62  */
63  buildNewDateProfile(eventDateProfile, calendar) {
64    let start = eventDateProfile.start.clone()
65    let end = null
66    let shouldRezone = false
67
68    if (eventDateProfile.end && !this.clearEnd) {
69      end = eventDateProfile.end.clone()
70    } else if (this.endDelta && !end) {
71      end = calendar.getDefaultEventEnd(eventDateProfile.isAllDay(), start)
72    }
73
74    if (this.forceTimed) {
75      shouldRezone = true
76
77      if (!start.hasTime()) {
78        start.time(0)
79      }
80
81      if (end && !end.hasTime()) {
82        end.time(0)
83      }
84    } else if (this.forceAllDay) {
85
86      if (start.hasTime()) {
87        start.stripTime()
88      }
89
90      if (end && end.hasTime()) {
91        end.stripTime()
92      }
93    }
94
95    if (this.dateDelta) {
96      shouldRezone = true
97
98      start.add(this.dateDelta)
99
100      if (end) {
101        end.add(this.dateDelta)
102      }
103    }
104
105    // do this before adding startDelta to start, so we can work off of start
106    if (this.endDelta) {
107      shouldRezone = true
108
109      end.add(this.endDelta)
110    }
111
112    if (this.startDelta) {
113      shouldRezone = true
114
115      start.add(this.startDelta)
116    }
117
118    if (shouldRezone) {
119      start = calendar.applyTimezone(start)
120
121      if (end) {
122        end = calendar.applyTimezone(end)
123      }
124    }
125
126    // TODO: okay to access calendar option?
127    if (!end && calendar.opt('forceEventDuration')) {
128      end = calendar.getDefaultEventEnd(eventDateProfile.isAllDay(), start)
129    }
130
131    return new EventDateProfile(start, end, calendar)
132  }
133
134
135  setDateDelta(dateDelta) {
136    if (dateDelta && dateDelta.valueOf()) {
137      this.dateDelta = dateDelta
138    } else {
139      this.dateDelta = null
140    }
141  }
142
143
144  setStartDelta(startDelta) {
145    if (startDelta && startDelta.valueOf()) {
146      this.startDelta = startDelta
147    } else {
148      this.startDelta = null
149    }
150  }
151
152
153  setEndDelta(endDelta) {
154    if (endDelta && endDelta.valueOf()) {
155      this.endDelta = endDelta
156    } else {
157      this.endDelta = null
158    }
159  }
160
161
162  isEmpty() {
163    return !this.clearEnd && !this.forceTimed && !this.forceAllDay &&
164      !this.dateDelta && !this.startDelta && !this.endDelta
165  }
166
167}
168