ninoxe 1.0.3 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +15 -0
- data/app/models/chouette/access_point.rb +33 -12
- data/app/models/chouette/active_record.rb +1 -1
- data/app/models/chouette/line.rb +2 -0
- data/app/models/chouette/stop_area.rb +41 -3
- data/app/models/chouette/time_table.rb +351 -45
- data/app/models/chouette/time_table_date.rb +5 -5
- data/app/models/chouette/time_table_period.rb +16 -0
- data/app/models/chouette/trident_active_record.rb +27 -3
- data/app/models/chouette/vehicle_journey.rb +1 -1
- data/config/locales/en.yml +1 -0
- data/config/locales/fr.yml +1 -0
- data/db/migrate/20140617131630_add_on_demand_transportation_to_line.rb +5 -0
- data/db/migrate/20140617132236_add_details_to_vehicle_journey.rb +6 -0
- data/db/migrate/20140618071147_fix_column_name.rb +11 -0
- data/db/migrate/20140625143030_add_in_out_to_timetable_date.rb +5 -0
- data/db/migrate/20140626054725_set_in_out_to_timetable_date.rb +8 -0
- data/db/migrate/20140718141703_acts_as_taggable_on_migration.acts_as_taggable_on_engine.rb +31 -0
- data/db/migrate/20140718141704_add_missing_unique_indices.acts_as_taggable_on_engine.rb +20 -0
- data/db/migrate/20140718141705_add_taggings_counter_cache_to_tags.acts_as_taggable_on_engine.rb +15 -0
- data/db/migrate/20140718141706_add_missing_taggable_index.acts_as_taggable_on_engine.rb +10 -0
- data/db/migrate/20140820060801_add_zip_code_and_city_name_to_stop_area.rb +8 -0
- data/db/migrate/20140820060814_add_zip_code_and_city_name_to_access_point.rb +8 -0
- data/lib/factories/chouette_routes.rb +3 -1
- data/lib/factories/chouette_time_table.rb +2 -2
- data/lib/factories/chouette_vehicle_journey.rb +1 -0
- data/lib/ninoxe/version.rb +1 -1
- data/lib/ninoxe.rb +1 -0
- metadata +117 -118
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
Njg5Yzg4YjEzOWIyZGUxNjc2MWU5YTEzMWYyOThiZTVjZmFlZjI1Yg==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
N2YzZmUzM2Y1MzYyNWYwMDI0MWViOGQzODQzNGEyYjY5MzY2NDY0Yg==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
YzUzNWM2ZWQwMmE4ODkzODYxZGZjNmE2MzViOGUzY2U4NDFiNTE0ZmQ5MDg5
|
10
|
+
ODkzZTJmNjY0YjU2MDdhNThiZWUzYzAxNTQ0N2VlN2U2Y2Q4NTI2NmRhZDJj
|
11
|
+
YjY3MTk5Y2Y4MmQzM2Q0MTJkODUyOTJlMDQzNDVlOGU3ZmJkZTA=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
MDYwZWI4OTZmMDUzNzE0NjRhZjI5OGQ0NzVmZDg4ZjlmMTc2M2Q3ODY5Njk1
|
14
|
+
MTU3YzQ2OWIwYzZiODczMTUyNzQ2ZTBjNWE3OTIwYjlmYjcwZWE1NTA1ZDk3
|
15
|
+
ZGMwOTQzNmEwNzY2NTY4MTYxZDFiOGZlZTFlZjVjMjNlMGY2ZDg=
|
@@ -9,19 +9,16 @@ class Chouette::AccessPoint < Chouette::TridentActiveRecord
|
|
9
9
|
belongs_to :stop_area
|
10
10
|
|
11
11
|
attr_accessor :access_point_type
|
12
|
+
attr_writer :coordinates
|
13
|
+
|
12
14
|
attr_accessible :objectid, :object_version, :creation_time, :creator_id, :name, :comment
|
13
15
|
attr_accessible :longitude, :latitude, :long_lat_type
|
14
|
-
|
15
|
-
attr_accessible :country_code, :street_name
|
16
|
+
attr_accessible :country_code, :street_name, :zip_code, :city_name
|
16
17
|
attr_accessible :openning_time, :closing_time, :access_type, :access_point_type
|
17
18
|
attr_accessible :mobility_restricted_suitability, :stairs_availability, :lift_availability
|
18
19
|
attr_accessible :stop_area_id
|
20
|
+
attr_accessible :coordinates
|
19
21
|
|
20
|
-
# workaround of ruby 1.8 private method y block attribute y reading access
|
21
|
-
#def y
|
22
|
-
# read_attribute :y
|
23
|
-
#end
|
24
|
-
|
25
22
|
validates_presence_of :name
|
26
23
|
validates_presence_of :access_type
|
27
24
|
|
@@ -30,14 +27,38 @@ class Chouette::AccessPoint < Chouette::TridentActiveRecord
|
|
30
27
|
validates_numericality_of :latitude, :less_than_or_equal_to => 90, :greater_than_or_equal_to => -90, :allow_nil => true
|
31
28
|
validates_numericality_of :longitude, :less_than_or_equal_to => 180, :greater_than_or_equal_to => -180, :allow_nil => true
|
32
29
|
|
33
|
-
|
34
|
-
#validates_presence_of :y, :if => :x
|
35
|
-
#validates_numericality_of :x, :allow_nil => true
|
36
|
-
#validates_numericality_of :y, :allow_nil => true
|
30
|
+
validates_format_of :coordinates, :with => %r{\A *-?(0?[0-9](\.[0-9]*)?|[0-8][0-9](\.[0-9]*)?|90(\.[0]*)?) *\, *-?(0?[0-9]?[0-9](\.[0-9]*)?|1[0-7][0-9](\.[0-9]*)?|180(\.[0]*)?) *\Z}, :allow_nil => true, :allow_blank => true
|
37
31
|
|
38
32
|
def self.nullable_attributes
|
39
|
-
[:street_name, :country_code, :comment, :long_lat_type]
|
33
|
+
[:street_name, :country_code, :comment, :long_lat_type, :zip_code, :city_name]
|
34
|
+
end
|
35
|
+
|
36
|
+
before_save :coordinates_to_lat_lng
|
37
|
+
|
38
|
+
def combine_lat_lng
|
39
|
+
if self.latitude.nil? || self.longitude.nil?
|
40
|
+
""
|
41
|
+
else
|
42
|
+
self.latitude.to_s+","+self.longitude.to_s
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def coordinates
|
47
|
+
@coordinates || combine_lat_lng
|
40
48
|
end
|
49
|
+
|
50
|
+
def coordinates_to_lat_lng
|
51
|
+
if ! @coordinates.nil?
|
52
|
+
if @coordinates.empty?
|
53
|
+
self.latitude = nil
|
54
|
+
self.longitude = nil
|
55
|
+
else
|
56
|
+
self.latitude = BigDecimal.new(@coordinates.split(",").first)
|
57
|
+
self.longitude = BigDecimal.new(@coordinates.split(",").last)
|
58
|
+
end
|
59
|
+
@coordinates = nil
|
60
|
+
end
|
61
|
+
end
|
41
62
|
|
42
63
|
def to_lat_lng
|
43
64
|
Geokit::LatLng.new(latitude, longitude) if latitude and longitude
|
data/app/models/chouette/line.rb
CHANGED
@@ -6,11 +6,13 @@ class Chouette::Line < Chouette::TridentActiveRecord
|
|
6
6
|
attr_accessible :transport_mode, :network_id, :company_id, :objectid, :object_version
|
7
7
|
attr_accessible :creation_time, :creator_id, :name, :number, :published_name, :transport_mode_name
|
8
8
|
attr_accessible :registration_number, :comment, :mobility_restricted_suitability, :int_user_needs
|
9
|
+
attr_accessible :flexible_service
|
9
10
|
|
10
11
|
belongs_to :company
|
11
12
|
belongs_to :network
|
12
13
|
has_many :routes, :dependent => :destroy
|
13
14
|
has_many :journey_patterns, :through => :routes
|
15
|
+
has_many :vehicle_journeys, :through => :journey_patterns
|
14
16
|
|
15
17
|
has_and_belongs_to_many :group_of_lines, :class_name => 'Chouette::GroupOfLine', :order => 'group_of_lines.name'
|
16
18
|
attr_accessible :group_of_lines, :group_of_line_ids, :group_of_line_tokens
|
@@ -15,13 +15,14 @@ class Chouette::StopArea < Chouette::TridentActiveRecord
|
|
15
15
|
|
16
16
|
attr_accessor :stop_area_type
|
17
17
|
attr_accessor :children_ids
|
18
|
+
attr_writer :coordinates
|
18
19
|
|
19
20
|
attr_accessible :routing_stop_ids, :routing_line_ids, :children_ids, :stop_area_type, :parent_id, :objectid
|
20
21
|
attr_accessible :object_version, :creation_time, :creator_id, :name, :comment, :area_type, :registration_number
|
21
22
|
attr_accessible :nearest_topic_name, :fare_code, :longitude, :latitude, :long_lat_type
|
22
|
-
attr_accessible :country_code, :street_name
|
23
|
+
attr_accessible :country_code, :street_name, :zip_code, :city_name
|
23
24
|
attr_accessible :mobility_restricted_suitability, :stairs_availability, :lift_availability, :int_user_needs
|
24
|
-
|
25
|
+
attr_accessible :coordinates
|
25
26
|
|
26
27
|
validates_uniqueness_of :registration_number, :allow_nil => true, :allow_blank => true
|
27
28
|
validates_format_of :registration_number, :with => %r{\A[0-9A-Za-z_-]+\Z}, :allow_blank => true
|
@@ -33,11 +34,40 @@ class Chouette::StopArea < Chouette::TridentActiveRecord
|
|
33
34
|
validates_numericality_of :latitude, :less_than_or_equal_to => 90, :greater_than_or_equal_to => -90, :allow_nil => true
|
34
35
|
validates_numericality_of :longitude, :less_than_or_equal_to => 180, :greater_than_or_equal_to => -180, :allow_nil => true
|
35
36
|
|
37
|
+
validates_format_of :coordinates, :with => %r{\A *-?(0?[0-9](\.[0-9]*)?|[0-8][0-9](\.[0-9]*)?|90(\.[0]*)?) *\, *-?(0?[0-9]?[0-9](\.[0-9]*)?|1[0-7][0-9](\.[0-9]*)?|180(\.[0]*)?) *\Z}, :allow_nil => true, :allow_blank => true
|
38
|
+
|
36
39
|
def self.nullable_attributes
|
37
|
-
[:registration_number, :street_name, :country_code, :fare_code, :nearest_topic_name, :comment, :long_lat_type]
|
40
|
+
[:registration_number, :street_name, :country_code, :fare_code, :nearest_topic_name, :comment, :long_lat_type, :zip_code, :city_name]
|
38
41
|
end
|
39
42
|
|
40
43
|
after_update :clean_invalid_access_links
|
44
|
+
|
45
|
+
before_save :coordinates_to_lat_lng
|
46
|
+
|
47
|
+
def combine_lat_lng
|
48
|
+
if self.latitude.nil? || self.longitude.nil?
|
49
|
+
""
|
50
|
+
else
|
51
|
+
self.latitude.to_s+","+self.longitude.to_s
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def coordinates
|
56
|
+
@coordinates || combine_lat_lng
|
57
|
+
end
|
58
|
+
|
59
|
+
def coordinates_to_lat_lng
|
60
|
+
if ! @coordinates.nil?
|
61
|
+
if @coordinates.empty?
|
62
|
+
self.latitude = nil
|
63
|
+
self.longitude = nil
|
64
|
+
else
|
65
|
+
self.latitude = BigDecimal.new(@coordinates.split(",").first)
|
66
|
+
self.longitude = BigDecimal.new(@coordinates.split(",").last)
|
67
|
+
end
|
68
|
+
@coordinates = nil
|
69
|
+
end
|
70
|
+
end
|
41
71
|
|
42
72
|
def children_in_depth
|
43
73
|
return [] if self.children.empty?
|
@@ -278,4 +308,12 @@ class Chouette::StopArea < Chouette::TridentActiveRecord
|
|
278
308
|
end
|
279
309
|
end
|
280
310
|
|
311
|
+
def duplicate
|
312
|
+
sa = self.deep_clone :except => [:object_version, :parent_id, :registration_number]
|
313
|
+
sa.uniq_objectid
|
314
|
+
sa.name = I18n.t("activerecord.copy", :name => self.name)
|
315
|
+
sa
|
316
|
+
end
|
317
|
+
|
318
|
+
|
281
319
|
end
|
@@ -1,13 +1,21 @@
|
|
1
1
|
class Chouette::TimeTable < Chouette::TridentActiveRecord
|
2
2
|
# FIXME http://jira.codehaus.org/browse/JRUBY-6358
|
3
3
|
self.primary_key = "id"
|
4
|
-
|
4
|
+
|
5
5
|
attr_accessible :objectid, :object_version, :creation_time, :creator_id, :version, :comment
|
6
6
|
attr_accessible :int_day_types,:monday,:tuesday,:wednesday,:thursday,:friday,:saturday,:sunday
|
7
7
|
attr_accessible :start_date, :end_date
|
8
|
-
attr_accessible :school_holliday,:public_holliday,:market_day
|
9
8
|
attr_accessor :monday,:tuesday,:wednesday,:thursday,:friday,:saturday,:sunday
|
10
|
-
|
9
|
+
|
10
|
+
acts_as_taggable
|
11
|
+
attr_accessible :tag_list, :tag_search
|
12
|
+
attr_accessor :tag_search
|
13
|
+
|
14
|
+
def self.ransackable_attributes auth_object = nil
|
15
|
+
(column_names + ['tag_search']) + _ransackers.keys
|
16
|
+
end
|
17
|
+
|
18
|
+
has_and_belongs_to_many :vehicle_journeys, :class_name => 'Chouette::VehicleJourney'
|
11
19
|
|
12
20
|
has_many :dates, inverse_of: :time_table, :validate => :true, :class_name => "Chouette::TimeTableDate", :order => :date, :dependent => :destroy, :after_add => :shortcuts_update, :after_remove => :shortcuts_update
|
13
21
|
has_many :periods, inverse_of: :time_table, :validate => :true, :class_name => "Chouette::TimeTablePeriod", :order => :period_start, :dependent => :destroy, :after_add => :shortcuts_update, :after_remove => :shortcuts_update
|
@@ -25,10 +33,10 @@ class Chouette::TimeTable < Chouette::TridentActiveRecord
|
|
25
33
|
validates_associated :periods
|
26
34
|
|
27
35
|
def self.start_validity_period
|
28
|
-
[Chouette::TimeTable.minimum(:start_date)].compact.min
|
36
|
+
[Chouette::TimeTable.minimum(:start_date)].compact.min
|
29
37
|
end
|
30
38
|
def self.end_validity_period
|
31
|
-
[Chouette::TimeTable.maximum(:end_date)].compact.max
|
39
|
+
[Chouette::TimeTable.maximum(:end_date)].compact.max
|
32
40
|
end
|
33
41
|
|
34
42
|
def shortcuts_update(date=nil)
|
@@ -40,7 +48,7 @@ class Chouette::TimeTable < Chouette::TridentActiveRecord
|
|
40
48
|
else
|
41
49
|
self.start_date=dates_array.min
|
42
50
|
self.end_date=dates_array.max
|
43
|
-
end
|
51
|
+
end
|
44
52
|
#else
|
45
53
|
# if dates_array.empty?
|
46
54
|
# update_attributes :start_date => nil, :end_date => nil
|
@@ -88,17 +96,26 @@ class Chouette::TimeTable < Chouette::TridentActiveRecord
|
|
88
96
|
end
|
89
97
|
|
90
98
|
def include_in_dates?(day)
|
91
|
-
self.dates.any?{ |d| d.date === day }
|
99
|
+
self.dates.any?{ |d| d.date === day && d.in_out == true }
|
100
|
+
end
|
101
|
+
|
102
|
+
def excluded_date?(day)
|
103
|
+
self.dates.any?{ |d| d.date === day && d.in_out == false }
|
92
104
|
end
|
93
105
|
|
94
106
|
def include_in_periods?(day)
|
95
|
-
self.periods.any?{ |period| period.period_start <= day &&
|
107
|
+
self.periods.any?{ |period| period.period_start <= day &&
|
108
|
+
day <= period.period_end &&
|
109
|
+
valid_days.include?(day.cwday) &&
|
110
|
+
! excluded_date?(day) }
|
96
111
|
end
|
97
112
|
|
98
113
|
def include_in_overlap_dates?(day)
|
114
|
+
return false if self.excluded_date?(day)
|
115
|
+
|
99
116
|
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
|
100
|
-
counter <= 1 ? false : true
|
101
|
-
|
117
|
+
counter <= 1 ? false : true
|
118
|
+
end
|
102
119
|
|
103
120
|
def periods_max_date
|
104
121
|
return nil if self.periods.empty?
|
@@ -107,11 +124,12 @@ class Chouette::TimeTable < Chouette::TridentActiveRecord
|
|
107
124
|
max_end = self.periods.map(&:period_end).compact.max
|
108
125
|
result = nil
|
109
126
|
|
110
|
-
if max_end
|
111
|
-
max_end.downto(
|
112
|
-
|
113
|
-
|
114
|
-
|
127
|
+
if max_end && min_start
|
128
|
+
max_end.downto( min_start) do |date|
|
129
|
+
if self.valid_days.include?(date.cwday) && !self.excluded_date?(date)
|
130
|
+
result = date
|
131
|
+
break
|
132
|
+
end
|
115
133
|
end
|
116
134
|
end
|
117
135
|
result
|
@@ -123,24 +141,25 @@ class Chouette::TimeTable < Chouette::TridentActiveRecord
|
|
123
141
|
max_end = self.periods.map(&:period_end).compact.max
|
124
142
|
result = nil
|
125
143
|
|
126
|
-
if min_start
|
127
|
-
min_start.upto(
|
128
|
-
|
129
|
-
|
130
|
-
|
144
|
+
if max_end && min_start
|
145
|
+
min_start.upto(max_end) do |date|
|
146
|
+
if self.valid_days.include?(date.cwday) && !self.excluded_date?(date)
|
147
|
+
result = date
|
148
|
+
break
|
149
|
+
end
|
131
150
|
end
|
132
151
|
end
|
133
152
|
result
|
134
153
|
end
|
135
154
|
def bounding_dates
|
136
|
-
bounding_min = self.dates.map(&:date).compact.min
|
137
|
-
bounding_max = self.dates.map(&:date).compact.max
|
155
|
+
bounding_min = self.dates.select{|d| d.in_out}.map(&:date).compact.min
|
156
|
+
bounding_max = self.dates.select{|d| d.in_out}.map(&:date).compact.max
|
138
157
|
|
139
158
|
unless self.periods.empty?
|
140
159
|
bounding_min = periods_min_date if periods_min_date &&
|
141
160
|
(bounding_min.nil? || (periods_min_date < bounding_min))
|
142
|
-
|
143
|
-
bounding_max = periods_max_date if periods_max_date &&
|
161
|
+
|
162
|
+
bounding_max = periods_max_date if periods_max_date &&
|
144
163
|
(bounding_max.nil? || (bounding_max < periods_max_date))
|
145
164
|
end
|
146
165
|
|
@@ -151,6 +170,11 @@ class Chouette::TimeTable < Chouette::TridentActiveRecord
|
|
151
170
|
int_day_types & flag == flag
|
152
171
|
end
|
153
172
|
|
173
|
+
def self.day_by_mask(int_day_types,flag)
|
174
|
+
int_day_types & flag == flag
|
175
|
+
end
|
176
|
+
|
177
|
+
|
154
178
|
def valid_days
|
155
179
|
# Build an array with day of calendar week (1-7, Monday is 1).
|
156
180
|
[].tap do |valid_days|
|
@@ -164,6 +188,19 @@ class Chouette::TimeTable < Chouette::TridentActiveRecord
|
|
164
188
|
end
|
165
189
|
end
|
166
190
|
|
191
|
+
def self.valid_days(int_day_types)
|
192
|
+
# Build an array with day of calendar week (1-7, Monday is 1).
|
193
|
+
[].tap do |valid_days|
|
194
|
+
valid_days << 1 if day_by_mask(int_day_types,4)
|
195
|
+
valid_days << 2 if day_by_mask(int_day_types,8)
|
196
|
+
valid_days << 3 if day_by_mask(int_day_types,16)
|
197
|
+
valid_days << 4 if day_by_mask(int_day_types,32)
|
198
|
+
valid_days << 5 if day_by_mask(int_day_types,64)
|
199
|
+
valid_days << 6 if day_by_mask(int_day_types,128)
|
200
|
+
valid_days << 7 if day_by_mask(int_day_types,256)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
167
204
|
def monday
|
168
205
|
day_by_mask(4)
|
169
206
|
end
|
@@ -185,25 +222,16 @@ class Chouette::TimeTable < Chouette::TridentActiveRecord
|
|
185
222
|
def sunday
|
186
223
|
day_by_mask(256)
|
187
224
|
end
|
188
|
-
|
189
|
-
day_by_mask(512)
|
190
|
-
end
|
191
|
-
def public_holliday
|
192
|
-
day_by_mask(1024)
|
193
|
-
end
|
194
|
-
def market_day
|
195
|
-
day_by_mask(2048)
|
196
|
-
end
|
197
|
-
|
225
|
+
|
198
226
|
def set_day(day,flag)
|
199
|
-
if
|
227
|
+
if day == '1' || day == true
|
200
228
|
self.int_day_types |= flag
|
201
229
|
else
|
202
230
|
self.int_day_types &= ~flag
|
203
231
|
end
|
204
232
|
shortcuts_update
|
205
233
|
end
|
206
|
-
|
234
|
+
|
207
235
|
def monday=(day)
|
208
236
|
set_day(day,4)
|
209
237
|
end
|
@@ -225,15 +253,293 @@ class Chouette::TimeTable < Chouette::TridentActiveRecord
|
|
225
253
|
def sunday=(day)
|
226
254
|
set_day(day,256)
|
227
255
|
end
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
256
|
+
|
257
|
+
def effective_days_of_period(period,valid_days=self.valid_days)
|
258
|
+
days = []
|
259
|
+
period.period_start.upto(period.period_end) do |date|
|
260
|
+
if valid_days.include?(date.cwday) && !self.excluded_date?(date)
|
261
|
+
days << date
|
262
|
+
end
|
263
|
+
end
|
264
|
+
days
|
265
|
+
end
|
266
|
+
|
267
|
+
def effective_days(valid_days=self.valid_days)
|
268
|
+
days=self.effective_days_of_periods(valid_days)
|
269
|
+
self.dates.each do |d|
|
270
|
+
days |= [d.date] if d.in_out
|
271
|
+
end
|
272
|
+
days.sort
|
273
|
+
end
|
274
|
+
|
275
|
+
def effective_days_of_periods(valid_days=self.valid_days)
|
276
|
+
days = []
|
277
|
+
self.periods.each { |p| days |= self.effective_days_of_period(p,valid_days)}
|
278
|
+
days.sort
|
279
|
+
end
|
280
|
+
|
281
|
+
def clone_periods
|
282
|
+
periods = []
|
283
|
+
self.periods.each { |p| periods << p.copy}
|
284
|
+
periods
|
285
|
+
end
|
286
|
+
|
287
|
+
def included_days
|
288
|
+
days = []
|
289
|
+
self.dates.each do |d|
|
290
|
+
days |= [d.date] if d.in_out
|
291
|
+
end
|
292
|
+
days.sort
|
293
|
+
end
|
294
|
+
|
295
|
+
def excluded_days
|
296
|
+
days = []
|
297
|
+
self.dates.each do |d|
|
298
|
+
days |= [d.date] unless d.in_out
|
299
|
+
end
|
300
|
+
days.sort
|
301
|
+
end
|
302
|
+
|
303
|
+
|
304
|
+
# produce a copy of periods without anyone overlapping or including another
|
305
|
+
def optimize_periods
|
306
|
+
periods = self.clone_periods
|
307
|
+
optimized = []
|
308
|
+
i=0
|
309
|
+
while i < periods.length
|
310
|
+
p1 = periods[i]
|
311
|
+
optimized << p1
|
312
|
+
j= i+1
|
313
|
+
while j < periods.length
|
314
|
+
p2 = periods[j]
|
315
|
+
if p1.contains? p2
|
316
|
+
periods.delete p2
|
317
|
+
elsif p1.overlap? p2
|
318
|
+
p1.period_start = [p1.period_start,p2.period_start].min
|
319
|
+
p1.period_end = [p1.period_end,p2.period_end].max
|
320
|
+
periods.delete p2
|
321
|
+
else
|
322
|
+
j += 1
|
323
|
+
end
|
324
|
+
end
|
325
|
+
i+= 1
|
326
|
+
end
|
327
|
+
optimized.sort { |a,b| a.period_start <=> b.period_start}
|
328
|
+
end
|
329
|
+
|
330
|
+
# add a peculiar day or switch it from excluded to included
|
331
|
+
def add_included_day(d)
|
332
|
+
if self.excluded_date?(d)
|
333
|
+
self.dates.each do |date|
|
334
|
+
if date.date === d
|
335
|
+
date.in_out = true
|
336
|
+
end
|
337
|
+
end
|
338
|
+
elsif !self.include_in_dates?(d)
|
339
|
+
self.dates << Chouette::TimeTableDate.new(:date => d, :in_out => true)
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
# merge effective days from another timetable
|
344
|
+
def merge!(another_tt)
|
345
|
+
transaction do
|
346
|
+
# if one tt has no period, just merge lists
|
347
|
+
if self.periods.empty? || another_tt.periods.empty?
|
348
|
+
if !another_tt.periods.empty?
|
349
|
+
# copy periods
|
350
|
+
self.periods = another_tt.clone_periods
|
351
|
+
# set valid_days
|
352
|
+
self.int_day_types = another_tt.int_day_types
|
353
|
+
end
|
354
|
+
# merge dates
|
355
|
+
self.dates ||= []
|
356
|
+
another_tt.included_days.each do |d|
|
357
|
+
add_included_day d
|
358
|
+
end
|
359
|
+
else
|
360
|
+
# check if periods can be kept
|
361
|
+
common_day_types = self.int_day_types & another_tt.int_day_types & 508
|
362
|
+
# if common day types : merge periods
|
363
|
+
if common_day_types != 0
|
364
|
+
periods = self.optimize_periods
|
365
|
+
another_periods = another_tt.optimize_periods
|
366
|
+
# add not common days of both periods as peculiar days
|
367
|
+
self.effective_days_of_periods(self.class.valid_days(self.int_day_types ^ common_day_types)).each do |d|
|
368
|
+
self.dates |= [Chouette::TimeTableDate.new(:date => d, :in_out => true)]
|
369
|
+
end
|
370
|
+
another_tt.effective_days_of_periods(self.class.valid_days(another_tt.int_day_types ^ common_day_types)).each do |d|
|
371
|
+
add_included_day d
|
372
|
+
end
|
373
|
+
# merge periods
|
374
|
+
self.periods = periods | another_periods
|
375
|
+
self.int_day_types = common_day_types
|
376
|
+
self.periods = self.optimize_periods
|
377
|
+
else
|
378
|
+
# convert all period in days
|
379
|
+
self.effective_days_of_periods.each do |d|
|
380
|
+
self.dates << Chouette::TimeTableDate.new(:date => d, :in_out => true) unless self.include_in_dates?(d)
|
381
|
+
end
|
382
|
+
another_tt.effective_days_of_periods.each do |d|
|
383
|
+
add_included_day d
|
384
|
+
end
|
385
|
+
end
|
386
|
+
end
|
387
|
+
# if remained excluded dates are valid in other tt , remove it from result
|
388
|
+
self.dates.each do |date|
|
389
|
+
date.in_out = true if date.in_out == false && another_tt.include_day?(date.date)
|
390
|
+
end
|
391
|
+
|
392
|
+
# if peculiar dates are valid in new periods, remove them
|
393
|
+
if !self.periods.empty?
|
394
|
+
days_in_period = self.effective_days_of_periods
|
395
|
+
dates = []
|
396
|
+
self.dates.each do |date|
|
397
|
+
dates << date unless date.in_out && days_in_period.include?(date.date)
|
398
|
+
end
|
399
|
+
self.dates = dates
|
400
|
+
end
|
401
|
+
self.dates.sort! { |a,b| a.date <=> b.date}
|
402
|
+
self.save!
|
403
|
+
end
|
404
|
+
end
|
405
|
+
|
406
|
+
# remove dates form tt which aren't in another_tt
|
407
|
+
def intersect!(another_tt)
|
408
|
+
transaction do
|
409
|
+
common_day_types = self.int_day_types & another_tt.int_day_types & 508
|
410
|
+
# if both tt have periods with common day_types, intersect them
|
411
|
+
if !self.periods.empty? && !another_tt.periods.empty?
|
412
|
+
if common_day_types != 0
|
413
|
+
periods = []
|
414
|
+
days = []
|
415
|
+
valid_days = self.class.valid_days(common_day_types)
|
416
|
+
self.optimize_periods.each do |p1|
|
417
|
+
another_tt.optimize_periods.each do |p2|
|
418
|
+
if p1.overlap? p2
|
419
|
+
# create period for intersection
|
420
|
+
pi = Chouette::TimeTablePeriod.new(:period_start => [p1.period_start,p2.period_start].max,
|
421
|
+
:period_end => [p1.period_end,p2.period_end].min)
|
422
|
+
if !self.effective_days_of_period(pi,valid_days).empty? && !another_tt.effective_days_of_period(pi,valid_days).empty?
|
423
|
+
if pi.period_start == pi.period_end
|
424
|
+
days << pi.period_start
|
425
|
+
else
|
426
|
+
periods << pi
|
427
|
+
end
|
428
|
+
end
|
429
|
+
end
|
430
|
+
end
|
431
|
+
end
|
432
|
+
# intersect dates
|
433
|
+
days |= another_tt.intersects(self.included_days) & self.intersects(another_tt.included_days)
|
434
|
+
excluded_days = self.excluded_days | another_tt.excluded_days
|
435
|
+
self.dates.clear
|
436
|
+
days.each {|day| self.dates << Chouette::TimeTableDate.new( :date =>day, :in_out => true)}
|
437
|
+
self.periods = periods
|
438
|
+
common_day_types = 0 if periods.empty?
|
439
|
+
self.int_day_types = common_day_types
|
440
|
+
days_of_periods = self.effective_days_of_periods
|
441
|
+
excluded_days.each do |day|
|
442
|
+
self.dates << Chouette::TimeTableDate.new( :date =>day, :in_out => false) if days_of_periods.contains?(day)
|
443
|
+
end
|
444
|
+
end
|
445
|
+
else
|
446
|
+
# transform tt as effective dates and get common ones
|
447
|
+
days = another_tt.intersects(self.effective_days) & self.intersects(another_tt.effective_days)
|
448
|
+
self.dates.clear
|
449
|
+
days.each {|d| self.dates << Chouette::TimeTableDate.new( :date =>d, :in_out => true)}
|
450
|
+
self.periods.clear
|
451
|
+
self.int_day_types = 0
|
452
|
+
end
|
453
|
+
self.dates.sort! { |a,b| a.date <=> b.date}
|
454
|
+
self.save!
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
458
|
+
|
459
|
+
def disjoin!(another_tt)
|
460
|
+
transaction do
|
461
|
+
common_day_types = self.int_day_types & another_tt.int_day_types & 508
|
462
|
+
# if both tt have periods with common day_types, reduce first ones to exclude second
|
463
|
+
if !self.periods.empty? && !another_tt.periods.empty?
|
464
|
+
if common_day_types != 0
|
465
|
+
periods = []
|
466
|
+
days = []
|
467
|
+
valid_days = self.class.valid_days(self.int_day_types)
|
468
|
+
remain_days = self.class.valid_days(self.int_day_types & ~another_tt.int_day_types)
|
469
|
+
self.optimize_periods.each do |p1|
|
470
|
+
deleted = false
|
471
|
+
another_tt.optimize_periods.each do |p2|
|
472
|
+
if p2.contains? p1
|
473
|
+
# p1 is removed, keep remaining dates as included
|
474
|
+
days |= self.effective_days_of_period(p1,remain_days)
|
475
|
+
deleted = true
|
476
|
+
break
|
477
|
+
elsif p1.contains? p2
|
478
|
+
# p1 is broken in 2; keep remaining dates covered by p2 as included days
|
479
|
+
days |= self.effective_days_of_period(p2,remain_days)
|
480
|
+
if p1.period_start != p2.period_start
|
481
|
+
pi = Chouette::TimeTablePeriod.new(:period_start => p1.period_start,
|
482
|
+
:period_end => p2.period_start - 1)
|
483
|
+
if !self.effective_days_of_period(pi,valid_days).empty?
|
484
|
+
if pi.period_start == pi.period_end
|
485
|
+
days << pi.period_start
|
486
|
+
else
|
487
|
+
periods << pi
|
488
|
+
end
|
489
|
+
end
|
490
|
+
end
|
491
|
+
if p1.period_end != p2.period_end
|
492
|
+
p1.period_start = p2.period_end + 1
|
493
|
+
else
|
494
|
+
deleted = true
|
495
|
+
break
|
496
|
+
end
|
497
|
+
elsif p1.overlap? p2
|
498
|
+
if p2.period_start <= p1.period_start
|
499
|
+
p2.period_start = p1.period_start
|
500
|
+
p1.period_start = p2.period_end + 1
|
501
|
+
else
|
502
|
+
p2.period_end = p1.period_end
|
503
|
+
p1.period_end = p2.period_start - 1
|
504
|
+
end
|
505
|
+
days |= self.effective_days_of_period(p2,remain_days)
|
506
|
+
end
|
507
|
+
end
|
508
|
+
unless deleted || self.effective_days_of_period(p1,valid_days).empty?
|
509
|
+
if p1.period_start != p1.period_end
|
510
|
+
periods << p1
|
511
|
+
else
|
512
|
+
days << p1.period_start
|
513
|
+
end
|
514
|
+
end
|
515
|
+
end
|
516
|
+
# rebuild periods and dates
|
517
|
+
self.periods = periods
|
518
|
+
self.int_day_types = 0 if periods.empty?
|
519
|
+
days.each { |d| self.dates |= [Chouette::TimeTableDate.new( :date =>d, :in_out => true)] }
|
520
|
+
end
|
521
|
+
else
|
522
|
+
# otherwise remove or exclude dates and delete empty periods
|
523
|
+
# first remove peculiar dates
|
524
|
+
days = self.intersects(another_tt.effective_days)
|
525
|
+
self.dates -= self.dates.select{|date| days.include?(date.date)}
|
526
|
+
# then add excluded dates
|
527
|
+
self.intersects(another_tt.effective_days).each do |d|
|
528
|
+
self.dates |= [Chouette::TimeTableDate.new( :date =>d, :in_out => false)]
|
529
|
+
end
|
530
|
+
end
|
531
|
+
self.dates.sort! { |a,b| a.date <=> b.date}
|
532
|
+
self.periods.sort! { |a,b| a.period_start <=> b.period_start}
|
533
|
+
self.save!
|
534
|
+
end
|
535
|
+
end
|
536
|
+
|
537
|
+
def duplicate
|
538
|
+
tt = self.deep_clone :include => [:periods, :dates], :except => :object_version
|
539
|
+
tt.uniq_objectid
|
540
|
+
tt.comment = I18n.t("activerecord.copy", :name => self.comment)
|
541
|
+
tt
|
542
|
+
end
|
237
543
|
|
238
544
|
end
|
239
545
|
|
@@ -2,18 +2,18 @@ class Chouette::TimeTableDate < Chouette::ActiveRecord
|
|
2
2
|
self.primary_key = "id"
|
3
3
|
belongs_to :time_table, inverse_of: :dates
|
4
4
|
acts_as_list :scope => 'time_table_id = #{time_table_id}',:top_of_list => 0
|
5
|
-
|
5
|
+
|
6
6
|
validates_presence_of :date
|
7
7
|
validates_uniqueness_of :date, :scope => :time_table_id
|
8
8
|
|
9
|
-
attr_accessible :date, :position, :time_table_id, :time_table
|
10
|
-
|
9
|
+
attr_accessible :date, :position, :time_table_id, :time_table, :in_out
|
10
|
+
|
11
11
|
after_update :update_parent
|
12
|
-
|
12
|
+
|
13
13
|
def self.model_name
|
14
14
|
ActiveModel::Name.new Chouette::TimeTableDate, Chouette, "TimeTableDate"
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
def update_parent
|
18
18
|
time_table.shortcuts_update
|
19
19
|
end
|