const Table = function(cfg){
  Object.assign(this, cfg);

  if(this.childrenEl && this.dom){
    D.appendChild(this.dom, this.childrenEl);
  }

  if(this.childrenEl && !this.dom){

    this.dom = this.childrenEl.parentNode;
    if(!this.dom){
      this.dom = this.childrenEl;
    }
  }

  const children = this.childrenEl = this.childrenEl || D.div({
    cls: 'cmp-table__children'
  });



  this.dom = this.dom || D.div({
    cls: D.cls('cmp-table', cfg.cls)
  }, children);

  this.currentSlice = [];
  this.childrenEls = [];

  if(this.items instanceof Store.StoreBinding){
    this.items.sub((items)=>{
      this.items = items;
      this.updateChildren();
    });
  }
  if(this.action){
    let actions = this.action;
    delete this.action;
    this.getActionDelegate((name, obj)=>{
      if(name in actions){
        actions[name].call(this, obj.data, obj)
      }else{
        console.warn('CMP.TABLE:error → action `'+name+'` is not specified!', obj);
      }
    });
  }
  setTimeout(()=>this.updateChildren(),0);
};
let regExpsCache = {};
Table.prototype = {
  key: 'id',
  currentSlice: [],
  childrenEls: [],
  sort: [{name: 'asc'}],
  childrenEl: null,
  filterText: '',
  filterFn: () => true,
  afterFilter: ()=>true,
  emptyTpl: ()=><div class={'empty-table'}/>,
  buildFilterRegExp: function(text) {
    return new RegExp(text.replace(/[\[\]\(\)\?\*\.\+]/g,'').replace(/\s+/g,'|'), 'ig');
  },
  filter: function(text) {
    this.filterText = text;
    this.filterRegExp = this.buildFilterRegExp(text);
  },
  fetch: function() {
    const sortFn = typeof this.sort === 'function';
    const field = sortFn ? null :Object.keys(this.sort[0])[0]

    this.currentSlice = (this.items || [])
      .filter(item=>this.filterFn.call(item, this.filterText, this))
      .sort(sortFn?this.sort:(a,b)=>a[field] > b[field] ? 1 : a[field] < b[field] ? -1 : 0)
      .map(data=>({data, dom: null}));

    this.afterFilter(this.getSelected());
  },
  updateChildren: function() {
    this.fetch();
    D.removeChildren(this.childrenEl);
    this.currentSlice.forEach((item) => {
      D.appendChild(this.childrenEl, item.dom = this.itemTpl(item.data, this, item));
    });
    if(this.currentSlice.length === 0){
      D.appendChild(this.childrenEl, this.emptyTpl(this.items));
    }
  },
  updateChild: function(item) {
    if(item.dom){
      const dom = this.itemTpl(item.data, this, item);
      item.dom.parentNode.replaceChild(dom, item.dom);
      item.dom = dom;
    }
  },
  removeChild: function(item, full) {
    if(item.dom){
      item.dom.parentNode.removeChild(item.dom);
      item.dom = null;
      this.currentSlice = this.currentSlice.filter(i=>!(i.data===item.data));
      if(full)
        this.items = this.items.filter(i=>!(i===item.data));
    }
  },
  removeChildByData: function(data, full) {
    const match = this.currentSlice.filter(i=>i.data===data),
      item = match[0];

    if(!item)
      return;

    this.removeChild(item, full);
  },
  updateChildByData: function(data) {
    const match = this.currentSlice.filter(i=>i.data===data),
      item = match[0];

    if(!item)
      return;

    if(item.dom){
      const dom = this.itemTpl(item.data, this, item);
      item.dom.parentNode.replaceChild(dom, item.dom);
      item.dom = dom;
    }
  },
  getSelected: function() {
    return this.currentSlice.filter(i=>!i.hidden).map(i=>i.data)
  },
  highlight: function(text, filterText) {
    if(!filterText)
      return text;
    let reg = regExpsCache[filterText] || (regExpsCache[filterText] = this.buildFilterRegExp(filterText))
    const txts = [];

    return D.join(text.replace(reg, function(match) {
      txts.push(match);
      return '|||||'
    }).split('|||||'), (i)=>D.span({cls: 'highlighted'}, txts[i]))
  },
  preventAction: true,
  getActionDelegate: function(fn) {
    var me = this;
    return this.action || (this.action = function(e) {
      const [type, val] = this.getAttribute('data-action').split(':');
      const match = me.currentSlice.filter(({data})=>data[me.key]+'' === val+'');
      if(!match || !match.length){
        debugger
        return;
      }
      if(fn){
        fn(type, match[0]);
      }else{
        if( type === 'hide' ){
          if( match.length ){
            match[ 0 ].hidden = true;
            me.updateChild( match[ 0 ] )
            me.afterFilter( me.getSelected() );
          }
        }
        if( type === 'toggle' ){
          if( match.length ){
            match[ 0 ].full = !match[ 0 ].full;
            me.updateChild( match[ 0 ] )
          }
        }
      }
      me.preventAction && e.stopPropagation();
    });
  },

};

export default Table;
export { Table };