fcf.module({
  name: "fcfControls:templates/table.wrapper.js",
  dependencies: ["fcf:NClient/Wrapper.js"],
  module: function(Wrapper){

    class TableWrapper extends Wrapper {

      constructor(a_initializeOptions){
        super(a_initializeOptions);
        this._currentDragRow = undefined;
        this._valueCount = fcf.count(this.getArg("value"));
      }

      onArg(a_name, a_value, a_editor, a_ignoreRedrawing, a_isInnerCall, a_suffix) {
        if (this.isChild(a_editor))
          return;
        if (!fcf.empty(a_suffix))
          return;
        if (a_name == "value"){
          if (this._valueCount == fcf.count(a_value))
            return;
          else
            this._valueCount = fcf.count(a_value);
        }
        this.update();
      }

      getRecordIndexByDomElement(a_domElement){
        let lastTR = undefined;
        let indexTR = undefined;
        let element = a_domElement;
        while(element){
          if (element.tagName.toLowerCase() == "tr")
            lastTR = element;
          if (element == this.getDomElement())
            break;
          element = element.parentElement;
        }

        if (!lastTR)
          return;

        let tbody = lastTR.parentElement;
        let counter = 0;
        fcf.each(tbody.childNodes, (a_key, a_element)=>{
          if (a_element == lastTR){
            indexTR = counter;
            return false;
          }
          if (a_element.tagName && a_element.tagName.toLowerCase() == "tr")
            ++counter;
        })

        if (indexTR === undefined)
          return;

        let indexRow = ((this.getArg("page")-1) * this.getArg("outputRowCount")) + indexTR;

        return indexRow;
      }

      getRecordByDomElement(a_domElement){
        let indexRow = this.getRecordIndexByDomElement(a_domElement);
        let value = this.getArg("value");
        return typeof value === "object" ? value[indexRow] : undefined;
      }

      onDragOver(a_event){
        var bottom = false;
        var firstRow = parseInt(this.select("tr[row]")[0].getAttribute("row"));
        var tr = this._getTr(a_event.toElement ? a_event.toElement : a_event.currentTarget);
        var row = tr ? tr.getAttribute("row") : undefined;
        if (row == "bottom"){
          bottom = true;
          row = this.select(">table>tbody")[0].rows.length;
        } else if (isNaN(parseInt(row))  ){
          row = firstRow-1;
        } else {
          row = parseInt(row);
        }
        this._setSelectionDrop(row, bottom);
        a_event.preventDefault();
      }

      onDragEnd(event){
        this._setSelectionDrop(-1);
      }


      onDragStart(a_event){
        if (a_event.target && a_event.target.getAttribute)
          this._currentDragRow = parseInt(a_event.target.getAttribute("row"));
      }

      onDrop(a_event){
        this._setSelectionDrop(-1);
        if (!this.getArg("dragable"))
          return;

        var bottom = false;
        var firstRow = parseInt(this.select("tr[row]")[0].getAttribute("row"));
        var row = this._getTr(a_event.toElement ? a_event.toElement : a_event.currentTarget).getAttribute("row");
        if (row == "bottom"){
          bottom = true;
          row = firstRow + this.select(">table>tbody")[0].rows.length;
        } else if (isNaN(parseInt(row))  ){
          row = firstRow-1;
        } else {
          row = parseInt(row);
        }
        if (row < 0)
          return;

        var rows = this.getArg("value");
        rows.splice(row + (row > this._currentDragRow ? 1 : 0), 0, rows[this._currentDragRow]);
        rows.splice(this._currentDragRow + (this._currentDragRow >= row ? 1 : 0), 1);
        this.setArg("value", rows);
        this.update();
      }

      _setSelectionDrop(a_row, a_bottom){
        let firstRowElement = this.select(">table>tbody>tr")[0];
        let headerRow       = firstRowElement ? parseInt(firstRowElement.getAttribute("row")) - 1 : undefined;
        if (headerRow == a_row && a_row != -1){
          fcf.last(this.select(">table>thead>tr")).classList.add("drag-enter");
         } else {
          fcf.last(this.select(">table>thead>tr")).classList.remove("drag-enter");
        }
        if (a_bottom){
          if (this.select(">table>tfoot>tr")[0])
            this.select(">table>tfoot>tr")[0].classList.add("drag-enter");
         } else {
          if (this.select(">table>tfoot>tr")[0])
            this.select(">table>tfoot>tr")[0].classList.remove("drag-enter");
        }
        fcf.each(this.select(">table>tbody>tr"), (a_key, a_element)=>{
          if (a_element.getAttribute("row") == a_row && a_row != -1){
            a_element.classList.add("drag-enter");
          } else {
            a_element.classList.remove("drag-enter");
          }
        });
      }

      _getTr(a_element){
        while(true){
          var tag = a_element.tagName.toLowerCase();
          if(tag == "tr")
            return a_element;
          if(tag == "body" || tag == "table")
            return;
          a_element = a_element.parentNode;
        }
      }

      onSort (a_event){
        var key       = a_event.target.getAttribute("key");
        var sortOrder = this.getArg("sortOrder", {});
        if (key in sortOrder && sortOrder[key] == "asc")
          sortOrder[key] = "desc";
        else if (key in sortOrder && sortOrder[key] == "desc")
          sortOrder[key] = "unsort";
        else
          sortOrder[key] = "asc";
        this.setArg("sortOrder", sortOrder);
        this.update();
      }

      onSearch(){
        var search = this.getChild("sort").getArg("value");
        this.setArg("search", search);
        this.update();
      }

      onClear(a_event){
        this.setArg("search", "");
        this.update();
      }

      onPage(a_event){
        this.setArg("page", a_event.page);
        this.update();
      }
    };

    return TableWrapper;
  }

});
