aboutsummaryrefslogtreecommitdiffstats
path: root/lib/stif/codif_line_synchronization.rb
blob: 600415424ed0ddb71a072c0e8482d512f6379433 (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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
module Stif
  module CodifLineSynchronization
    class << self
      attr_accessor :imported_count, :updated_count, :deleted_count

      def reset_counts
        self.imported_count = 0
        self.updated_count  = 0
        self.deleted_count  = 0
      end

      def processed_counts
        {
          imported: self.imported_count,
          updated: self.updated_count,
          deleted: self.deleted_count
        }
      end

      def increment_counts prop_name, value
        self.send("#{prop_name}=", self.send(prop_name) + value)
      end

      def synchronize
        self.reset_counts
        start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC, :second)
        # Fetch Codifline data
        client = Codifligne::API.new
        operators       = client.operators
        lines           = client.lines
        networks        = client.networks
        # groups_of_lines = client.groups_of_lines

        Rails.logger.info "Codifligne:sync - Codifligne request processed in #{elapsed_time_since start_time} seconds"

        # Create or update Companies
        stime = Process.clock_gettime(Process::CLOCK_MONOTONIC, :second)
        operators.map       { |o| create_or_update_company(o) }
        log_create_or_update "Companies", operators.count, stime

        # Create or update Lines
        stime = Process.clock_gettime(Process::CLOCK_MONOTONIC, :second)
        lines.map           { |l| create_or_update_line(l) }
        log_create_or_update "Lines", lines.count, stime

        # Create or update Networks
        stime = Process.clock_gettime(Process::CLOCK_MONOTONIC, :second)
        networks.map        { |n| create_or_update_network(n) }
        log_create_or_update "Networks", networks.count, stime

        # # Create or update Group of lines
        # stime = Process.clock_gettime(Process::CLOCK_MONOTONIC, :second)
        # groups_of_lines.map { |g| create_or_update_group_of_lines(g) }
        # log_create_or_update "Group of lines", groups_of_lines.count, stime

        # # Delete deprecated Group of lines
        # deleted_gr = delete_deprecated(groups_of_lines, Chouette::GroupOfLine)
        # log_deleted "Group of lines", deleted_gr unless deleted_gr == 0

        # Delete deprecated Networks
        deleted_ne = delete_deprecated(networks, Chouette::Network)
        log_deleted "Networks", deleted_ne unless deleted_ne == 0

        # Delete deprecated Lines
        deleted_li = delete_deprecated_lines(lines)
        log_deleted "Lines", deleted_li unless deleted_li == 0

        # Delete deprecated Operators
        deleted_op = delete_deprecated(operators, Chouette::Company)
        log_deleted "Operators", deleted_op unless deleted_op == 0

        self.processed_counts
      end

      def create_or_update_company(api_operator)
        params = {
          name: api_operator.name,
          objectid: api_operator.stif_id,
          import_xml: api_operator.xml
        }
        save_or_update(params, Chouette::Company)
      end

      def create_or_update_line(api_line)
        params = {
          name: api_line.name,
          objectid: api_line.stif_id,
          number: api_line.short_name,
          deactivated: (api_line.status == "inactive" ? true : false),
          import_xml: api_line.xml
        }

        params[:transport_submode] = api_line.transport_submode.to_s
        unless api_line.operator_ref.nil?
          params[:company] = Chouette::Company.find_by(objectid: api_line.operator_ref)
        end
        save_or_update(params, Chouette::Line)
      end

      def create_or_update_network(api_network)
        params = {
          name: api_network.name,
          objectid: api_network.stif_id,
          import_xml: api_network.xml
        }

        # Find Lines
        params[:lines] = []
        api_network.line_codes.each do |line|
          line_id = "STIF:CODIFLIGNE:Line:" + line
          chouette_line = Chouette::Line.find_by(objectid: line_id)
          params[:lines] << chouette_line if chouette_line.present?
        end

        save_or_update(params, Chouette::Network)
      end

      def create_or_update_group_of_lines(api_group_of_lines)
        params = {
          name: api_group_of_lines.name,
          objectid: api_group_of_lines.stif_id,
          import_xml: api_group_of_lines.xml
        }

        # Find Lines
        params[:lines] = []
        api_group_of_lines.line_codes.each do |line|
          line_id = "STIF:CODIFLIGNE:Line:" + line
          # TODO : handle when lines doesn't exist
          chouette_line = Chouette::Line.find_by(objectid: line_id)
          params[:lines] << chouette_line if chouette_line.present?
        end

        save_or_update(params, Chouette::GroupOfLine)
      end

      def delete_deprecated(objects, klass)
        ids = objects.map{ |o| o.stif_id }.to_a
        deprecated = klass.where.not(objectid: ids)
        increment_counts :deleted_count, deprecated.destroy_all.length
      end

      def delete_deprecated_lines(lines)
        ids = lines.map{ |l| l.stif_id }.to_a
        deprecated = Chouette::Line.where.not(objectid: ids).where(deactivated: false)
        deprecated.update_all deactivated: true
        increment_counts :deleted_count, deprecated.update_all(deactivated: true)
      end

      def save_or_update(params, klass)
        params[:line_referential] = LineReferential.first
        object = klass.where(objectid: params[:objectid]).first
        if object
          object.assign_attributes(params)
          if object.changed?
            object.save
            increment_counts :updated_count, 1
          end
        else
          object = klass.new(params)
          if object.valid?
            object.save
            increment_counts :imported_count, 1
          end
        end
        object
      end

      def elapsed_time_since start_time = 0
        Process.clock_gettime(Process::CLOCK_MONOTONIC, :second) - start_time
      end

      def log_create_or_update name, count, start_time
        time = elapsed_time_since start_time
        Rails.logger.info "Codifligne:sync - #{count} #{name} retrieved"
        Rails.logger.info "Codifligne:sync - Create or update #{name} done in #{time} seconds"
      end

      def log_deleted name, count
        Rails.logger.info "Codifligne:sync - #{count} #{name} deleted"
      end
    end
  end
end