aboutsummaryrefslogtreecommitdiffstats
path: root/app/models/chouette/journey_pattern.rb
blob: 1104c603594369571b67e7b88f3923be1eeb68dd (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
class Chouette::JourneyPattern < Chouette::TridentActiveRecord
  include ChecksumSupport
  include JourneyPatternRestrictions
  # FIXME http://jira.codehaus.org/browse/JRUBY-6358
  self.primary_key = "id"

  belongs_to :route
  has_many :vehicle_journeys, :dependent => :destroy
  has_many :vehicle_journey_at_stops, :through => :vehicle_journeys
  has_and_belongs_to_many :stop_points, -> { order("stop_points.position") }, :before_add => :vjas_add, :before_remove => :vjas_remove, :after_add => :shortcuts_update_for_add, :after_remove => :shortcuts_update_for_remove
  has_many :stop_areas, through: :stop_points

  validates_presence_of :route
  validates_presence_of :name

  #validates :stop_points, length: { minimum: 2, too_short: :minimum }, on: :update
  enum section_status: { todo: 0, completed: 1, control: 2 }

  attr_accessor  :control_checked
  def local_id
    "IBOO-#{self.referential.id}-#{self.try(:route).try(:line).try(:objectid).try(:local_id)}-#{self.id}"
  end

  def checksum_attributes
    values = self.slice(*['name', 'published_name', 'registration_number']).values
    values << self.stop_points.map(&:stop_area).map(&:user_objectid)
    values.flatten
  end

  def self.state_update route, state
    transaction do
      state.each do |item|
        item.delete('errors')
        jp = find_by(objectid: item['object_id']) || state_create_instance(route, item)
        next if item['deletable'] && jp.persisted? && jp.destroy
        # Update attributes and stop_points associations
        jp.update_attributes(state_permited_attributes(item)) unless item['new_record']
        jp.state_stop_points_update(item) if !jp.errors.any? && jp.persisted?
        item['errors'] = jp.errors if jp.errors.any?
      end

      if state.any? {|item| item['errors']}
        state.map {|item| item.delete('object_id') if item['new_record']}
        raise ActiveRecord::Rollback
      end
    end

    state.map {|item| item.delete('new_record')}
    state.delete_if {|item| item['deletable']}
  end

  def self.state_permited_attributes item
    {
      name: item['name'],
      published_name: item['published_name'],
      registration_number: item['registration_number']
    }
  end

  def self.state_create_instance route, item
    # Flag new record, so we can unset object_id if transaction rollback
    jp = route.journey_patterns.create(state_permited_attributes(item))

    # FIXME
    # DefaultAttributesSupport will trigger some weird validation on after save
    # wich will call to valid?, wich will populate errors
    # In this case, we mark jp to be valid if persisted? return true
    jp.errors.clear if jp.persisted?

    item['object_id']  = jp.objectid
    item['new_record'] = true
    jp
  end

  def state_stop_points_update item
    item['stop_points'].each do |sp|
      exist = stop_area_ids.include?(sp['id'])
      next if exist && sp['checked']

      stop_point = route.stop_points.find_by(stop_area_id: sp['id'])
      if !exist && sp['checked']
        stop_points << stop_point
      end
      if exist && !sp['checked']
        stop_points.delete(stop_point)
      end
    end
  end

  # TODO: this a workarround
  # otherwise, we loose the first stop_point
  # when creating a new journey_pattern
  def special_update
    bck_sp = self.stop_points.map {|s| s}
    self.update_attributes :stop_points => []
    self.update_attributes :stop_points => bck_sp
  end

  def departure_stop_point
    return unless departure_stop_point_id
    Chouette::StopPoint.find( departure_stop_point_id)
  end

  def arrival_stop_point
    return unless arrival_stop_point_id
    Chouette::StopPoint.find( arrival_stop_point_id)
  end

  def shortcuts_update_for_add( stop_point)
    stop_points << stop_point unless stop_points.include?( stop_point)

    ordered_stop_points = stop_points
    ordered_stop_points = ordered_stop_points.sort { |a,b| a.position <=> b.position} unless ordered_stop_points.empty?

    self.update_attributes( :departure_stop_point_id => (ordered_stop_points.first && ordered_stop_points.first.id),
                             :arrival_stop_point_id => (ordered_stop_points.last && ordered_stop_points.last.id))
  end

  def shortcuts_update_for_remove( stop_point)
    stop_points.delete( stop_point) if stop_points.include?( stop_point)

    ordered_stop_points = stop_points
    ordered_stop_points = ordered_stop_points.sort { |a,b| a.position <=> b.position} unless ordered_stop_points.empty?

    self.update_attributes( :departure_stop_point_id => (ordered_stop_points.first && ordered_stop_points.first.id),
                             :arrival_stop_point_id => (ordered_stop_points.last && ordered_stop_points.last.id))
  end

  def vjas_add( stop_point)
    return if new_record?

    vehicle_journeys.each do |vj|
      vjas = vj.vehicle_journey_at_stops.create :stop_point_id => stop_point.id
    end
  end

  def vjas_remove( stop_point)
    return if new_record?

    vehicle_journey_at_stops.where( :stop_point_id => stop_point.id).each do |vjas|
      vjas.destroy
    end
  end
end