a1cf615da09e69fe853d90e8c93417efec4bec6e
[aquarium] / src / main / scala / gr / grnet / aquarium / logic / accounting / dsl / DSLTimeSpec.scala
1 /*
2  * Copyright 2011-2012 GRNET S.A. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or
5  * without modification, are permitted provided that the following
6  * conditions are met:
7  *
8  *   1. Redistributions of source code must retain the above
9  *      copyright notice, this list of conditions and the following
10  *      disclaimer.
11  *
12  *   2. Redistributions in binary form must reproduce the above
13  *      copyright notice, this list of conditions and the following
14  *      disclaimer in the documentation and/or other materials
15  *      provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
18  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
21  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
24  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  *
30  * The views and conclusions contained in the software and
31  * documentation are those of the authors and should not be
32  * interpreted as representing official policies, either expressed
33  * or implied, of GRNET S.A.
34  */
35
36 package gr.grnet.aquarium.logic.accounting.dsl
37
38 import java.util.{GregorianCalendar, Date, Calendar}
39 import collection.mutable
40
41 /**
42  * Represents an instance of an expanded cronstring declaration. Enforces,
43  * at object creation time, the following conditions:
44  *
45  *  - 0 < `min` < 60
46  *  - 0 < `hour` < 24
47  *  - -1 < `dom` < 31 and `dom` not equal to 0
48  *  - -1 < `mon` < 12 and `mon` not equal to 0
49  *  - -1 < `dow` < 7
50  * 
51  * A value of -1 for the fields `dom`,`mon` and `dow` means that the defined
52  * time moment can be repeated within a timeframe.
53  * `min` and `hour` fields cannot be used to define repetitive time moments.
54  *
55  * @author Georgios Gousios <gousiosg@gmail.com>
56  */
57   case class DSLTimeSpec(
58     min: Int,
59     hour: Int,
60     dom: Int,
61     mon: Int,
62     dow: Int
63   ) extends DSLItem {
64   //Preconditions to force correct values on object creation
65   assert(0 <= min && 60 > min)
66   assert(0 <= hour && 24 > hour)
67   assert(-1 <= dom && 31 > dom && dom != 0)
68   assert(-1 <= mon && 12 > mon && mon != 0)
69   assert(-1 <= dow && 7 > dow)
70
71   /* calendar-related methods*/
72   private val cal = new GregorianCalendar()
73   private def initDay(init:Long) {
74     cal.setTimeInMillis(init)
75     cal.set(Calendar.MINUTE,min)
76     cal.set(Calendar.HOUR_OF_DAY,hour)
77     cal.set(Calendar.SECOND,0)
78   }
79   private def nextValidDay(end:Long) (): Date = {
80     var ret : Date = null
81     while (cal.getTimeInMillis <= end && ret == null) {
82       val valid : Boolean = (mon < 0  || cal.get(Calendar.MONTH) == getCalendarMonth()) &&
83                             (dom < 0  || cal.get(Calendar.DAY_OF_MONTH) == dom) &&
84                             (dow < 0  || cal.get(Calendar.DAY_OF_WEEK) == getCalendarDow())
85       if(valid)
86          ret = cal.getTime
87       cal.add(Calendar.DAY_OF_YEAR, 1)
88     }
89     ret
90   }
91
92   def expandTimeSpec(from: Date,  to: Date) : List[Date] = {
93     val result = new mutable.ListBuffer[Date]()
94     val nextDay = this.nextValidDay (to.getTime) _
95     var d : Date = null
96     initDay(from.getTime)
97     while({d=nextDay();d}!=null) result += d
98     result.toList
99   }
100
101   /** Day of week conversions to stay compatible with [[java.util.Calendar]] */
102   private def getCalendarDow(): Int = dow match {
103     case 0 => Calendar.SUNDAY
104     case 1 => Calendar.MONDAY
105     case 2 => Calendar.TUESDAY
106     case 3 => Calendar.WEDNESDAY
107     case 4 => Calendar.THURSDAY
108     case 5 => Calendar.FRIDAY
109     case 6 => Calendar.SATURDAY
110     case 7 => Calendar.SUNDAY
111   }
112
113   /** Month conversions to stay compatible with [[java.util.Calendar]] */
114   private def getCalendarMonth(): Int = mon match {
115     case 1 => Calendar.JANUARY
116     case 2 => Calendar.FEBRUARY
117     case 3 => Calendar.MARCH
118     case 4 => Calendar.APRIL
119     case 5 => Calendar.MAY
120     case 6 => Calendar.JUNE
121     case 7 => Calendar.JULY
122     case 8 => Calendar.AUGUST
123     case 9 => Calendar.SEPTEMBER
124     case 10 => Calendar.OCTOBER
125     case 11 => Calendar.NOVEMBER
126     case 12 => Calendar.DECEMBER
127   }
128 }
129
130 object DSLTimeSpec {
131   val emtpyTimeSpec = DSLTimeSpec(0,0, -1, -1, -1)
132
133   def expandTimeSpec(d0:DSLTimeSpec,d1:DSLTimeSpec, from: Date,  to: Date) : List[(Date,Date)] = {
134     assert(d0!=null)
135     assert(d1!=null)
136     assert(from!=null)
137     assert(to!=null)
138     val result = new mutable.ListBuffer[(Date,Date)]()
139     val d0_nextDay = d0.nextValidDay (to.getTime) _ /* iterator for valid dates of d0*/
140     val d1_nextDay = d1.nextValidDay (to.getTime) _ /* iterator for valid dates of d1*/
141     var d0_d : Date = null
142     d0.initDay(from.getTime)
143     while({d0_d=d0_nextDay();d0_d}!=null){
144       val d1_d : Date = {d1.initDay(d0_d.getTime);d1_nextDay()}
145       if(d1_d!=null) result += ((d0_d,d1_d))
146     }
147     result.toList
148   }
149 }