Class: Chouette::TimeTable

Inherits:
TridentActiveRecord show all
Defined in:
app/models/chouette/time_table.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from TridentActiveRecord

#build_objectid, #clean_object_id, #default_values, #fix_uniq_objectid, model_name, #objectid, #objectid_format_compliance, #prefix, #prepare_auto_columns, #reset_auto_columns, #timestamp_attributes_for_create, #timestamp_attributes_for_update, #uniq_objectid

Methods inherited from ActiveRecord

#human_attribute_name, #nil_if_blank, nullable_attributes

Instance Attribute Details

#fridayObject

Returns the value of attribute friday.



13
14
15
# File 'app/models/chouette/time_table.rb', line 13

def friday
  @friday
end

#mondayObject

Returns the value of attribute monday.



13
14
15
# File 'app/models/chouette/time_table.rb', line 13

def monday
  @monday
end

#saturdayObject

Returns the value of attribute saturday.



13
14
15
# File 'app/models/chouette/time_table.rb', line 13

def saturday
  @saturday
end

#sundayObject

Returns the value of attribute sunday.



13
14
15
# File 'app/models/chouette/time_table.rb', line 13

def sunday
  @sunday
end

#tag_searchObject

Returns the value of attribute tag_search.



14
15
16
# File 'app/models/chouette/time_table.rb', line 14

def tag_search
  @tag_search
end

#thursdayObject

Returns the value of attribute thursday.



13
14
15
# File 'app/models/chouette/time_table.rb', line 13

def thursday
  @thursday
end

#tuesdayObject

Returns the value of attribute tuesday.



13
14
15
# File 'app/models/chouette/time_table.rb', line 13

def tuesday
  @tuesday
end

#wednesdayObject

Returns the value of attribute wednesday.



13
14
15
# File 'app/models/chouette/time_table.rb', line 13

def wednesday
  @wednesday
end

Class Method Details

.day_by_mask(int_day_types, flag) ⇒ Object



182
183
184
# File 'app/models/chouette/time_table.rb', line 182

def self.day_by_mask(int_day_types,flag)
  int_day_types & flag == flag
end

.end_validity_periodObject



41
42
43
# File 'app/models/chouette/time_table.rb', line 41

def self.end_validity_period
  [Chouette::TimeTable.maximum(:end_date)].compact.max
end

.object_id_keyObject



27
28
29
# File 'app/models/chouette/time_table.rb', line 27

def self.object_id_key
  "Timetable"
end

.ransackable_attributes(auth_object = nil) ⇒ Object



16
17
18
# File 'app/models/chouette/time_table.rb', line 16

def self.ransackable_attributes auth_object = nil
  (column_names + ['tag_search']) + _ransackers.keys
end

.start_validity_periodObject



38
39
40
# File 'app/models/chouette/time_table.rb', line 38

def self.start_validity_period
  [Chouette::TimeTable.minimum(:start_date)].compact.min
end

.valid_days(int_day_types) ⇒ Object



200
201
202
203
204
205
206
207
208
209
210
211
# File 'app/models/chouette/time_table.rb', line 200

def self.valid_days(int_day_types)
  # Build an array with day of calendar week (1-7, Monday is 1).
  [].tap do |valid_days|
    valid_days << 1  if day_by_mask(int_day_types,4)
    valid_days << 2  if day_by_mask(int_day_types,8)
    valid_days << 3  if day_by_mask(int_day_types,16)
    valid_days << 4  if day_by_mask(int_day_types,32)
    valid_days << 5  if day_by_mask(int_day_types,64)
    valid_days << 6  if day_by_mask(int_day_types,128)
    valid_days << 7  if day_by_mask(int_day_types,256)
  end
end

.validity_out_between?(start_date, end_date, limit = 0) ⇒ Boolean

Returns:

  • (Boolean)


86
87
88
89
90
91
92
# File 'app/models/chouette/time_table.rb', line 86

def self.validity_out_between?(start_date, end_date,limit=0)
  if limit==0
    Chouette::TimeTable.where( "? < end_date", start_date).where( "end_date <= ?", end_date)
  else
    Chouette::TimeTable.where( "? < end_date", start_date).where( "end_date <= ?", end_date).limit( limit)
  end
end

.validity_out_from_on?(expected_date, limit = 0) ⇒ Boolean

Returns:

  • (Boolean)


79
80
81
82
83
84
85
# File 'app/models/chouette/time_table.rb', line 79

