Statistics
| Branch: | Tag: | Revision:

root / src / main / scala / gr / grnet / aquarium / logic / accounting / dsl / Timeslot.scala @ 11b49c26

History | View | Annotate | Download (5.8 kB)

1
/*
2
 * Copyright 2011 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.Date
39
import scala.collection.mutable
40

    
41
/**
42
 * A representation of a timeslot with a start and end date.
43
 *
44
 * @author Georgios Gousios <gousiosg@gmail.com>
45
 */
46
case class Timeslot(from: Date, to: Date) extends Ordered[Timeslot] {
47

    
48
  /* Preconditions to ensure correct object creations */
49
  assert(from != null)
50
  assert(to != null)
51
  assert(from.before(to))
52

    
53
  def startsBefore(t: Timeslot) : Boolean = this.from.before(t.from)
54

    
55
  def startsAfter(t: Timeslot) : Boolean = this.from.after(t.from)
56

    
57
  def endsBefore(t: Timeslot) : Boolean = this.to.before(t.to)
58

    
59
  def endsAfter(t: Timeslot) : Boolean = this.to.after(t.to)
60

    
61
  /**
62
   * Check whether this time slot fully contains the provided one.
63
   */
64
  def contains(t: Timeslot) : Boolean = t.startsAfter(this) && t.endsBefore(this)
65

    
66
  /**
67
   * Check whether this timeslot contains the provided time instant.
68
   */
69
  def includes(t: Date) : Boolean =
70
    if (from.before(t) && to.after(t)) true else false
71

    
72
  /**
73
   * Check whether this timeslot overlaps with the provided one.
74
   */
75
  def overlaps(t: Timeslot) : Boolean = {
76
    if (contains(t) || t.contains(this))
77
      return true
78

    
79
    if (this.includes(t.from) || this.includes(t.to))
80
      return true
81

    
82
    false
83
  }
84

    
85
  /**
86
   * Merges this timeslot with the provided one. If the timeslots overlap,
87
   * a list with the resulting merge is returned. If the timeslots do not
88
   * overlap, the returned list contains both timeslots in increasing start
89
   * date order.
90
   */
91
  def merge(t: Timeslot) : List[Timeslot] = {
92
    if (overlaps(t)) {
93
      val nfrom = if (from.before(t.from)) from else t.from
94
      val nto   = if (to.after(t.to)) to else t.to
95
      List(Timeslot(nfrom, nto))
96
    } else
97
      if (this.from.before(t.from))
98
        List(this, t)
99
      else
100
        List(t, this)
101
  }
102

    
103
  /**
104
   * Split the timeslot in two parts at the provided timestamp, if the
105
   * timestamp falls within the timeslot boundaries.
106
   */
107
  def slice(d: Date) : List[Timeslot] =
108
    if (includes(d))
109
      List(Timeslot(from, d), Timeslot(d,to))
110
    else
111
      List(this)
112

    
113
  /**
114
   * Find and return the timeslots whithin which this Timeslot overrides
115
   * with the provided list of timeslots. For example if:
116
   * 
117
   *  - `this == Timeslot(7,20)`
118
   *  - `list == List(Timeslot(1,3), Timeslot(6,8), Timeslot(11,15))`
119
   *
120
   * the result will be: `List(Timeslot(7,8), Timeslot(11,15))`
121
   */
122
  def overlappingTimeslots(list: List[Timeslot]) : List[Timeslot] = {
123

    
124
    val result = new mutable.ListBuffer[Timeslot]()
125

    
126
    list.foreach {
127
      t =>
128
        if (t.contains(this)) result += this
129
        else if (this.contains(t)) result += t
130
        else if (t.overlaps(this) && t.startsBefore(this)) result += this.slice(t.to).head
131
        else if (t.overlaps(this) && t.startsAfter(this)) result += this.slice(t.from).tail.head
132
    }
133
    result.toList
134
  }
135

    
136
  /**
137
   * Find and return the timeslots whithin which this Timeslot does not
138
   * override with the provided list of timeslots. For example if:
139
   *
140
   *  - `this == Timeslot(7,20)`
141
   *  - `list == List(Timeslot(1,3), Timeslot(6,8), Timeslot(11,15))`
142
   *
143
   * the result will be: `List(Timeslot(9,10), Timeslot(15,20))`
144
   */
145
  def nonOverlappingTimeslots(list: List[Timeslot]): List[Timeslot] = {
146

    
147
    val overlaps = list.filter(t => this.overlaps(t))
148

    
149
    if (overlaps.isEmpty)
150
      return List(this)
151

    
152
    def build(acc: List[Timeslot], listPart: List[Timeslot]): List[Timeslot] = {
153

    
154
      listPart match {
155
        case Nil => acc
156
        case x :: Nil => build(acc, List())
157
        case x :: y :: rest =>
158
          build(acc ++ List(Timeslot(x.to,  y.from)), y :: rest)
159
      }
160
    }
161

    
162
    val head = overlaps.head
163
    val last = overlaps.reverse.head
164

    
165
    val start = if (head.startsAfter(this)) List(Timeslot(this.from, head.from)) else List()
166
    val end = if (last.endsBefore(this)) List(Timeslot(last.to, this.to)) else List()
167

    
168
    start ++ build(List(), overlaps) ++ end
169
  }
170

    
171
  /**
172
   * Compares the starting times of two timeslots.
173
   */
174
  def compare(that: Timeslot): Int = {
175
    if (this.startsBefore(that)) -1
176
    else if (this.startsAfter(that)) 1
177
    else 0
178
  }
179

    
180
  /**
181
   * Converts the timeslot to the amount of hours it represents
182
   */
183
  def hours: Float = ((to.getTime - from.getTime)/1000)/60F/60F
184
}