var Duplicatable = new Class({
  initialize: function(element) {
    this.element = element;
    this.add_link = element.getElement(".add");
    if(this.add_link) {
      this.add_link.addEvent("click", this.add.bind(this));
    }
    this.element.getElements(".duplicatable").each(function(duplicatable) {
      this.setup(duplicatable);
    }.bind(this));
  },
  
  add: function(duplicatable) {
    var clone = this.clone(duplicatable || this.element.getElements('.duplicatable').getLast());
    this.reset(clone);
    this.setup(clone);
    window.fireEvent("duplicatable:add", clone);
    clone.inject(this.element.getElements('.duplicatable').getLast(), 'after');
  },
  
  ensureOneEmptyInput: function(duplicatable) {
    // TODO: Consider inputs hidden from duplicatable?
    var emptyElements = this.element.getElements(".duplicatable").filter(function(element) {
      return element.getElement("select").value == "";
    });
    if(emptyElements.length == 0) { this.add(duplicatable); }

    var emptyOption = duplicatable.getElement("select option");
    if(emptyOption && emptyOption.getProperty("value") == "") { emptyOption.remove(); }
  
    // duplicatable.getElement(".remove").show();
    duplicatable.getElement(".remove").style.display = '';
  },
  
  clone: function(duplicatable) {
    var clone = duplicatable.clone();
    // This is required in IE, otherwise clicking the remove link removes all duplicatables.
    // TODO: We may want to remove events from all elements to make sure we don't get double binding going on.
    clone.getElement(".remove").removeEvents();
    var input = duplicatable.getElement("input[type=text]") || duplicatable.getElement("textarea") || duplicatable.getElement("select");
    var match = input.getProperty("id").match(/_(\d+)_/);
    
    if(match) {
      var duplicatable_id = match[1];
      var clone_id = parseInt(duplicatable_id) + 1;
    
      var inputs = duplicatable.getElements("input[type=text]") + duplicatable.getElements("textarea") + duplicatable.getElements("select");
      inputs.each(function(input) {
        input.setProperty("id", input.getProperty("id").gsub("_" + duplicatable_id + "_", "_" + clone_id + "_"));
        input.setProperty("name", input.getProperty("name").gsub(/\[\d+\]/, "[" + clone_id + "]"));
      });
    
      clone.getElements('label').each(function(label) {
        var duplicatable_for = label.getProperty("for");
        if(duplicatable_for) {
          label.setProperty("for", duplicatable_for.gsub("_" + duplicatable_id + "_", "_" + clone_id + "_"));
        }
      });
    }
    
    var delete_field = clone.getElement(".delete");
    if(delete_field) { delete_field.remove(); }
    // clone.show();
    clone.style.display = '';
    
    return clone;
  },
  
  reset: function(duplicatable) {
    duplicatable.getElements('input[type=text]').each(function(input) { input.value = input.getProperty("default") || ""; });
    duplicatable.getElements('textarea').each(function(input) { input.value = ''; });
    duplicatable.getElements('select').each(function(input) { input.selectedIndex = 0; });
  },
  
  setup: function(duplicatable) {
    duplicatable.getElement(".remove").addEvent("click", this.remove.bind(this, duplicatable));
    if(!this.add_link) {
      duplicatable.getElement("select").addEvent("change", this.ensureOneEmptyInput.bind(this, duplicatable));
      if(duplicatable.getElement("select").getProperty("value") == "") {
        // duplicatable.getElement(".remove").hide();
        duplicatable.getElement(".remove").style.display = "none";
      } else {
        // TODO: This can cause the first item to be selected if the actual selected item is no longer available
        var emptyOption = duplicatable.getElement("select option");
        if(emptyOption && emptyOption.getProperty("value") == "") { emptyOption.remove(); }
      }
    }
  },

  remove: function(duplicatable) {
    var visible_duplicatables = this.element.getElements('.duplicatable').filter(function(d) { 
      // return d.visible();
      return d.style.display != 'none';
    });
    
    var delete_field = duplicatable.getElement(".delete");
    if(delete_field) {
      delete_field.value = 1;
      // clone.hide();
      clone.style.display = "none";

      if(visible_duplicatables.length == 1) { this.add(); }
    } else {
      if(visible_duplicatables.length == 1) {
        this.reset(duplicatable);
      } else {
        duplicatable.remove();
      }
    }
    
    window.fireEvent("duplicatable:remove", duplicatable);
  }
});

window.addEvent("domready", function() {
  $$(".duplicatables").each(function(element) {
    new Duplicatable(element);
  }); 
});