def self.validity_out_from_on?(expected_date,limit=0)
  if limit==0
    Chouette::TimeTable.where("end_date <= ?", expected_date)
  else
    Chouette::TimeTable.where("end_date <= ?", expected_date).limit( limit)
  end
end

Instance Method Details

#add_included_day(d) ⇒ Object

add a peculiar day or switch it from excluded to included



340
341
342
343
344
345
346
347
348
349
350
# File 'app/models/chouette/time_table.rb', line 340

def add_included_day(d)
  if self.excluded_date?(d)
     self.dates.each do |date|
       if date.date === d
         date.in_out = true
       end
     end
  elsif !self.include_in_dates?(d)
     self.dates << Chouette::TimeTableDate.new(:date => d, :in_out => true)
  end
end

#bounding_datesObject



163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'app/models/chouette/time_table.rb', line 163

def bounding_dates
  bounding_min = self.dates.select{|d| d.in_out}.map(&:date).compact.min
  bounding_max = self.dates.select{|d| d.in_out}.map(&:date).compact.max

  unless self.periods.empty?
    bounding_min = periods_min_date if periods_min_date &&
        (bounding_min.nil? || (periods_min_date < bounding_min))

    bounding_max = periods_max_date if periods_max_date &&
        (bounding_max.nil? || (bounding_max < periods_max_date))
  end

  [bounding_min, bounding_max].compact
end

#clone_periodsObject



290
291
292
293
294
# File 'app/models/chouette/time_table.rb', line 290

def clone_periods
  periods = []
  self.periods.each { |p| periods << p.copy}
  periods
end

#day_by_mask(flag) ⇒ Object



178
179
180
# File 'app/models/chouette/time_table.rb', line 178

def day_by_mask(flag)
  int_day_types & flag == flag
end

#disjoin!(another_tt) ⇒ Object



431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
# File 'app/models/chouette/time_table.rb', line 431

def disjoin!(another_tt)
  transaction do
    # remove days from another calendar
    days_to_exclude = self.intersects(another_tt.effective_days)
    days = self.effective_days - days_to_exclude
    self.dates.clear
    self.periods.clear
    self.int_day_types = 0

    days.each {|d| self.dates << Chouette::TimeTableDate.new( :date =>d, :in_out => true)}

    self.dates.to_a.sort! { |a,b| a.date <=> b.date}
    self.periods.to_a.sort! { |a,b| a.period_start <=> b.period_start}
    self.save!
  end
end

#duplicateObject



448
449
450
451
452
453
# File 'app/models/chouette/time_table.rb', line 448

def duplicate
  tt = self.deep_clone :include => [:periods, :dates], :except => :object_version
  tt.uniq_objectid
  tt.comment = I18n.t("activerecord.copy", :name => self.comment)
  tt
end

#effective_days(valid_days = self.valid_days) ⇒ Object



276
277
278
279
280
281
282
# File 'app/models/chouette/time_table.rb', line 276

def effective_days(valid_days=self.valid_days)
  days=self.effective_days_of_periods(valid_days)
  self.dates.each do |d|
    days |= [d.date] if d.in_out
  end
  days.sort
end

#effective_days_of_period(period, valid_days = self.valid_days) ⇒ Object



266
267
268
269
270
271
272
273
274
# File 'app/models/chouette/time_table.rb', line 266

def effective_days_of_period(period,valid_days=self.valid_days)
  days = []
    period.period_start.upto(period.period_end) do |date|
      if valid_days.include?(date.cwday) && !self.excluded_date?(date)
          days << date
      end
    end
  days
end

#effective_days_of_periods(valid_days = self.valid_days) ⇒ Object



284
285
286
287
288
# File 'app/models/chouette/time_table.rb', line 284

def effective_days_of_periods(valid_days=self.valid_days)
  days = []
  self.periods.each { |p| days |= self.effective_days_of_period(p,valid_days)}
  days.sort
end

#excluded_date?(day) ⇒ Boolean

Returns:

  • (Boolean)


111
112
113
# File 'app/models/chouette/time_table.rb', line 111

def excluded_date?(day)
  self.dates.any?{ |d| d.date === day && d.in_out == false }
end

#excluded_daysObject



304
305
306
307
308
309
310
# File 'app/models/chouette/time_table.rb', line 304

def excluded_days
  days = []
  self.dates.each do |d|
    days |= [d.date] unless d.in_out
  end
  days.sort
