module Netzke
  module Basepack
    class Form < Netzke::Base
      module Services
        extend ActiveSupport::Concern

        def submit(data, this)
          # File uploads are in raw params instead of "data" hash, so, mix them in into "data"
          controller.params.each_pair do |k,v|
            data[k] = v if v.is_a?(ActionDispatch::Http::UploadedFile)
          end

          success = create_or_update_record(data)

          if success
            this.set_form_values(js_record_data)
            this.success = true # respond to classic form submission with {success: true}
            this.on_submit_success # inform the Netzke endpoint caller about success
          else
            # flash eventual errors
            data_adapter.errors_array(@record).each do |error|
              flash :error => error
            end
            this.netzke_feedback(@flash)
            this.apply_form_errors(build_form_errors(record))
          end
        end

        def values
          record && record.netzke_hash(fields)
        end

        private

        # Builds the form errors
        def build_form_errors(record)
          form_errors = {}
          foreign_keys = data_adapter.hash_fk_model
          record.errors.to_hash.map{|field, error|
            # some ORM return an array for error
            error = error.join ', ' if error.kind_of? Array
            # Get the correct field name for the errors on foreign keys
            if foreign_keys.has_key?(field)
              fields.each do |k, v|
                # Hack to stop to_nifty_json from camalizing model__field
                field = k.to_s.gsub('__', '____') if k.to_s.split('__').first == foreign_keys[field].to_s
              end
            end
            form_errors[field] ||= []
            form_errors[field] << error
          }
          form_errors
        end

        # Creates/updates a record from hash
        def create_or_update_record(hsh)
          hsh.merge!(config[:strong_default_attrs]) if config[:strong_default_attrs]
          @record ||= data_adapter.find_record hsh.delete(data_class.primary_key.to_s) # only pick up the record specified in the params if it was not provided in the configuration
          #data_class.find(:first, :conditions => {data_class.primary_key => hsh.delete(data_class.primary_key)})
          success = true

          @record = data_class.new if @record.nil?

          hsh.each_pair do |k,v|
            data_adapter.set_record_value_for_attribute(@record, fields[k.to_sym].nil? ? {:name => k} : fields[k.to_sym], v, config.role || :default)
          end

          # did we have complete success?
          success && data_adapter.save_record(@record)
        end
      end
    end
  end
end