aboutsummaryrefslogtreecommitdiffstats
path: root/app/models/concerns/timetable_support.rb
blob: 5242abc335852547e14f70ed801f67f030311426 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
module TimetableSupport
  extend ActiveSupport::Concern

  def presenter
    @presenter ||= ::TimeTablePresenter.new( self)
  end

  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

  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

  def bounding_dates
    bounding_min = self.all_dates.select{|d| d.in_out}.map(&:date).compact.min
    bounding_max = self.all_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

  def month_inspect(date)
    (date.beginning_of_month..date.end_of_month).map do |d|
      {
        day: I18n.l(d, format: '%A'),
        date: d.to_s,
        wday: d.wday,
        wnumber: d.strftime("%W").to_s,
        mday: d.mday,
        include_date: include_in_dates?(d),
        excluded_date: excluded_date?(d)
      }
    end
  end

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

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

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

    self.all_dates.any?{ |d| d.date === day} \
    && self.periods.any?{ |period| period.period_start <= day && day <= period.period_end && valid_days.include?(day.cwday) }
  end

  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

  def state_update_periods state_periods
    state_periods.each do |item|
      period = self.find_period_by_id(item['id']) if item['id']
      next if period && item['deleted'] && self.destroy_period(period)
      period ||= self.build_period

      period.period_start = Date.parse(item['period_start'])
      period.period_end   = Date.parse(item['period_end'])

      period.save if period.is_a?(ActiveRecord::Base) && period.changed?

      item['id'] = period.id
    end

    state_periods.delete_if {|item| item['deleted']}
  end

  def state_update state
    update_attributes(self.class.state_permited_attributes(state))
    self.tag_list    = state['tags'].collect{|t| t['name']}.join(', ') if state['tags']
    self.calendar_id = nil if self.respond_to?(:calendar_id) && !state['calendar']

    days = state['day_types'].split(',')
    Date::DAYNAMES.map(&:underscore).each do |name|
      prefix = human_attribute_name(name).first(2)
      send("#{name}=", days.include?(prefix))
    end

    cmonth = Date.parse(state['current_periode_range'])

    state['current_month'].each do |d|
      date    = Date.parse(d['date'])
      checked = d['include_date'] || d['excluded_date']
      in_out  = d['include_date'] ? true : false

      date_id = saved_dates.key(date)
      time_table_date = self.find_date_by_id(date_id) if date_id

      next if !checked && !time_table_date
      # Destroy date if no longer checked
      next if !checked && destroy_date(time_table_date)

      # Create new date
      unless time_table_date
        time_table_date = self.create_date in_out: in_out, date: date
      end
      # Update in_out
      self.update_in_out time_table_date, in_out
    end

    self.state_update_periods state['time_table_periods']
    self.save
  end

end