<!--
@license
Copyright (c) 2016 The Jviz Project Authors. All rights reserved.
The Jviz Project is under the MIT License. See https://github.com/jviz/jviz/blob/dev/LICENSE
-->

<!-- Import components -->
<link rel="import" href="../../../polymer/polymer.html">
<link rel="import" href="../../../jviz-styles/jviz-styles.html">

<!-- Import jviz elements -->
<link rel="import" href="../../jviz.html">
<link rel="import" href="../jviz-btn/jviz-btn.html">
<link rel="import" href="../jviz-input/jviz-input.html">
<link rel="import" href="../jviz-select/jviz-select.html">

<!-- Import table components -->
<link rel="import" href="./jviz-table-column.html">

<!-- Table component -->
<dom-module id="jviz-table">
  <template>
    <style>
      /* Main element */
      :host
      {
        display: block;
        margin-top: 0px;
        margin-bottom: 10px;
      }

      /* Table header */
      :host .header
      {
        display: block;
      }
      :host .header .title
      {
        @apply --jviz-heading-3;
      }

      /* Main table container */
      :host .main
      {
        display: block;
        width: 100%;
        overflow-x: auto;
        overflow-y: auto;
      }

      /* Table element */
      :host .table
      {
        display: table;
        min-width: 100%;
        table-layout: auto;
        @apply(--jviz-font);
        color: var(--jviz-navy);
        border-collapse: collapse;
        border-width: 0px;
      }

      /* Table head */
      :host .head
      {
        display: table-header-group;
        width: 100%;
        position: relative;
        height: 40px;
        background-color: var(--jviz-grey-2);
      }

      /* Table head row */
      :host .head .row
      {
        display: table-row;
        transition: all 0.3s;
      }

      /* Table head cell */
      :host .head .cell
      {
        display: table-cell;
        transition: all 0.3s;
        vertical-align: top;
        user-select: none;
        -webkit-touch-callout: none;
        -webkit-user-select: none;
        -moz-user-select: none;
        font-weight: bold;
        line-height: 24px;
        text-overflow: ellipsis;
        white-space: nowrap;
        overflow: hidden;
        cursor: pointer;
        padding: 10px;
      }
      :host .head .cell:first-of-type
      {
        border-top-left-radius: 5px !important;
      }
      :host .head .cell:last-of-type
      {
        border-top-right-radius: 5px !important;
      }
      :host .head .sortable
      {
        background-size: 15px 30px;
        background-position: right center;
        background-repeat: no-repeat;
      }
      :host .head .order-none
      {
        background-image: url('./img/tab_order_none.svg');
      }
      :host .head .order-asc
      {
        background-image: url('./img/tab_order_asc.svg');
      }
      :host .head .order-desc
      {
        background-image: url('./img/tab_order_desc.svg');
      }
      :host .head .checkbox
      {
        width: 26px;
        padding-right: 10px;
        padding-left: 10px;
        padding-top: 12px;
        padding-bottom: 12px;
      }

      /* Table body */
      :host .body
      {
        display: table-row-group;
      }

      /* Table body row */
      :host .body .row
      {
        display: table-row;
        transition: all 0.3s;
      }
      :host .body .row:nth-child(even)
      {
        background-color: var(--jviz-grey-4);
      }
      :host .body .row:nth-child(odd)
      {
        background-color: var(--jviz-grey-3);
      }

      /* Table body cell */
      :host .body .row .cell
      {
        display: table-cell;
        transition: all 0.3s;
        padding: 10px;
      }
      :host .body .row:last-of-type .cell:first-of-type
      {
        border-bottom-left-radius: 5px !important;
      }
      :host .body .row:last-of-type .cell:last-of-type
      {
        border-bottom-right-radius: 5px !important;
      }
      
      /* Page control */
      :host .page
      {
        display: block;
        width: 100%;
        height: 30px;
        margin-top: 10px;
        margin-bottom: 10px;
      }
      :host .page .content-left
      {
        display: inline-block;
        float: left;
      }
      :host .page .content-right
      {
        display: inline-block;
        float: right;
      }
      :host .page .text
      {
        display: inline-block;
        height: 30px;
        line-height: 30px;
        vertical-align: top;
      }
      :host .page .text-rows
      {
        padding-right: 5px;
      }
      :host .page .text-page
      {
        padding-left: 6px;
        padding-right: 6px;
      }
      :host .page .space
      {
        display: inline-block;
        width: 15px;
      }
    </style>
    <!-- Columns -->
    <content select="jviz-table-column"></content>
    <div class="header">
      <div class="title">{{ header }}</div>
    </div>
    <div id="main" class="main">
      <!-- Table container -->
      <div id="table" class="table">
        <!-- Table head -->
        <div id="head" class="head">
          <div class="row">
            <template is="dom-if" if="{{ selectable }}">
              <div class="cell checkbox"></div>
            </template>
            <template id="headerRow" is="dom-repeat" items="{{ _columns }}">
              <template is="dom-if" if="{{ item.sortable }}">
                <div class="cell sortable order-none" data-key$="{{ item.key }}" data-index$="{{ item.index }}" on-tap="_tap_head_cell">
                  {{ item.header }}
                </div>
              </template>
              <template is="dom-if" if="{{ !item.sortable }}">
                <div class="cell" data-key$="{{ item.key }}" data-index$="{{ item.index }}" on-tap="_tap_head_cell">
                  {{ item.header }}
                </div>
              </template>
            </template>
          </div>
        </div>
        <!-- Table body -->
        <div id="body" class="body">
          <template id="bodyRow" is="dom-repeat" items="{{ _keys_displayed }}" as="row">
            <div class="row">
              <template is="dom-if" if="{{ selectable }}">
                <div class="cell checkbox"></div>
              </template>
              <template is="dom-repeat" items="{{ _columns }}" index-as="column">
                <div class="cell" data-row$="{{ row }}" data-column$="{{ column }}" on-tap="_tap_body_cell">
                  {{ value(row, column) }}
                </div>
              </template>
            </div>
          </template>
        </div>
      </div>
    </div>
    <!-- Page control -->
    <div class="page">
      <div class="content-left">
        <div class="text text-rows">
          Showing <b>{{ _get_range_start(page, pageSize, rows) }}</b> to
          <b>{{ _get_range_end(page, pageSize, rows) }}</b> of <b>{{ rows }}</b> rows.
        </div>
      </div>
      <div class="content-right">
        <div class="text text-rows">Rows per page:</div>
        <jviz-select id="entries" width="60px">
          <option value="10">10</option>
        </jviz-select>
        <div class="space"></div>
        <jviz-btn color="grey" icon="chevron-left" text="Prev" on-tap="prev_page" icon-align="left"></jviz-btn>
        <div class="text text-page">Page <b>{{ page }}</b> of <b>{{ _page_end }}</b></div>
        <jviz-btn color="grey" icon="chevron-right" text="Next" on-tap="next_page" icon-align="right"></jviz-btn>
      </div>
    </div>
  </template>