end

#include_day?(day) ⇒ Boolean

Returns:

  • (Boolean)


103
104
105
# File 'app/models/chouette/time_table.rb', line 103

def include_day?(day)
  include_in_dates?(day) || include_in_periods?(day)
end

#include_in_dates?(day) ⇒ Boolean

Returns:

  • (Boolean)


107
108
109
# File 'app/models/chouette/time_table.rb', line 107

def include_in_dates?(day)
  self.dates.any?{ |d| d.date === day && d.in_out == true }
end

#include_in_overlap_dates?(day) ⇒ Boolean

Returns:

  • (Boolean)


122
123
124
125
126
127
# File 'app/models/chouette/time_table.rb', line 122

def include_in_overlap_dates?(day)
 return false if self.excluded_date?(day)

 counter = self.dates.select{ |d| d.date === day}.size + self.periods.select{ |period| period.period_start <= day && day <= period.period_end && valid_days.include?(day.cwday) }.size
 counter <= 1 ? false : true
end

#include_in_periods?(day) ⇒ Boolean

Returns:

  • (Boolean)


115
116
117
118
119
120
# File 'app/models/chouette/time_table.rb', line 115

def include_in_periods?(day)
  self.periods.any?{ |period| period.period_start <= day &&
                              day <= period.period_end &&
                              valid_days.include?(day.cwday) &&
                              ! excluded_date?(day) }
end

#included_daysObject



296
297
298
299
300
301
302
# File 'app/models/chouette/time_table.rb', line 296

def included_days
  days = []
  self.dates.each do |d|
    days |= [d.date] if d.in_out
  end
  days.sort
end

#intersect!(another_tt) ⇒ Object

remove dates form tt which aren’t in another_tt



416
417
418
419
420
421
422
423
424
425
426
427
428
# File 'app/models/chouette/time_table.rb', line 416

def intersect!(another_tt)
  transaction do
    
    # transform tt as effective dates and get common ones
    days = another_tt.intersects(self.effective_days) & self.intersects(another_tt.effective_days)
    self.dates.clear
    days.each {|d| self.dates << Chouette::TimeTableDate.new( :date =>d, :in_out => true)}
    self.periods.clear
    self.int_day_types = 0
    self.dates.to_a.sort! { |a,b| a.date <=> b.date}
    self.save!
  end
end

#intersects(days) ⇒ Object

Return days which intersects with the time table dates and periods



95
96
97
98
99
100
101
# File 'app/models/chouette/time_table.rb', line 95

def intersects(days)
  [].tap do |intersect_days|
    days.each do |day|
      intersect_days << day if include_day?(day)
    end
  end
end

#merge!(another_tt) ⇒ Object

merge effective days from another timetable



353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
# File 'app/models/chouette/time_table.rb', line 353

def merge!(another_tt)
  transaction do
  # if one tt has no period, just merge lists
  if self.periods.empty? || another_tt.periods.empty?
    if !another_tt.periods.empty?
      # copy periods
      self.periods = another_tt.clone_periods
      # set valid_days
      self.int_day_types = another_tt.int_day_types
    end
    # merge dates
    self.dates ||= []
    another_tt.included_days.each do |d|
      add_included_day d
    end
  else
    # check if periods can be kept
    common_day_types = self.int_day_types & another_tt.int_day_types & 508
    # if common day types : merge periods
    if common_day_types != 0
      periods = self.optimize_periods
      another_periods = another_tt.optimize_periods
      # add not common days of both periods as peculiar days
      self.effective_days_of_periods(self.class.valid_days(self.int_day_types ^ common_day_types)).each do |d|
        self.dates |= [Chouette::TimeTableDate.new(:date => d, :in_out => true)]
      end
      another_tt.effective_days_of_periods(self.class.valid_days(another_tt.int_day_types ^ common_day_types)).each do |d|
        add_included_day d
      end
      # merge periods
      self.periods = periods | another_periods
      self.int_day_types = common_day_types
      self.periods = self.optimize_periods
    else
      # convert all period in days
      self.effective_days_of_periods.each do |d|
        self.dates << Chouette::TimeTableDate.new(:date => d, :in_out => true) unless self.include_in_dates?(d)
      end
      another_tt.effective_days_of_periods.each do |d|
        add_included_day d
      end
    end
  end
  # if remained excluded dates are valid in other tt , remove it from result
  self.dates.each do |date|
    date.in_out = true if date.in_out == false && another_tt.include_day?(date.date)
  end

  # if peculiar dates are valid in new periods, remove them
  if !self.periods.empty?
    days_in_period = self.effective_days_of_periods
    dates = []
    self.dates.each do |date|
      dates << date unless date.in_out && days_in_period.include?(date.date)
    end
    self.dates = dates
  end
  self.dates.to_a.sort! { |a,b| a.date <=> b.date}
  self.save!
  end
