//REQUIRES: jQuery (1.3+?), databind (by ddorothy), 
(function($) {
  var test = [
    {name: 'first_name', title: 'First Name', type: 'text'},
    {name: 'color', title: 'Color', type: 'select', options: ['red', 'blue', 'green', 'yellow', 'orange', 'purple']},
    {name: 'age', title: 'Age', type: 'radio', options: ['0-12', '13-18', '19-25', '26-35', '36+']},
    {name: 'blind', title: 'Blind', type: 'checkbox'},
    {name: 'password', title: 'Password', type: 'password'},
    {name: 'birthday', title: 'Birthday', type: 'date'},
    {name: 'description', type: 'textarea'},
    {name: 'bio', title: 'Bio', type: 'wysiwyg'}
  ];
  
  this.Form = Class.extend({
    defaultOptions: {
      use_form_tag: false, /* encapsulate form with a form tag? */
      action: '',
      method: 'POST',
      enctype: null,
      form_name: null,
      form_class: null
    },
    options: null,
    fields: [],
    
    /**
     * Constructor.
     * @param {Array} fields Ordered list of field descriptions.
     * @param {Object} options The options to apply to this Form object. 
     */
    init: function(fields, options) {
      this.fields = fields;
      this.setOptions(options);
    },
    
    /**
     * Builds the options for this object based on the default options and the
     * passed in options
     */
    setOptions: function(options) {
      this.options = {};
      
      //add the default options
      for( var i in this.defaultOptions ) {
        this.options[i] = this.defaultOptions[i];
      }
      
      //add the passed in options
      for( i in options ) {
        this.options[i] = options[i];
      }
    },
    
    render: function() {
      //create the container
      if( this.options.use_form_tag ) {
        var container = $('<form></form>');
        container
          .attr('action', this.options.action)
          .attr('method', this.options.method);
        
        if( this.options.enctype !== null ) {
          container.attr('enctype', this.options.enctype);
        }
        
        if( this.options.form_name !== null ) {
          container.attr('name', this.options.form_name);
        }
      } else {
        container = $('<div></div>');
      }
      
      //add the class if one was provided
      if( this.options.form_class !== null ) {
        container.addClass(this.options.form_class);
      }
      
      //render each form element
      for( var i = 0; i < this.fields.length; i++ ) {
        var field = this.fields[i];
        
        var field_container = $('<div class="field"></div>');
        field_container.addClass(field.type);
        
        if( Form.renderers[field.type] !== undefined ) {  
          var form_field = Form.renderers[field.type](field, field_container);
        } else {
          field_container.html('Unknown field type provided.');
        }
        
        container.append(field_container);
      }
      
      return container;
    }
    
  });
  
  var for_id = 0; //used to track the current for_id for labels. (no access allowed)
  
  this.Form.utils = {
    /**
     * Determines whether to use the name as the title or the title if provided.
     */
    getTitle: function(field) {
      if( field.title === undefined || field.title === null ) {
        return field.name.substr(0,1).toUpperCase() + field.name.substr(1);
      }
      return field.title;
    },
    
    /**
     * Get the next for_id.
     * @return the next for id.
     */
    getFor: function() { //TODO: make accessible outside of here.
      return for_id++;
    },
    
    /**
     * Builds a basic label DOMElement (returns jQuery object)
     * @param {Object} field An object representing the current field.
     * @param {String) id The value to set the DOMElement's 'id' to.
     */
    getLabel: function(field, id) {
      var label = $('<label></label>');
      label.html(Form.utils.getTitle(field));
      label.attr('for', id);
      return label;
    },
    
    /**
     * Adds the basic information to inputs, textareas, and selects.
     * @param {Object} field An object representing the current field.
     * @param {jQuery} elem The DOMElement to add the details to.
     * @param {String) id The value to set the DOMElement's 'id' to.
     */
    setInputBasics: function(field, elem, id) {
      elem.attr('id', id)
        .attr('name', field.name);
      elem.addClass(field.name);
    }
  };
  
  this.Form.renderers = {
    text: function(field, container) {
      var id = Form.utils.getFor();
      container.append(Form.utils.getLabel(field, 'text'+ id));
      
      var input = $('<input type="text"/>');
      Form.utils.setInputBasics(field, input, 'text'+ id);
      container.append(input);
      
      //handle default value
      if( field['default'] ) {
        input.val(field['default']);
      }
    },
    
    // Shows static (read-only) data fields
    label: function(field, container) {
      var id = Form.utils.getFor();
      container.append(Form.utils.getLabel(field, 'label' + id));
      
      var span = $('<p />');
      span.attr('id', 'label' + id).addClass(field.name);
      container.append(span);
    },
    
    // Hack added by JPJ to support hidden fields
    // (needs abstraction so it doesn't duplicate all of "input()"'s code...)
    hidden: function(field, container) {
      var input = $('<input type="hidden"/>');
      Form.utils.setInputBasics(field, input, 'hidden' + Form.utils.getFor());
      container.append(input);
    },
    
    textarea: function(field, container) {
      var id = Form.utils.getFor();
      container.append(Form.utils.getLabel(field, 'textarea'+ id));
      
      var input = $('<textarea></textarea>');
      Form.utils.setInputBasics(field, input, 'textarea'+ id);
      container.append(input);
      
      //handle default value
      if( field['default'] ) {
        input.val(field['default']);
      }
    },
    
    
    wysiwyg: function(field, container) {}, //TODO: wysiwyg
    
        
    password: function(field, container) {
      var id = Form.utils.getFor();
      container.append(Form.utils.getLabel(field, 'password'+ id));
      
      var input = $('<input type="password"/>');
      Form.utils.setInputBasics(field, input, 'password'+ id);
      container.append(input);
    },
    
    
    date: function(field, container) {
      var id = Form.utils.getFor();
      container.append(Form.utils.getLabel(field, 'date' + id));
      
      var input = $('<input type="text"/>');
      Form.utils.setInputBasics(field, input, 'date' + id);
      container.append(input);
      
      var btn = $('<input type="button" value="Pick" />');
      btn.click(function() { DatePicker.display(input.get(0)); });
      container.append(btn);
    }, 
    
    select: function(field, container) {
      var id = Form.utils.getFor();
      container.append(Form.utils.getLabel(field, 'select'+ id));
      
      var input = $('<select></select>');
      Form.utils.setInputBasics(field, input, 'select'+ id);
      
      //handle options
      if( field.options !== undefined && field.options !== null ) {
        try {
          var data = field.options();
        } catch(e) {
          data = field.options;
        }
        for( var i = 0; i < data.length; ++i ) {
          var option = data[i];
          if( typeof option == 'string' || typeof option == 'number' ) { //simple
            input.append('<option>'+option+'</option>');
          } else if( typeof option == 'array' || option instanceof Array ) { //array
            var val = option[0];
            var text = option[0];
            if( option.length > 1 ) {
              text = option[1];
            }
            input.append('<option value="'+ val +'">'+ text +'</option>');
          } else if( typeof option == 'object' ) { //object 
            val = option.value;
            text = option.value;
            if( option.text !== undefined && option.text !== null ) {
              text = option.text;
            }
            input.append('<option value="'+ val +'">'+ text +'</option>');
          }
        }
      }
      
      container.append(input);
    },
    
    
    radio: function(field, container) {}, //TODO: radio
    
    
    checkbox: function(field, container) {
      var id = Form.utils.getFor();
      
      var input = $('<input type="checkbox"/>');
      Form.utils.setInputBasics(field, input, 'text'+ id);
      container.append(input);
      
      //TODO: make this an option
      //standard checkbox order is label second, checkbox first
      container.append(Form.utils.getLabel(field, 'text'+ id));
    }
  };
  
})(jQuery);
