/**
 * Manages lists of "things." Should allow for multiple data displayed and provided.
 */
(function($) {
  var removable = {
    onMouseOver: function(obj, elem, id) {
      return function(e) {
        if( elem.find('.edit_field').length > 0 ) {
          elem.find('.edit_field').stop(true);
          elem.find('.edit_field').css('opacity', 1);
        } else {
          elem.css('position', 'relative');
          elem.append('<div class="edit_field"><a class="edit">Edit</a> | <a class="remove">Remove</a></div>');
          elem.find('.edit_field .remove').click(function(e) { $(obj).trigger('remove', id); });
          elem.find('.edit_field .edit').click(function(e) { $(obj).trigger('edit', id); });
          elem.addClass('selected');
        }
      };
    },
    
    onMouseOut: function(elem) {
      return function(e) {
        elem.find('.edit_field').fadeOut(500, function() { 
          elem.find('.edit_field').remove();
          elem.removeClass('selected');          
        });
      };
    }
  }; 
  
  this.ListWidget = Widget.extend({
    defaultOptions: {
      display_format: function(data) { return data.toString(); }, //a function that adjust how to display the record
      type_name: 'Record',
      form_fields: [],
      validation_rules: []
    },
    records: [],
    dialog: null,
    editingID: null,
    buttons: null,
    
    /** 
     * Constructor.
     */
    init: function(options) {
      var self = this;
      
      this.setOptions(options);
      
      //handle remove actions.
      $(this).bind('remove', function(e, id) { self.deleteRecord(e, id); });
      $(this).bind('edit', function(e, id) { self.edit(e, id); });
      this.records = []; //must be unique for each.
      
      //create buttons for add/edit dialog
      //TODO: think about this some more.
      this.buttons = {
        add: {Add: function() { if( self.addRecord()) { $(this).dialog('close'); } }, Cancel: function() { $(this).dialog('close'); } },
        edit: {Save: function() { if( self.saveRecord() ) { $(this).dialog('close'); } }, Cancel: function() { $(this).dialog('close'); } }
      };
    },
    
    /**
     * Remove a record from the current set of records (event handler)
     * @param {Event} e The event object.
     * @param {Integer} id The index of the record to remove.
     */
    deleteRecord: function(e, id) {
      this.records.splice(id, 1);
      this.container.empty();
      this.render();
    },
    
    /**
     * Display the records.
     */
    render: function() {
      var self = this;
      
      //must have a container to render to.
      if( this.container === null ) {
        return;
      }
      
    	for( var i = 0; i < this.records.length; i++ ) {
    	  var record = $('<div></div>');
    	  var disp = this.options.display_format(this.records[i]);
    	  
    	  //hook up event to allow for removal
    	  record.hover(removable.onMouseOver(this, record, i), removable.onMouseOut(record));
    	  
    	  //figure out how to add the display to the content.
    	  if( typeof disp == 'string' ) {
    	    record.html(disp);
    	  } else {
    	    record.append(disp);
    	  }
    	  
    	  this.container.append(record);
    	}
    	
    	//provide an add "button"
    	var add = $('<a></a>')
    	  .html('Add '+ this.options.type_name)
    	  .css('cursor', 'pointer')
    	  .addClass('button')
    	  .click(function(e) { 
    	    var dlg = self.getDialog(); 
    	    dlg.dialog('option', 'title', 'New ' + self.options.type_name);
    	    dlg.dialog('option', 'buttons', self.buttons.add); 
    	    dlg.dialog('open'); });
    	
    	this.container.append(add);
    },
    
    renderForm: function() {
      var form = new Form(this.options.form_fields, {});
      return form.render();
    },
    
    getDialog: function() {
      var self = this;
      var firstTime = false;
      
      if( this.dialog === null ) {
        firstTime = true;
        this.dialog = $('<div></div>');
        this.dialog.dialog({
          modal: true,
          draggable: false,
          resizable: false,
          title: 'New '+ this.options.type_name,
          width: '450',
          buttons: {Add: function() { if( self.addRecord()) { $(this).dialog('close'); } }, Cancel: function() { $(this).dialog('close'); }},
          open: function() { try { $(this).find(':input')[0].focus(); } catch(e) {}} 
        });
      }
      this.dialog.empty().append(this.renderForm());
      if( firstTime ) {
        this.dialog.find(':input')[0].focus();
      }
      return this.dialog;
    },
    
    edit: function(e, id) {
      if( id !== undefined ) {
        var data = this.records[id];
        var dialog = this.getDialog();
        this.editingID = id; //so we know what one we are editing.
        
        dialog.dialog('option', 'title', 'Edit ' + this.options.type_name);
        dialog.dialog('option', 'buttons', this.buttons.edit);
        dialog.dialog('open');
        dialog.databind(data);
      }
    },
    
    /**
     * Called to save a record that is being edited.
     */
    saveRecord: function() {
      var data = this.dialog.scrape();
      
      //do validation
      if( this.options.validation_rules ) {
        //clear errors
        this.dialog.find('.error').removeClass('error');
        var errors = rsv.validate(data, this.options.validation_rules);
        
        var msgs = '';
        for( var key in errors ) {
          this.dialog.find('.'+key).addClass('error');
          msgs += errors[key] + '\n';
        }
        if( msgs ) {
          alert(msgs);
          return false;
        }
        
      }
      
      this.records[this.editingID] = data;
      this.container.empty();
      this.render();
      return true;
    },
    
    addRecord: function() {
      var data = this.dialog.scrape();
      
      //do validation
      if( this.options.validation_rules ) {
        //clear errors
        this.dialog.find('.error').removeClass('error');
        var errors = rsv.validate(data, this.options.validation_rules);
        
        var msgs = '';
        for( var key in errors ) {
          this.dialog.find('.'+key).addClass('error');
          msgs += errors[key] + '\n';
        }
        if( msgs ) {
          alert(msgs);
          return false;
        }
        
      }
      
      this.records.push(data);
      this.container.empty();
      this.render();
      return true;
    }
    
  });
})(jQuery);

