/**
 * @requires javelin-install
 *           javelin-stratcom
 *           javelin-dom
 *           javelin-util
 * @provides multirow-row-manager
 * @javelin
 */


/**
 * Give a MultirowRowManager a table DOM elem to manage.
 * You can add rows, and provide a given ID if you like.
 * You can update rows by ID.
 * Rows are automatically equipped with a removal button.
 * You can listen to the 'row-removed' event on the Manager to get
 * notifications of these row removals, with the DOM id of the removed
 * row as event data.
 */
JX.install('MultirowRowManager', {
  /**
   * @param DOM element <table> root Container for rows
   */
  construct : function(root, minRows) {
    this._root = root;
    this._rows = [];

    if (typeof minRows !== "undefined") {
      this._minRows = minRows;
    } else {
      this._minRows = 1;
    }

    JX.DOM.listen(
      this._root,
      'click',
      JX.MultirowRowManager._removeSigil,
      JX.bind(this, this._onrowremoved));
  },

  members : {
    _count : 0,
    _nextID : 0,
    _root : null,
    _rows : null,

    _generateRowID : function() {
      return "" + this._nextID++;
    },

    _wrapRowContents : function(row_id, row_contents) {
      var row = JX.$N('tr',
                      { sigil : JX.MultirowRowManager.getRowSigil(),
                        meta : { multirow_row_manager_row_id : row_id }
                      },
                      row_contents);

      var removeButton = JX.$N(
        'td',
        {},
        JX.$N(
          'a',
          { className: "button",
            sigil: JX.MultirowRowManager._removeSigil
          },
          '-'));

      JX.DOM.appendContent(row, removeButton);
      return row;
    },

    getRowID : function(row) {
      return JX.Stratcom.getData(row).multirow_row_manager_row_id;
    },
    /**
       * @param row_contents [DOM elements] New contents of row
       * @param row_id row ID to update, will throw if this row has been removed
       */
    updateRow : function(row_id, row_contents) {
      if (__DEV__) {
        if (typeof this._rows[row_id] === "undefined") {
          throw new Error("JX.MultirowRowManager.updateRow(row_id, " +
                          "row_contents): provided row id does not exist." +
                          " Use addRow to create a new row and make sure " +
                          "not to update rows that have been deleted.");
        }
      }
      var old_row = this._rows[row_id];
      var new_row = this._wrapRowContents(row_id, row_contents);
      JX.copy(JX.Stratcom.getData(new_row), JX.Stratcom.getData(old_row));

      JX.DOM.replace(old_row, new_row);
      this._rows[row_id] = new_row;

      this._oncountchanged(); // Fix the new button.
      return new_row;
    },

    addRow : function(row_contents) {
      var row_id = this._generateRowID();
      var row = this._wrapRowContents(row_id, row_contents);
      JX.DOM.appendContent(this._root, row);

      this._count++;
      this._oncountchanged();

      this._rows[row_id] = row;
      return row;
    },
    _onrowremoved : function(e) {
      if (!JX.Stratcom.getData(e.getTarget()).enabled) {
        return;
      }
      var row = e.getNode(JX.MultirowRowManager.getRowSigil());
      var row_id = this.getRowID(row);
      delete this._rows[row_id];
      JX.DOM.remove(row);

      this._count--;
      this._oncountchanged();
      this.invoke('row-removed', row_id);
    },

    _oncountchanged : function(e) {
      var buttons = JX.DOM.scry(
        this._root,
        'a',
        JX.MultirowRowManager._removeSigil);

      var disable = (this._minRows >= 0 && this._count <= this._minRows);
      for (var i = 0; i < buttons.length; i++) {
        var button = buttons[i];
        JX.DOM.alterClass(button, 'disabled', disable);
        JX.Stratcom.getData(button).enabled = !disable;
      }
    }
  },
  events : ['row-removed'],
  statics : {
    getRowSigil : function() {
      return "tools-multirow-row-manager-row";
    },
    _removeSigil : "tools-multirow-row-manager-row-remove"
  }
});

