c2ce1095239bf77d32a54bbb45273ff1a713c834
[aquarium] / src / main / scala / gr / grnet / aquarium / logic / accounting / dsl / DSLUtils.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 gr.grnet.aquarium.util.DateUtils
39 import java.util.{Date, GregorianCalendar, Calendar}
40 import scala.collection.immutable
41 import java.util
42
43 /**
44  * Utility functions to use when working with DSL types.
45  *
46  * @author Georgios Gousios <gousiosg@gmail.com>
47  */
48
49 trait DSLUtils extends DateUtils {
50
51   val maxdate = new Date(Int.MaxValue * 1000L)
52
53   /**
54    * Resolves the effective algorithm for each chunk of the
55    * provided timeslot and returns it as a Map
56    */
57   def resolveEffectiveAlgorithmsForTimeslot(timeslot: Timeslot,
58                                            agr: DSLAgreement):
59   immutable.SortedMap[Timeslot, DSLAlgorithm] =
60     resolveEffective[DSLAlgorithm](timeslot, agr.algorithm)
61
62   /**
63    * Resolves the effective price list for each chunk of the
64    * provided timeslot and returns it as a Map
65    */
66   def resolveEffectivePricelistsForTimeslot(timeslot: Timeslot,
67                                             agr: DSLAgreement):
68   immutable.SortedMap[Timeslot, DSLPriceList] =
69     resolveEffective[DSLPriceList](timeslot,agr.pricelist)
70
71   /*private def printPolicy[T <: DSLTimeBoundedItem[T]](t : T) : Unit = {
72     Console.err.println("Policy " + t.name + " " + t.toTimeslot + " DETAIL : " + t.effective)
73     t.overrides match {
74       case None => Console.println
75       case Some(t) => printPolicy(t)
76     }
77   }
78
79   private def printMap[T <: DSLTimeBoundedItem[T]](m: immutable.SortedMap[Timeslot, T]) = {
80     Console.err.println("BEGIN MAP: ")
81     for { (t,p) <- m.toList } Console.err.println("Timeslot " + t + "\t\t" + p.name)
82     Console.err.println("END MAP")
83   } */
84
85   def resolveEffective[T <: DSLTimeBoundedItem[T]](timeslot0: Timeslot,policy: T):
86   immutable.SortedMap[Timeslot, T] = {
87     //Console.err.println("\n\nInput timeslot: " + timeslot0 + "\n\n")
88     ///printPolicy(policy)
89     val ret =  resolveEffective3(timeslot0,policy) //HERE
90     //printMap(ret)
91     ret
92   }
93
94   def resolveEffective3[T <: DSLTimeBoundedItem[T]](timeslot0: Timeslot,policy: T):
95   immutable.SortedMap[Timeslot, T] = {
96     assert(policy.toTimeslot contains timeslot0,"Policy does not contain timeslot")
97     val timeslot = timeslot0 //TODO: timeslot0.align(5000)
98     val subtimeslots_of_this_policy = Timeslot.mergeOverlaps(policy.effective intervalsOf timeslot)
99     val subtimeslots_NOT_IN_this_policy = Timeslot.mergeOverlaps(timeslot.nonOverlappingTimeslots
100                                                                                           (subtimeslots_of_this_policy))
101     val policy_map =  subtimeslots_of_this_policy.foldLeft  (immutable.SortedMap[Timeslot, T]())
102                                                             {(map,t) =>
103                                                                   //Console.err.println("Adding timeslot" + t + " for policy " + policy.name)
104                                                                   map + ((t,policy))
105                                                             }
106     val other_policy_map = policy.overrides match {
107                                               case None =>
108                                                  immutable.SortedMap[Timeslot, T]()
109                                               case Some(parent_policy)=>
110                                                   subtimeslots_NOT_IN_this_policy.foldLeft (
111                                                       (immutable.SortedMap[Timeslot, T]()))
112                                                       {(map,t) =>
113                                                         //Console.err.println("Residual timeslot: " + t)
114                                                         map ++ resolveEffective3(t,parent_policy)
115                                                       }
116                                             }
117     val final_map = policy_map ++ other_policy_map
118     final_map
119   }
120
121   /*def resolveEffective2[T <: DSLTimeBoundedItem[T]](timeslot0: Timeslot,policy: T):
122   immutable.SortedMap[Timeslot, T] = {
123     assert(policy.toTimeslot contains timeslot0,"Policy does not contain timeslot")
124
125     /* generate mappings from timeslots -> policies
126      * Algorithm: find next valid date (starting from timeslot.start) in this policy
127      */
128     val timeslot = timeslot0 //TODO: timeslot0.align(5000)
129     def nextDate(d:Date,p:T) : Option[(Date,T,Boolean)] =
130       (p.effective nextValidAfter d,p.overrides) match {
131         case (None,None) => None
132         case (None,Some(parent_policy)) =>
133           val d1 = nextDate(d,parent_policy)
134           d1
135         case (Some(d1),_) => /* the next valid date cannot occur after the end of timeslot*/
136            if (d1.before(timeslot.to)) Some((d1,p,true)) else Some((timeslot.to,p,false))
137       }
138     def genMap(map: immutable.SortedMap[Timeslot, T],d:Date) : immutable.SortedMap[Timeslot, T] = {
139         val step = 1000L
140         nextDate(d,policy) match {
141         case None => map
142         case Some((d1,policy,cont)) =>
143           val t = Timeslot(d,d1)
144           val map1 = map + (t -> policy)
145           if(cont) genMap(map1,new Date(d1.getTime + step)) // 1 second after d1
146           else map1 /* done */
147       }
148     }
149     val map = genMap(immutable.SortedMap[Timeslot, T](),timeslot.from)
150     map
151   }
152
153   /**
154    * Splits the provided timeslot into chunks according to the validity
155    * timeslots specified by the provided time bounded item. It
156    * returns a map whose keys are the timeslot chunks and the values
157    * correspond to the effective time bounded item (algorithm or pricelist).
158    */
159   def resolveEffective1[T <: DSLTimeBoundedItem[T]](timeslot: Timeslot,policy: T):
160   immutable.SortedMap[Timeslot, T] = {
161       assert(policy.toTimeslot contains timeslot,"Policy does not contain timeslot")
162
163      /* Get a list of all effective/expanded policy timeslots within
164         a timeslot specified by "variable timeslot".
165       * NOTICE: The returned timeslots may be slightly out of "timeslot" bounds
166       *         so we need to invoke overlappingTimeslots and nonOverlapping timeslots
167       */
168      val all_timeslots = allEffectiveTimeslots(policy.effective,timeslot)
169      val timeslots_IN_policy = timeslot.overlappingTimeslots(all_timeslots)
170      val timeslots_NOT_IN_policy = timeslot.nonOverlappingTimeslots(all_timeslots)
171
172      val ret =  immutable.SortedMap[Timeslot, T]() ++
173       /*add [timeslots -> policy] covered by this policy*/
174       timeslots_IN_policy.flatMap {
175          effective_timeslot =>  Map(effective_timeslot -> policy)
176       } ++
177       /*add [timeslots -> policy] covered by parent policies */
178       timeslots_NOT_IN_policy.flatMap { /* search the policy hierarchy for effective timeslots not covered by this policy.*/
179         not_effective_timeslot => policy.overrides match {
180           case None => immutable.SortedMap[Timeslot, T]() /*Nothing to do. TODO: throw exception ?*/
181           case Some(parent_policy) => resolveEffective1(not_effective_timeslot,parent_policy) /* search the policy hierarchy*/
182         }
183       }
184     ret
185   }*/
186
187    /*
188   /*
189    * Get a list of all timeslots within which a timeframe
190    * is effective, whithin the provided time bounds.
191    */
192   def allEffectiveTimeslots(spec: DSLTimeFrame, t: Timeslot):
193   List[Timeslot] =
194     if (spec.repeat.isEmpty) { //A  simple timeframe with no repetition defined
195       val fromDate = if (spec.from.before(t.from)) t.from else spec.from
196       val toDate = if (spec.to.getOrElse(t.to).after(t.to)) t.to else spec.to.getOrElse(t.to)
197       List(Timeslot(fromDate, toDate))
198     } /* otherwise for all repetitions determine timeslots*/
199     else {
200         val all =  for { r <- spec.repeat
201                          ts <- effectiveTimeslots(r, t.from, t.to)
202                       }  yield ts
203       //for{ i <- all} Console.err.println(i)
204         mergeOverlaps(all)
205     }
206   */
207
208
209
210   /**
211    * Merges overlapping timeslots.
212    */
213
214   /*/**
215    * Get a list of all timeslots within which a time frame is active.
216      The result is returned sorted by timeframe start date.
217    */
218   def effectiveTimeslots(spec: DSLTimeFrameRepeat, from: Date, to : Date):
219     List[Timeslot] =
220       for { (h1,h2) <- spec.start zip spec.end
221             (d1,d2) <- DSLTimeSpec.expandTimeSpec(h1,h2,from,to)
222           }
223       yield Timeslot(d1,d2)
224       */
225 }