class RegistrationBehavior < Behavior::Base
  
  class RegistrationTagError < StandardError; end
  
  register "Registration"
  
  description %{
    Use the "Registration" behavior to create a page to register visitors.
    
    The "Registration" behavior provides the following Radius tags:
    
    <r:registration:form>...</r:registration:form>
      The actual form.
    
    <r:registration:form:text />
    <r:registration:form:password />
    <r:registration:form:file />
    <r:registration:form:submit />
    <r:registration:form:reset />
    <r:registration:form:checkbox />
    <r:registration:form:radio />
    <r:registration:form:hidden />
    <r:registration:form:select />
    <r:registration:form:textarea />
    <r:registration:form:radiogroup />
    <r:registration:form:option />
      Form fields to capture visitor information.
  }
  
  attr_reader :form_name, :form_conf, :form_error, :form_data, :tag_attr, :do_redirect, :success_msg, :row
  
  before_filter :proc_req, :for=>:all
 
  def proc_req(request, response)
    RAILS_DEFAULT_LOGGER.info "RegistrationBehavior : proc_rec :: START"
    @request, @response = request, response
    @form_name, @form_error = nil, nil
    if request.post?
      RAILS_DEFAULT_LOGGER.info "RegistrationBehavior : proc_rec :: Doing POST, got this registration\n#{row.inspect}"
      @form_name = request.parameters[:registration_name]
      @form_conf = page_config['registrations'][form_name].symbolize_keys || {}
      @form_data = request.parameters[:registration]
      @row = Registration.new @form_data
      if @row.save
				@row = Registration.new
				@success_msg = "Thank you for registering"
        RAILS_DEFAULT_LOGGER.info "RegistrationBehavior : proc_rec :: Saved succesfully [#{success_msg}], got this registration\n#{row.inspect}"
        if form_conf.has_key? :redirect_to
					@do_redirect = true
          RAILS_DEFAULT_LOGGER.info "RegistrationBehavior : proc_rec :: Redirecting to #{form_conf[:redirect_to]} on process"
        else
          RAILS_DEFAULT_LOGGER.info "RegistrationBehavior : proc_rec :: NOT redirecting"
        end
      else
        @form_error = "There were problems saving your information."
      end
    else
      @row = Registration.new
      RAILS_DEFAULT_LOGGER.info "RegistrationBehavior : proc_rec :: Not POST, got this registration\n#{row.inspect}"
    end
    RAILS_DEFAULT_LOGGER.info "RegistrationBehavior : proc_rec :: END"
  end
	
	def process(request, response)
		RAILS_DEFAULT_LOGGER.info "RegistrationBehavior : process :: START"
		if @do_redirect
			RAILS_DEFAULT_LOGGER.info "RegistrationBehavior : process :: redirecting"
	    response.redirect( form_conf[:redirect_to] ) 
		else
			RAILS_DEFAULT_LOGGER.info "RegistrationBehavior : process :: processing normally"
			super(request, response)
		end
		RAILS_DEFAULT_LOGGER.info "RegistrationBehavior : process :: END"
	end

  # We need to process the page everytime, so that we can send the email!
  def cache_page?
    false
  end
  
  define_tags do 
  
    url = request.request_uri unless request.nil?

    tag 'registration' do |tag|
      tag.expand
    end
    
    tag "registration:form" do |tag|
      @tag_attr = { :class=>get_class_name('form') }.update( tag.attr.symbolize_keys )
      raise_error_if_name_missing 'registration:form'
      results =  %Q(<form action="#{ url }" method="POST" class="#{ tag_attr[:class] }" enctype="multipart/form-data">\n)
      results << %Q(<input type="hidden" name="registration_name" value="#{ tag_attr[:name] }" />\n)
      results << tag.expand
      results << %Q(</form>\n)
    end
		
    tag "registration:form:errors" do |tag|
			results = ""
			unless @row.errors.empty?
				results << %Q{<div class="registration-errors">\n}
				results << %Q{<p>#{tag_attr[:message] || tag_attr[:message] || "There were errors processing the form."}</p>\n}
				results << %Q{<ul>}
				@row.errors.full_messages.each {|e| results << "<li>#{e}</li>" }
				results << %Q{</ul>\n}
				results << %Q{</div>\n}
				#RAILS_DEFAULT_LOGGER.info "RegistrationBehavior : registration:form:errors :: errors:[#{@row.errors.inspect}], html\n#{results}"
			else
				#RAILS_DEFAULT_LOGGER.info "RegistrationBehavior : registration:form :: NO errors, nothing to show"
			end
			results
    end
		
    tag "registration:form:success" do |tag|
			results = ""
			if success_msg
				results << %Q{<div class="registration-success">}
				results << %Q{#{success_msg}}
				results << %Q{</div>}
				RAILS_DEFAULT_LOGGER.info "RegistrationBehavior : registration:form:success :: html\n#{results}"
			else
				RAILS_DEFAULT_LOGGER.info "RegistrationBehavior : registration:success :: NO success msg"
			end
			results
    end
		
    tag 'registration:form:debug' do |tag|
      "<pre>#{row.to_yaml}</pre>"
    end
    
    %w(text password file submit reset checkbox radio hidden).each do |type|
      tag "registration:form:#{type}" do |tag|
        @tag_attr = tag.attr.symbolize_keys
        #RAILS_DEFAULT_LOGGER.info "RegistrationBehavior : registration:form:#{type} :: attrs : #{tag_attr.inspect}"
        raise_error_if_name_missing "registration:form:#{type}" unless %(submit reset).include? type
        input_tag_html( type )
      end      
    end

    tag 'registration:form:select' do |tag|
      @tag_attr = { :id=>tag.attr['name'], :class=>get_class_name('select'), :size=>'1' }.update( tag.attr.symbolize_keys )
      raise_error_if_name_missing "registration:form:select"
      tag.locals.parent_tag_name = tag_attr[:name]
      tag.locals.parent_tag_type = 'select'
      results =  %Q(<select name="registration[#{tag_attr[:name]}]" #{add_attrs_to("")}>)
      results << tag.expand
      results << "</select>"
    end

    tag 'registration:form:option' do |tag|
      @tag_attr = tag.attr.symbolize_keys
      raise_error_if_name_missing "registration:form:option"
      result = ""
      if tag.locals.parent_tag_type == 'select'
        result << %Q{<option value="#{tag_attr[:value] || tag_attr[:name]}" #{add_attrs_to("")}>#{tag_attr[:name]}</option>}
      elsif tag.locals.parent_tag_type == 'radiogroup'
        tag.globals.option_count = tag.globals.option_count.nil? ? 1 : tag.globals.option_count += 1
        name = tag.locals.parent_tag_name
        value = tag_attr[:value] || tag_attr[:name]
        options = tag_attr.clone.update({
          :id => "#{tag.locals.parent_tag_name}_#{tag.globals.option_count}",
          :value => value,
          :name => name
        })
        options[:selected] = "selected" if @row.send(name) == value
        result << input_tag_html( 'radio', options )
        result << %Q|<label for="#{options[:id]}">#{tag_attr[:name]}</label>|
      end
    end

    tag 'registration:form:textarea' do |tag|
      @tag_attr = { :id=>tag.attr['name'], :class=>get_class_name('textarea'), :rows=>'5', :cols=>'35' }.update( tag.attr.symbolize_keys )
      raise_error_if_name_missing "registration:form:textarea"
      results =  %Q(<textarea name="registration[#{tag_attr[:name]}]" #{add_attrs_to("")}>)
      results << get_value_for(tag.attr['name'])
      results << tag.expand
      results << "</textarea>"
    end
    
    tag 'registration:form:radiogroup' do |tag|
      @tag_attr = tag.attr.symbolize_keys
      raise_error_if_name_missing "registration:form:radiogroup"
      tag.locals.parent_tag_name = tag_attr[:name]
      tag.locals.parent_tag_type = 'radiogroup'
      tag.expand
    end

    # For use with email template parts -- retrieves the data posted by the form
    tag 'registration:form:get' do |tag|
      name = tag.attr['name']
      if name
        form_data[name]
      else
        form_data.to_hash.to_yaml.to_s
      end
    end  

  end
  
protected

  def input_tag_html(type, opts=tag_attr)
    options = { :id => "registration-#{tag_attr[:name]}", :value => nil, :class => get_class_name(type) }.update(opts)
		value = get_value_for(tag_attr[:name])
		options[:value]    ||= value if %(text password file hidden).include? type
		options[:checked]  ||= "checked" if %(checkbox radio).include?(type) and value
		options[:checked]  ||= "checked" if type == "checkbox" and value
		options[:checked]  ||= "checked" if type == "radio" and value.to_s == options[:value].to_s
    #RAILS_DEFAULT_LOGGER.info "RegistrationBehavior : input_tag_html(#{type}, #{opts.inspect}) :: options:#{options.inspect} :: [#{value.to_s}:#{options[:value].to_s}]"
		results =  %Q(<input type="#{type}" )
    results << %Q(name="registration[#{options[:name]}]" ) if tag_attr[:name]
    results << "#{add_attrs_to("", options)} "
    results << "/>"
  end

  def add_attrs_to(results, tag_attrs=tag_attr)
    tag_attrs.stringify_keys.sort.each do |name, value|
      results << %Q(#{name.to_s}="#{value.to_s}" ) unless name == 'name'
    end
    results
  end
  
	def get_value_for(name)
		value = @row.send(name).to_s rescue ""
		#RAILS_DEFAULT_LOGGER.info "RegistrationBehavior : get_value_for(#{name}) :: value:#{value.inspect}"
		return value
	end
  
  def get_class_name(type, class_name=nil)
    class_name = 'registration-form' if class_name.nil? and %(form).include? type
    class_name = 'registration-field' if class_name.nil? and %(text password file select textarea).include? type
    class_name = 'registration-button' if class_name.nil? and %(submit reset).include? type
    class_name = 'registration-option' if class_name.nil? and %(checkbox radio).include? type
    class_name
  end
  
  def raise_name_error(tag_name)
    raise RegistrationTagError.new( "`#{tag_name}' tag requires a `name' attribute" )
  end

  def raise_error_if_name_missing(tag_name)
    #RAILS_DEFAULT_LOGGER.info "RegistrationBehavior : raise_error_if_name_missing(#{tag_name}) :: attrs : #{tag_attr.inspect}"
    raise_name_error( tag_name ) if tag_attr[:name].nil? or tag_attr[:name].empty?
  end

end
