2 * Copyright 2011-2012 GRNET S.A. All rights reserved.
4 * Redistribution and use in source and binary forms, with or
5 * without modification, are permitted provided that the following
8 * 1. Redistributions of source code must retain the above
9 * copyright notice, this list of conditions and the following
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.
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.
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.
36 package gr.grnet.aquarium.logic.accounting.dsl
38 import gr.grnet.aquarium.util.DateUtils
39 import java.util.{Date, GregorianCalendar, Calendar}
40 import scala.collection.immutable
44 * Utility functions to use when working with DSL types.
46 * @author Georgios Gousios <gousiosg@gmail.com>
49 trait DSLUtils extends DateUtils {
51 val maxdate = new Date(Int.MaxValue * 1000L)
54 * Resolves the effective algorithm for each chunk of the
55 * provided timeslot and returns it as a Map
57 def resolveEffectiveAlgorithmsForTimeslot(timeslot: Timeslot,
59 immutable.SortedMap[Timeslot, DSLAlgorithm] =
60 resolveEffective[DSLAlgorithm](timeslot, agr.algorithm)
63 * Resolves the effective price list for each chunk of the
64 * provided timeslot and returns it as a Map
66 def resolveEffectivePricelistsForTimeslot(timeslot: Timeslot,
68 immutable.SortedMap[Timeslot, DSLPriceList] =
69 resolveEffective[DSLPriceList](timeslot,agr.pricelist)
71 /*private def printPolicy[T <: DSLTimeBoundedItem[T]](t : T) : Unit = {
72 Console.err.println("Policy " + t.name + " " + t.toTimeslot + " DETAIL : " + t.effective)
74 case None => Console.println
75 case Some(t) => printPolicy(t)
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")
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
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]())
103 //Console.err.println("Adding timeslot" + t + " for policy " + policy.name)
106 val other_policy_map = policy.overrides match {
108 immutable.SortedMap[Timeslot, T]()
109 case Some(parent_policy)=>
110 subtimeslots_NOT_IN_this_policy.foldLeft (
111 (immutable.SortedMap[Timeslot, T]()))
113 //Console.err.println("Residual timeslot: " + t)
114 map ++ resolveEffective3(t,parent_policy)
117 val final_map = policy_map ++ other_policy_map
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")
125 /* generate mappings from timeslots -> policies
126 * Algorithm: find next valid date (starting from timeslot.start) in this policy
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)
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))
138 def genMap(map: immutable.SortedMap[Timeslot, T],d:Date) : immutable.SortedMap[Timeslot, T] = {
140 nextDate(d,policy) match {
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
149 val map = genMap(immutable.SortedMap[Timeslot, T](),timeslot.from)
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).
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")
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
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)
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)
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*/
189 * Get a list of all timeslots within which a timeframe
190 * is effective, whithin the provided time bounds.
192 def allEffectiveTimeslots(spec: DSLTimeFrame, t: 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*/
200 val all = for { r <- spec.repeat
201 ts <- effectiveTimeslots(r, t.from, t.to)
203 //for{ i <- all} Console.err.println(i)
211 * Merges overlapping timeslots.
215 * Get a list of all timeslots within which a time frame is active.
216 The result is returned sorted by timeframe start date.
218 def effectiveTimeslots(spec: DSLTimeFrameRepeat, from: Date, to : Date):
220 for { (h1,h2) <- spec.start zip spec.end
221 (d1,d2) <- DSLTimeSpec.expandTimeSpec(h1,h2,from,to)
223 yield Timeslot(d1,d2)