</dom-module>

<!-- Table logic -->
<script>
  //Initialize the table element
  var jviz_table = { is: 'jviz-table' };

  //Properties
  jviz_table.properties = {};

  //Table private properties
  jviz_table.properties._sort_keys = { type: Array, value: [] };
  jviz_table.properties._sort_order = { type: Array, value: [] };
  jviz_table.properties._columns = { type: Array, value: [] };
  jviz_table.properties._keys_displayed = { type: Array, value: [] };
  jviz_table.properties._keys_selected = { type: Array, value: [] };
  jviz_table.properties._keys_filtered = { type: Array, value: [] };
  jviz_table.properties._keys_sorted = { type: Array, value: [] };
  jviz_table.properties._page_start = { type: Number, value: 1 };
  jviz_table.properties._page_end = { type: Number, value: 1 };

  //Table public api
  jviz_table.properties.selectable = { type: Boolean, reflectToAttribute: true, value: false };
  jviz_table.properties.header = { type: String, reflectToAttribute: true };
  jviz_table.properties.default = { type: String, reflectToAttribute: true, value: '' };
  jviz_table.properties.rows = { type: Number, value: 0 };
  jviz_table.properties.pageSize = { type: Number, reflectToAttribute: true, value: 10, observer: '_update_page_size' };
  jviz_table.properties.page = { type: Number, reflectToAttribute: true, value: 1, observer: '_update_page' };
  jviz_table.properties.pageEntries = { type: String, reflectToAttribute: true, value: '10', observer: '_update_page_entries' };

  //Table public lists
  jviz_table.properties.columns = { type: Array, value: [], observer: '_update_columns' };
  jviz_table.properties.data = { type: Array, value: [], observer: '_update_data' };

  //Observers
  jviz_table.observers = [ '_get_pages(rows, pageSize)' ];

  //Table is attached
  jviz_table.attached = function()
  {
    //Save this
    var self = this;

    //Save the actual columns
    this.columns = this.queryAllEffectiveChildren('jviz-table-column');

    //Add the entries event listener
    this.$.entries.addEventListener('change:value', function()
    {
      //Update the page size
      self.pageSize = parseInt(self.$.entries.value);
    });
  };

  //Update the columns
  jviz_table._update_columns = function()
  {
    //Save this
    var self = this;

    //Display in console
    console.debug('Update columns information');

    //Initialize the columns list
    var list = [];

    //Read all the columns
    this.columns.forEach(function(col, index)
    {
      //Check if column is visible
      if(col.visible === false){ return; }

      //Save the column information
      list.push({ header: col.header, key: col.key, sortable: col.sortable, index: index });
    });

    //Reset the columns list
    this._columns = list;

    //Update the columns images
    jviz.time_out(50, function()
    {
      //Update the columns images
      return self._images_sort();
    });
  };

  //Update the data
  jviz_table._update_data = function()
  {
    //Display in console
    console.debug('Update data information');

    //Clear the filter
    this._clear_filter();

    //Fire the update data event
    var event = this.fire('update-data', { data: this.data });

    //Check if the prevent default has been set
    if(event.defaultPrevented === false)
    {
      //Display all the data
      //this.display(0, this.data.length - 1);
      this.page = 1;
    }
  };

  //Update the entries number
  jviz_table._update_page_entries = function(value)
  {
    //Initialize the entries list
    var entries = [];

    //Split the entries by comma
    value.split(',').forEach(function(el)
    {
      //Initialize the option object
      var obj = { value: el, text: el, selected: false };

      //Save the option to the entries list
      entries.push(obj);
    });

    //Update the entries values
    this.$.entries.options = entries;

    //Check the number of entries
    if(entries.length > 0)
    {
      //Set the page size as the first entry value
      this.pageSize = parseInt(entries[0].value);
    }
  };

  //Update the page size
  jviz_table._update_page_size = function()
  {
    //Save the actual value
    this.$.entries.value = this.pageSize.toString();
  };

  //Calculate the number of pages
  jviz_table._get_pages = function()
  {
    //Calculate the number of pages
    this._page_end = this.rows / this.pageSize;

    //Parse the number of pages
    this._page_end = (Math.floor(this._page_end) === this._page_end) ? this._page_end : Math.floor(this._page_end) + 1;

    //Check for empty page
    if(this._page_end === 0){ this._page_end = 1; }

    //Check the actual page
    if(this.page === 1)
    {
      //Update the actual page
      this._update_page();
    }
    else
    {
      //Reset the actual page
      this.page = 1;
    }
  };

  //Update the actual page
  jviz_table._update_page = function()
  {
    //Get the start position
    //var start = (this.page - 1) * this.pageSize;

    //Get the end position
    //var end = (this.page) * this.pageSize - 1;

    //Display the data
    //this.display(start, end);

    //Draw the table
    this.reload();
  };

  //Get the start range value
  jviz_table._get_range_start = function()
  {
    //Return the start range value
    return (this.page - 1) * this.pageSize + 1;
  };

  //Get the end range
  jviz_table._get_range_end = function()
  {
    //Return the end range value
    return Math.min(this.rows, this.page * this.pageSize);
  };

  //Get a data value
  jviz_table.value = function(row_index, column_index)
  {
    //Get the column key
    var column_key = this.columns[column_index].key;

    //Get the column parse method
    var column_parse = this.columns[column_index].parse;

    //Get the real index
    //var index = this._keys_displayed[row_index];

    //Get the data value
    var value = (typeof this.data[row_index][column_key] === 'undefined') ? this.default : this.data[row_index][column_key];

    //Check if the parse method is defined
    if(column_parse)
    {
      //Parse the column data
      var new_value = jviz.exec(column_parse, window, value, column_key, this.data[row_index], row_index);

      //Check the new value
      if(typeof new_value !== 'undefined')
      {
        //Save the new value
        value = new_value;
      }
    }

    //Return the data value
    return value;
  };

  //Display a subset of data
  jviz_table.display = function(start, end)
  {
    /*
    //Check for no start position
    if(typeof start !== 'number'){ var start = 0; }

    //Check for no end position
    if(typeof end !== 'number'){ var end = this.rows - 1; }

    //Check the start value
    if(start < 0){ start = 0; }

    //Check the end value
    if(end < 0){ end = 0; }

    //Save the start value
    this._row_start = Math.min(start, end);

    //Save the end value
    this._row_end = Math.max(start, end);
    */

    //Display the data
    //this._display();
    this.reload();
  };

  //Reload the table
  jviz_table.reload = function()
  {
    //Check if data exists
    if(typeof this.data !== 'object'){ return; }

    //Reset the displayed keys
    this._keys_displayed = [];

    //Check for no data to show
    if(this.data.length > 0)
    {
      //Get the computed start position
      //var start = Math.max(0, this._row_start);
      var start = this._get_range_start() - 1;

      //Get the computed end position
      //var end = Math.min(this.rows - 1, this._row_end);
      var end = this._get_range_end() - 1;

      //Display in console (debug)
      console.log('Draw ' + start + ' - ' + end);

      //Build the displayed keys array
      //this._keys_displayed = jviz.array.range(start, end, 1);
      this._keys_displayed = this._keys_sorted.slice(start, end + 1);
    }

    //Render the table
    //this.$.bodyRow.render();
    //this._display_data();
  };

  //Reset all
  jviz_table.reset = function()
  {
    //Clear the data
    this.data = [];
  };

  //Select a row
  jviz_table.select = function(index, notify)
  {

  };

  //Select all rows
  jviz_table.select_all = function(notify)
  {

  };

  //Deselect a row
  jviz_table.deselect = function(index, notify)
  {

  };

  //Deselect all rows
  jviz_table.deselect_all = function(notify)
  {

  };

  //Toggle the selection
  jviz_table.toggle = function()
  {

  };

  //Sort the data
  jviz_table.sort = function(conditions)
  {
    //Save this
    var self = this;

    //Check for undefined conditions
    if(typeof conditions !== 'object'){ var conditions = []; }

    //Check if the conditions is an array
    if(jviz.is.array(conditions) === false){ conditions = [ conditions ]; }

    //Clear the sort
    this._clear_sort();

    //Reset the sort keys
    //this._reset_sort();

    //Read all the conditions
    conditions.forEach(function(el)
    {
      //Check if the key and the order is defined
      if(typeof el.key !== 'string' || typeof el.order !== 'string'){ return; }

      //Save the key value
      self._sort_keys.push(el.key);

      //Save the order value
      self._sort_order.push(el.order);
    });

    //Apply the sort conditions
    this._apply_sort();
  };

  //Sort the data
  jviz_table._apply_sort = function()
  {
    //Save this
    var self = this;

    //Reset the keys order
    this._reset_sort();

    //Check the sort keys
    if(this._sort_keys.length !== 0)
    {
      //Sort the order array
      this._keys_sorted.sort(function(a, b)
      {
        //Compare all keys
        for(var i = 0; i < self._sort_keys.length; i++)
        {
          //Get the column key
          var key = self._sort_keys[i];

          //Get the order
          var order = self._sort_order[i];

          //Check if que difference is numeric
          var numeric = !isNaN(+self.data[a][key] - +self.data[b][key]);

          //Get the values
          var value1 = (numeric === true) ? +self.data[a][key] : self.data[a][key].toLowerCase();
          var value2 = (numeric === true) ? +self.data[b][key] : self.data[b][key].toLowerCase();

          //Check the values
          if(value1 < value2)
          {
            //Check the order
            return (order === 'desc') ? 1 : -1;
          }
          else if(value1 > value2)
          {
            //Check the order
            return (order === 'desc') ? -1 : 1;
          }
        }

        //Default, return 0
        return 0;
      });
    }

    //Display the sort images
    this._images_sort();

    //Display again the data
    //this._display();
    this.reload();
  };

  //Display the sort images
  jviz_table._images_sort = function()
  {
    //Save this
    var self = this;

    //Iterate over all sortable and visible columns
    this.$.head.querySelectorAll('.sortable').forEach(function(col)
    {
      //Remove the asc order
      col.classList.remove('order-asc');

      //Remove the desc order
      col.classList.remove('order-desc');

      //Get the column key
      var key = col.dataset.key;

      //Get the key index in the sort array
      var index = self._sort_keys.indexOf(key);

      //Check if key exists
      if(index === -1)
      {
        //Add the none order
        col.classList.add('order-none');
      }
      else
      {
        //Remove the order none
        col.classList.remove('order-none');

        //Add the order
        col.classList.add('order-' + self._sort_order[index]);
      }
    });
  };

  //Reset the sort
  jviz_table._reset_sort = function()
  {
    //Reset the sorted keys
    this._keys_sorted = this._keys_filtered.concat([]);
  };

  //Clear the sort
  jviz_table._clear_sort = function()
  {
    //Reset the sorted keys
    //this._reset_sort();

    //Clear the sort keys
    this._sort_keys = [];

    //Clear the sort order
    this._sort_order = [];
  };

  //Add a new sort key
  jviz_table._add_sort = function(key)
  {
    //Save the key
    this._sort_keys.push(key);

    //Add the order value
    this._sort_order.push('asc');
  };

  //Change the sort order for a key
  jviz_table._change_sort = function(key)
  {
    //Get the key index
    var index = this._sort_keys.indexOf(key);

    //Check for not found
    if(index === -1){ return false; }

    //Change the order
    if(this._sort_order[index] === 'asc')
    {
      //Change the order to desc
      this._sort_order[index] = 'desc';
    }
    else
    {
      //Remove the item
      this._remove_sort(key);
    }
  };

  //Remove a sort key
  jviz_table._remove_sort = function(key)
  {
    //Get the index
    var index = this._sort_keys.indexOf(key);

    //Check for not found
    if(index === -1){ return; }

    //Remove from the keys array
    this._sort_keys.splice(index, 1);

    //Remove from the order array
    this._sort_order.splice(index, 1);
  };

  //Filter the data
  jviz_table.filter = function(condition)
  {
    //Save this
    var self = this;

    //Check the condition
    if(typeof condition !== 'function'){ return this._clear_filter(); }

    //Reset the filtered array
    this._keys_filtered = [];

    //Read all the data
    this.data.forEach(function(el, index)
    {
      //Call the condition function
      var valid = condition(el, index);

      //Check for no valid
      if(typeof valid === 'boolean' && valid === false){ return; }

      //Save the index
      self._keys_filtered.push(index);
    });

    //Save the number of rows
    this.rows = this._keys_filtered.length;

    //Reset the sorted keys
    //this._reset_sort();

    //Order again the data
    this._apply_sort();
  };

  //Clear the filters
  jviz_table._clear_filter = function()
  {
    //Clear the filter keys
    //this._keys_filtered = Array.apply(null, Array(this.data.length)).map(function(v, i){ return i; });
    this._keys_filtered = jviz.array.range(0, this.data.length - 1, 1);

    //Save the number of rows
    this.rows = this._keys_filtered.length;

    //Reset the sorted keys
    this._reset_sort();

    //Apply the sort conditions
    this._apply_sort();
  };

  //Clicked on a header cell
  jviz_table._tap_head_cell = function(e)
  {
    //Display the column index in console
    console.debug(e.target.dataset.key);

    //Get the column key value
    var column_key = e.target.dataset.key;

    //Get the column index
    var column_index = e.target.dataset.index;

    //Check if this column is sortable
    if(this.columns[column_index].sortable === false){ return; }

    //Check if exists
    var column_exists = this._sort_keys.indexOf(column_key) !== -1;

    //Check for shift key pressed
    if(e.detail.sourceEvent.shiftKey === true)
    {
      //Display in console
      console.debug('Shift pressed');

      //Check if column exists
      if(column_exists === true)
      {
        //Display in console
        console.debug('Key ' + column_key + ' exists, change the order');

        //Change the order
        this._change_sort(column_key);
      }
      else
      {
        //Display in console
        console.debug('Key ' + column_key + ' does not exists, adding');

        //Add the new key
        this._add_sort(column_key);
      }
    }
    else
    {
      //Display in console
      console.debug('Shift not pressed');

      //Check the number of keys sorted
      if(this._sort_keys.length === 0)
      {
        //Display in console
        console.debug('Sort is empty. Adding ' + column_key);

        //Add the new sort key
        this._add_sort(column_key);
      }
      else if(this._sort_keys.length === 1 && column_exists === true)
      {
        //Display in console
        console.debug('Sort key ' + column_key + ' exists, change the key order...');

        //Change the key order
        this._change_sort(column_key);
      }
      else
      {
        //Display in console
        console.debug('Remove all sort keys');

        //Reset the sort arrays
        this._clear_sort();

        //Add the new sort key
        this._add_sort(column_key);
      }
    }

    //Sort the data
    this._apply_sort();
  };

  //Clicked on a body cell
  jviz_table._tap_body_cell = function(e)
  {
    //Get the cell div
    var cell = e.path[0];

    //Check for undefined dataset row and column
    if(typeof cell.dataset.row === 'undefined' || typeof cell.dataset.column === 'undefined'){ return; }

    //Get the row index
    var row_index = parseInt(cell.dataset.row);

    //Get the row data
    var row_data = this.data[row_index];

    //Get the column index
    var column_index = parseInt(cell.dataset.column);

    //Get the column key
    var column_key = this.columns[column_index].key;

    //Get the value
    var value = row_data[column_key];

    //Emit the tap cell
    this.fire('tap:body:cell', { value: value, row: row_data, column: column_key, row_index: row_index, column_index: column_index });
  };

  //Next page
  jviz_table.next_page = function()
  {
    //Check the page
    this.page = (this._page_end <= this.page) ? this._page_end : this.page + 1;
  };

  //Prev page
  jviz_table.prev_page = function()
  {
    //Check the page
    this.page = (this.page <= this._page_start) ? this._page_start : this.page - 1;
  };

  //Go to the first page
  jviz_table.first_page = function()
  {
    //Open the first page
    this.page = this._page_start;
  };

  //Go to the last page
  jviz_table.last_page = function()
  {
    //Open the last page
    this.page = this._page_end;
  };

  //Register the table element
  Polymer(jviz_table);
</script>
