1require 'rss/itunes'
2require 'rss/maker/2.0'
3
4module RSS
5  module Maker
6    module ITunesBaseModel
7      def def_class_accessor(klass, name, type, *args)
8        name = name.gsub(/-/, "_").gsub(/^itunes_/, '')
9        full_name = "#{RSS::ITUNES_PREFIX}_#{name}"
10        case type
11        when nil
12          klass.def_other_element(full_name)
13        when :yes_other
14          def_yes_other_accessor(klass, full_name)
15        when :yes_clean_other
16          def_yes_clean_other_accessor(klass, full_name)
17        when :csv
18          def_csv_accessor(klass, full_name)
19        when :element, :attribute
20          recommended_attribute_name, = *args
21          klass_name = "ITunes#{Utils.to_class_name(name)}"
22          klass.def_classed_element(full_name, klass_name,
23                                    recommended_attribute_name)
24        when :elements
25          plural_name, recommended_attribute_name = args
26          plural_name ||= "#{name}s"
27          full_plural_name = "#{RSS::ITUNES_PREFIX}_#{plural_name}"
28          klass_name = "ITunes#{Utils.to_class_name(name)}"
29          plural_klass_name = "ITunes#{Utils.to_class_name(plural_name)}"
30          def_elements_class_accessor(klass, name, full_name, full_plural_name,
31                                      klass_name, plural_klass_name,
32                                      recommended_attribute_name)
33        end
34      end
35
36      def def_yes_other_accessor(klass, full_name)
37        klass.def_other_element(full_name)
38        klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
39          def #{full_name}?
40            Utils::YesOther.parse(@#{full_name})
41          end
42        EOC
43      end
44
45      def def_yes_clean_other_accessor(klass, full_name)
46        klass.def_other_element(full_name)
47        klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
48          def #{full_name}?
49            Utils::YesCleanOther.parse(#{full_name})
50          end
51        EOC
52      end
53
54      def def_csv_accessor(klass, full_name)
55        klass.def_csv_element(full_name)
56      end
57
58      def def_elements_class_accessor(klass, name, full_name, full_plural_name,
59                                      klass_name, plural_klass_name,
60                                      recommended_attribute_name=nil)
61        if recommended_attribute_name
62          klass.def_classed_elements(full_name, recommended_attribute_name,
63                                     plural_klass_name, full_plural_name)
64        else
65          klass.def_classed_element(full_plural_name, plural_klass_name)
66        end
67        klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
68          def new_#{full_name}(text=nil)
69            #{full_name} = @#{full_plural_name}.new_#{name}
70            #{full_name}.text = text
71            if block_given?
72              yield #{full_name}
73            else
74              #{full_name}
75            end
76          end
77        EOC
78      end
79    end
80
81    module ITunesChannelModel
82      extend ITunesBaseModel
83
84      class << self
85        def append_features(klass)
86          super
87
88          ::RSS::ITunesChannelModel::ELEMENT_INFOS.each do |name, type, *args|
89            def_class_accessor(klass, name, type, *args)
90          end
91        end
92      end
93
94      class ITunesCategoriesBase < Base
95        def_array_element("category", "itunes_categories",
96                          "ITunesCategory")
97        class ITunesCategoryBase < Base
98          attr_accessor :text
99          add_need_initialize_variable("text")
100          def_array_element("category", "itunes_categories",
101                            "ITunesCategory")
102
103          def have_required_values?
104            text
105          end
106
107          alias_method :to_feed_for_categories, :to_feed
108          def to_feed(feed, current)
109            if text and current.respond_to?(:itunes_category)
110              new_item = current.class::ITunesCategory.new(text)
111              to_feed_for_categories(feed, new_item)
112              current.itunes_categories << new_item
113            end
114          end
115        end
116      end
117
118      class ITunesImageBase < Base
119        add_need_initialize_variable("href")
120        attr_accessor("href")
121
122        def to_feed(feed, current)
123          if @href and current.respond_to?(:itunes_image)
124            current.itunes_image ||= current.class::ITunesImage.new
125            current.itunes_image.href = @href
126          end
127        end
128      end
129
130      class ITunesOwnerBase < Base
131        %w(itunes_name itunes_email).each do |name|
132          add_need_initialize_variable(name)
133          attr_accessor(name)
134        end
135
136        def to_feed(feed, current)
137          if current.respond_to?(:itunes_owner=)
138            _not_set_required_variables = not_set_required_variables
139            if (required_variable_names - _not_set_required_variables).empty?
140              return
141            end
142
143            unless have_required_values?
144              raise NotSetError.new("maker.channel.itunes_owner",
145                                    _not_set_required_variables)
146            end
147            current.itunes_owner ||= current.class::ITunesOwner.new
148            current.itunes_owner.itunes_name = @itunes_name
149            current.itunes_owner.itunes_email = @itunes_email
150          end
151        end
152
153        private
154        def required_variable_names
155          %w(itunes_name itunes_email)
156        end
157      end
158    end
159
160    module ITunesItemModel
161      extend ITunesBaseModel
162
163      class << self
164        def append_features(klass)
165          super
166
167          ::RSS::ITunesItemModel::ELEMENT_INFOS.each do |name, type, *args|
168            def_class_accessor(klass, name, type, *args)
169          end
170        end
171      end
172
173      class ITunesDurationBase < Base
174        attr_reader :content
175        add_need_initialize_variable("content")
176
177        %w(hour minute second).each do |name|
178          attr_reader(name)
179          add_need_initialize_variable(name, 0)
180        end
181
182        def content=(content)
183          if content.nil?
184            @hour, @minute, @second, @content = nil
185          else
186            @hour, @minute, @second =
187              ::RSS::ITunesItemModel::ITunesDuration.parse(content)
188            @content = content
189          end
190        end
191
192        def hour=(hour)
193          @hour = Integer(hour)
194          update_content
195        end
196
197        def minute=(minute)
198          @minute = Integer(minute)
199          update_content
200        end
201
202        def second=(second)
203          @second = Integer(second)
204          update_content
205        end
206
207        def to_feed(feed, current)
208          if @content and current.respond_to?(:itunes_duration=)
209            current.itunes_duration ||= current.class::ITunesDuration.new
210            current.itunes_duration.content = @content
211          end
212        end
213
214        private
215        def update_content
216          components = [@hour, @minute, @second]
217          @content =
218            ::RSS::ITunesItemModel::ITunesDuration.construct(*components)
219        end
220      end
221    end
222
223    class ChannelBase
224      include Maker::ITunesChannelModel
225      class ITunesCategories < ITunesCategoriesBase
226        class ITunesCategory < ITunesCategoryBase
227          ITunesCategory = self
228        end
229      end
230
231      class ITunesImage < ITunesImageBase; end
232      class ITunesOwner < ITunesOwnerBase; end
233    end
234
235    class ItemsBase
236      class ItemBase
237        include Maker::ITunesItemModel
238        class ITunesDuration < ITunesDurationBase; end
239      end
240    end
241  end
242end
243