1# Copyright 2014 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5class Bounds(object):
6  """Represents a min-max bounds."""
7  def __init__(self):
8    self.is_empty_ = True
9    self.min_ = None
10    self.max_ = None
11
12  @staticmethod
13  def CreateFromEvent(event):
14    bounds = Bounds()
15    bounds.AddEvent(event)
16    return bounds
17
18  def __repr__(self):
19    if self.is_empty_:
20      return "Bounds()"
21    else:
22      return "Bounds(min=%s,max=%s)" % (self.min_, self.max_)
23
24  @property
25  def is_empty(self):
26    return self.is_empty_
27
28  @property
29  def min(self):
30    if self.is_empty_:
31      return None
32    return self.min_
33
34  @property
35  def max(self):
36    if self.is_empty_:
37      return None
38    return self.max_
39
40  @property
41  def bounds(self):
42    if self.is_empty_:
43      return None
44    return self.max_ - self.min_
45
46  @property
47  def center(self):
48    return (self.min_ + self.max_) * 0.5
49
50  def Contains(self, other):
51    if self.is_empty or other.is_empty:
52      return False
53    return self.min <= other.min and self.max >= other.max
54
55  def ContainsInterval(self, start, end):
56    return self.min <= start and self.max >= end
57
58  def Intersects(self, other):
59    if self.is_empty or other.is_empty:
60      return False
61    return not (other.max < self.min or other.min > self.max)
62
63  def Reset(self):
64    self.is_empty_ = True
65    self.min_ = None
66    self.max_ = None
67
68  def AddBounds(self, bounds):
69    if bounds.is_empty:
70      return
71    self.AddValue(bounds.min_)
72    self.AddValue(bounds.max_)
73
74  def AddValue(self, value):
75    if self.is_empty_:
76      self.max_ = value
77      self.min_ = value
78      self.is_empty_ = False
79      return
80
81    self.max_ = max(self.max_, value)
82    self.min_ = min(self.min_, value)
83
84  def AddEvent(self, event):
85    self.AddValue(event.start)
86    self.AddValue(event.start + event.duration)
87
88  @staticmethod
89  def CompareByMinTimes(a, b):
90    if not a.is_empty and not b.is_empty:
91      return a.min_ - b.min_
92
93    if a.is_empty and not b.is_empty:
94      return -1
95
96    if not a.is_empty and b.is_empty:
97      return 1
98
99    return 0
100
101  @staticmethod
102  def GetOverlapBetweenBounds(first_bounds, second_bounds):
103    """Compute the overlap duration between first_bounds and second_bounds."""
104    return Bounds.GetOverlap(first_bounds.min_, first_bounds.max_,
105                             second_bounds.min_, second_bounds.max_)
106
107  @staticmethod
108  def GetOverlap(first_bounds_min, first_bounds_max,
109                 second_bounds_min, second_bounds_max):
110    assert first_bounds_min <= first_bounds_max
111    assert second_bounds_min <= second_bounds_max
112    overlapped_range_start = max(first_bounds_min, second_bounds_min)
113    overlapped_range_end = min(first_bounds_max, second_bounds_max)
114    return max(overlapped_range_end - overlapped_range_start, 0)
115