end

#optimize_periodsObject

produce a copy of periods without anyone overlapping or including another



314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
# File 'app/models/chouette/time_table.rb', line 314

def optimize_periods
  periods = self.clone_periods
  optimized = []
  i=0
  while i < periods.length
    p1 = periods[i]
    optimized << p1
    j= i+1
    while j < periods.length
      p2 = periods[j]
      if p1.contains? p2
        periods.delete p2
      elsif p1.overlap? p2
        p1.period_start = [p1.period_start,p2.period_start].min
        p1.period_end = [p1.period_end,p2.period_end].max
        periods.delete p2
      else
        j += 1
      end
    end
    i+= 1
  end
  optimized.sort { |a,b| a.period_start <=> b.period_start}
end

#periods_max_dateObject



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'app/models/chouette/time_table.rb', line 129

def periods_max_date
  return nil if self.periods.empty?

  min_start = self.periods.map(&:period_start).compact.min
  max_end = self.periods.map(&:period_end).compact.max
  result = nil

  if max_end && min_start
    max_end.downto( min_start) do |date|
      if self.valid_days.include?(date.cwday) && !self.excluded_date?(date)
          result = date
          break
      end
    end
  end
  result
end

#periods_min_dateObject



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# File 'app/models/chouette/time_table.rb', line 146

def periods_min_date
  return nil if self.periods.empty?

  min_start = self.periods.map(&:period_start).compact.min
  max_end = self.periods.map(&:period_end).compact.max
  result = nil

  if max_end && min_start
    min_start.upto(max_end) do |date|
      if self.valid_days.include?(date.cwday) && !self.excluded_date?(date)
          result = date
          break
      end
    end
  end
  result
end

#save_shortcutsObject



45
46
47
48
49
# File 'app/models/chouette/time_table.rb', line 45

def save_shortcuts
    shortcuts_update
    self.update_column(:start_date, start_date)
    self.update_column(:end_date, end_date)
end

#set_day(day, flag) ⇒ Object



235
236
237
238
239
240
241
242
# File 'app/models/chouette/time_table.rb', line 235

def set_day(day,flag)
  if day == '1' || day == true
    self.int_day_types |= flag
  else
    self.int_day_types &= ~flag
  end
  shortcuts_update
end

#shortcuts_update(date = nil) ⇒ Object



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'app/models/chouette/time_table.rb', line 51

def shortcuts_update(date=nil)
  dates_array = bounding_dates
  #if new_record?
    if dates_array.empty?
      self.start_date=nil
      self.end_date=nil
    else
      self.start_date=dates_array.min
      self.end_date=dates_array.max
    end
  #else
   # if dates_array.empty?
   #   update_attributes :start_date => nil, :end_date => nil
   # else
   #   update_attributes :start_date => dates_array.min, :end_date => dates_array.max
   # end
  #end
end

#valid_daysObject



187
188
189
190
191
192
193
194
195
196
197
198
# File 'app/models/chouette/time_table.rb', line 187

def valid_days
  # Build an array with day of calendar week (1-7, Monday is 1).
  [].tap do |valid_days|
    valid_days << 1  if monday
    valid_days << 2  if tuesday
    valid_days << 3  if wednesday
    valid_days << 4  if thursday
    valid_days << 5  if friday
    valid_days << 6  if saturday
    valid_days << 7  if sunday
  end
end

#validity_out_between?(starting_date, ending_date) ⇒ Boolean

Returns:

  • (Boolean)


74
75
76
77
78
# File 'app/models/chouette/time_table.rb', line 74

def validity_out_between?(starting_date, ending_date)
  return false unless self.start_date
  starting_date < self.end_date  &&
    self.end_date <= ending_date
end

#validity_out_from_on?(expected_date) ⇒ Boolean

Returns:

  • (Boolean)


70
71
72
73
# File 'app/models/chouette/time_table.rb', line 70

def validity_out_from_on?(expected_date)
  return false unless self.end_date
  self.end_date <= expected_date
end