/*
* Copyright (c) 2021 Xilinx, Inc.
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 
* associated documentation files (the "Software"), to deal in the Software without restriction, including 
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
* copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to 
* the following conditions: 
* 
* The above copyright notice and this permission notice shall be included in all copies or substantial 
* portions of the Software. 
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 
* LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* 
*
*
*/
import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
import '@polymer/paper-input/paper-input.js';
import '@polymer/iron-icons/iron-icons.js';
import '@polymer/iron-iconset-svg/iron-iconset-svg.js';
import '@polymer/paper-button/paper-button.js';
import '@polymer/iron-ajax/iron-ajax.js';
import '../../shared/datatable-imports';
import '@vaadin/vaadin-upload/vaadin-upload';
import { api_url, socket_url, notificationRef, configObj } from '../../shared/constants.js';
import { redirectToLogin, handleErrorResponse, handlePaging, _updatepaginationtext } from '../../shared/shared-script';
class memoryData extends PolymerElement {
  static get template() {
    return html`
      <style>
        :host {
          display: block;
        }
        #memorywatchWidget{
          display: flex;
        }
        paper-input{
          margin-right: 15px;
        }
        paper-card {
          display: block;
          width: 100%;
          margin: auto;
          --paper-card-background-color: white;
        }
        paper-button {
          font-family: 'Roboto', 'Noto', sans-serif;
          font-weight: normal;
          font-size: 14px;
          -webkit-font-smoothing: antialiased;
          height: 30px;
        }
        paper-button.blue {
          background-color: var(--paper-blue-500);
          color: white;
        }
        exmg-paper-toolbar .flex {
          @apply --layout-flex;
        }
        iron-input {
          width: 100%;
        }
        input {
          font-size: 14px;
          margin: 0px 4px;
          padding: 4px;
          border: 0px solid var(--divider-color);
          width: 100%;
        }
        exmg-paper-toolbar span.interactive-content {
          margin-left: 10px;
          white-space: nowrap;
          overflow: hidden;
          color: rgba(0,0,0,0.38);
          font-size: 14px;
          text-overflow: ellipsis;
          letter-spacing: .005em;
          box-sizing: border-box;
          font-weight: 400;
          cursor: pointer;
          width: 100%;
        }
        .search {
          background: #fff;
          box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14),
              0 1px 5px 0 rgba(0, 0, 0, 0.12),
              0 3px 1px -2px rgba(0, 0, 0, 0.2);
        }
        .search input {
          outline: none;
        }
        exmg-paper-datatable{
          font-size:14px;
        }
        .mt-15px {
          margin-top: 15px;
        }
        .exportAnchor {
          text-decoration: none;
          color: #fff !important;
        }
        .text-right {
          text-align: right;
        }
      </style>
      <div id="memorywatchWidget">
        <paper-input always-float-label label="Address" id="addressip" value={{hexValue}} auto-validate pattern="[a-fA-F0-9]*" maxlength="11">
          <div slot="prefix">0x</div>
        </paper-input>
        <paper-input always-float-label label="Memory Length" id="lengthip" value={{hexLen}} auto-validate pattern="[0-9]*" maxlength="4"></paper-input>
        <paper-button class="blue mt-15px" raised onink hidden={{start}} on-tap="_watchMemory">Start</paper-button>
        <paper-button class="blue mt-15px" raised onink hidden={{!start}} on-tap="_stopwatchMemory">Stop</paper-button>
      </div>
      <vaadin-upload id="uploadmw" headers={{headers}} class="uploadBtn mt-15px" accept=".tcl" target=[[url]] max-files="1" max-file-size="1000000">
        <span slot="drop-label">Please upload .tcl file</span>
      </vaadin-upload>
      <div id="memorywatchTable" hidden={{!rawItems.length}} class="mt-15px">
        <p class="text-right" hidden={{!rawItems.length}}>
          <paper-button raised class="blue" noink on-tap="_export" title="Download(csv)">
            <iron-icon icon="swap-vert"></iron-icon>
            <a id="exportData" class="exportAnchor">Download</a>
          </paper-button>
        </p>
        <paper-card elevation="1">
          <exmg-paper-datatable>
            <!-- THead -->
            <exmg-paper-thead sort-direction="{{sortDirection}}">
              <template>
                <div class="tr">
                  <div class="th flex-none" style="width:50%">
                    <span title="Address">Address</span>
                  </div>
                  <div class="th flex-none" style="width:50%">
                    <span title="Value">Value</span>
                  </div>
                </div>
              </template>
            </exmg-paper-thead>
            <exmg-paper-tbody items="[[items]]" id="memoryTable">
              <template>
                <div class="tr">
                  <div class="td flex-none" style="width:50%;height: auto;padding-top: .5em;padding-bottom: .5em;">
                    <span title={{_getaddress(item)}}>[[_getaddress(item)]]</span>
                  </div>
                  <div class="td flex-none" style="width:50%;height: auto;padding-top: .5em;padding-bottom: .5em;">
                    <span title={{_getvalue(item)}}>[[_getvalue(item)]]</span>
                  </div>
                </div>
              </template>
            </exmg-paper-tbody>
          </exmg-paper-datatable>
          <!-- Table Paging -->
          <exmg-paper-paging total-items={{totalItems}} page-index="{{pageIndex}}" page-size="{{pageSize}}"></exmg-paper-paging>
        </paper-card>
        <!-- Filter items by filter value and return resulting items to the data provider  -->
        <exmg-paper-data-filter raw-items="[[rawItems]]" items="{{filteredItems}}" filter-value="[[filterValue]]" filter-fields="address"></exmg-paper-data-filter>
        <!-- Manage sorting and paging  -->
        <exmg-paper-data-helper raw-items="[[filteredItems]]" items="{{items}}" page-index="[[pageIndex]]" page-size="[[pageSize]]" sorted="[[sorted]]" sort-direction="[[sortDirection]]" total-items={{totalItems}}></exmg-paper-data-helper>
        <iron-ajax id="memorywatchAjax" method="post" url="[[url]]" body={{memorycommand}} handle-as="json" content-type="application/json" last-response="{{handleResponse}}" on-error="_handleErrorResponse"></iron-ajax>
        <iron-ajax id="stopwatch" method="post" body={{closeBody}} url="[[urlstop]]" handle-as="json" content-type="application/json" last-response="{{handleResponse}}" on-error="_handleErrorResponse"></iron-ajax>
        </div>
      `;
  }
  static get properties() {
    return {
      url: {
        type: String,
        value: `${api_url}watch`
      },
      urlstop: {
        type: String,
        value: `${api_url}closeplot/`
      },
      memorycommand: {
        type: Object,
        value: { "command": "" },
      },
      hexValue: {
        type: String,
        value: ''
      },
      hexLen: {
        type: Number,
      },
      rawItems: {
        type: Array,
        value: []
      },
      pageIndex: {
        type: Number,
        value: 0,
      },
      pageSize: {
        type: Number,
        value: 25,
      },
      sorted: {
        type: String,
        value: 'address',
      },
      sortDirection: {
        type: String,
        value: 'ASC',
      },
      filterValue: {
        type: String,
        value: '',
      },
      start: {
        type: Boolean,
        value: false
      },
      headers: {
        type: Object,
        value: { 'uid': ''}
      },
      closeBody: {
        type: Array,
        Value: []
      }
    };
  }

  _handleErrorResponse(req) {
    handleErrorResponse(req);
  }

  _stopwatchMemory() {
    let self = this;
    self.closeBody = [];
    self.closeBody.push({ 'threadname': self.headers.uid + '_watch'});
    let request = self.$.stopwatch.generateRequest();
    request.completes.then((req) => {
      if (req.response.status === "Fail") {
        notificationRef.setAttribute('text', 'Please Connect to board and try again');
      } else {
        notificationRef.setAttribute('text', 'Memory watch stopped');
        self.ws.close();
      }
      self.start = false;
      notificationRef.open();
    });
  }

  _export() {
    if (this.rawItems && this.rawItems.length === 0) {
      return;
    }
    let row = "";
    let csv = "";
    let fileName = 'sysWatch'
    const table = this.rawItems;
    const columnHeaders = this.shadowRoot.querySelector('exmg-paper-thead').shadowRoot.querySelectorAll('span');
    for (let i = 0; i < columnHeaders.length; i++) {
      csv += columnHeaders[i].innerText + ",";
    }
    csv += '\r\n';
    for (let i = 0; i < table.length; i++) {
      row = '';
      if (table[i].indexOf(':') > -1) {
        const splitVal = table[i].split(':');
        for (let k = 0; k < splitVal.length; k++) {
          if (splitVal[k])
            row += splitVal[k].trim() + ',';
          else
            row += '-' + ',';
        }
      }
      row = row.slice(0, row.length - 1);
      csv += row + '\r\n';
    }
    const hrefUrl = 'data:text/csv;charset=utf-8,' + encodeURIComponent(csv);
    const sender = this.$.exportData;
    sender.setAttribute("href", hrefUrl);
    sender.setAttribute("download", fileName + ".csv");
  }

  _getaddress(item) {
    if (item && item.indexOf(':') > -1)
      return item.split(':')[0];
  }

  _getvalue(item) {
    if (item && item.indexOf(':') > -1)
      return item.split(':')[1];
  }

  _getFilterValue(filterValue) {
    return filterValue || this.placeHolder;
  }

  _watchMemory() {
    const addrErr = this.$.addressip.invalid;
    const lengthErr = this.$.lengthip.invalid;
    if (this.$.addressip.value !== "" && this.$.lengthip.value !== "" && addrErr === false && lengthErr === false) {
      if (this.$.addressip.value.length == 8 || this.$.addressip.value.length == 11) {
        document.querySelector("#pageloader").style.display = "block";
        let data = [];
        data.push('0x' + this.hexValue);
        this.memorycommand = { "threadname": this.headers.uid + "_watch", "command": data, "size" : this.hexLen, "delay": 2 };
        let self = this;
          let request = self.$.memorywatchAjax.generateRequest();
          request.completes.then((req) => {
            if (req.response.status === "Fail") {
              MyAppGlobals.stopMemoryWatch = true;
              notificationRef.setAttribute('text', 'Please Connect to board and try again');
              notificationRef.open();
              document.querySelector("#pageloader").style.display = "none";
            } else {
              const thread = req.response.response[0].threadname;
              const threadcreate_time = req.response.response[0].thread_createtime;
              self.wbsocketCheck(self,thread,threadcreate_time);
            }
          }, () => {
            if (request.status == 400)
              redirectToLogin();
          });
      } else {
        notificationRef.setAttribute('text', 'The length of the address must be 8 or 11 characters');
        notificationRef.open();
      }
    } else {
      notificationRef.setAttribute('text', 'Please enter correct data');
      notificationRef.open();
    }
  }

  wbsocketCheck(self,thread,threadcreate_time) {
    if ("WebSocket" in window) {
      let ws = new WebSocket(`ws://${socket_url}/ws`);
      this.ws = ws;
      self.start = true;
      const tab_name = "syswatch";
      const keyref = 'syswatchref';
      configObj[keyref] = '';
      const session = JSON.parse(localStorage.getItem('storedUser'));
      ws.onopen = () => {
        ws.send(JSON.stringify({"tabname":tab_name,"uid":session["uid"], "threadname":thread, "thread_createtime":threadcreate_time}));
      };
      ws.onmessage = (evt) => {
        const data = JSON.parse(evt.data);
        document.querySelector("#pageloader").style.display = "none";
        if (data.length > 0 && data[0].error && document.location.pathname === '/CLI' && data[0].tabname === "syswatch") {
          notificationRef.setAttribute('text', data.error);
          notificationRef.open();
          return;
        }
        if (data.length > 0 && data[0].tabname === "syswatch" && data[0].data.length > 0) {
           if(data[0].data[0].value.length > 0 && Array.isArray(data[0].data[0].value.slice(-1)[0]))
             data[0].data[0].value.pop();
           self.rawItems = _.compact(data[0].data[0].value);
           let eve = "";
          _updatepaginationtext(eve, self);
        }
        const datum = JSON.parse(evt.data);
          if (datum.length) {
            configObj[keyref] = datum[datum.length-1].time;
            ws.send(JSON.stringify({"tabname":tab_name,"time":datum[datum.length-1].time,"uid":session["uid"], "threadname":thread, "thread_createtime":threadcreate_time}));
          } else{
            if(configObj[keyref] !== "")
            ws.send(JSON.stringify({"tabname":tab_name,"uid":session["uid"], "time":configObj[keyref], "threadname":thread, "thread_createtime":threadcreate_time}));
            else
            ws.send(JSON.stringify({"tabname":tab_name,"uid":session["uid"], "threadname":thread, "thread_createtime":threadcreate_time}));
          }
      };
    } else {
      document.querySelector("#pageloader").style.display = "none";
      notificationRef.setAttribute('text', "WebSocket NOT supported by your Browser!");
      notificationRef.open();
    }
  }

  ready() {
    super.ready();
    let self = this;
    document.querySelector("#pageloader").style.display = "none";
    const session = JSON.parse(localStorage.getItem('storedUser'));
    self.headers.uid = session.uid;
    self.$.stopwatch.headers = self.headers;
    self.$.memorywatchAjax.headers['uid'] = session.uid;
    const uploadmw = this.$.uploadmw;
    uploadmw.addEventListener('upload-response', (req) => {
      const threadresp = JSON.parse(req.detail.xhr.response);
      if(threadresp.hasOwnProperty('error')){
        notificationRef.setAttribute('text', threadresp.error);
        notificationRef.open();
      }else{
        const thread = threadresp.response[0].threadname;
        self.wbsocketCheck(self, thread);
      }
    });
    const pagingTable = this.shadowRoot.querySelector('exmg-paper-paging').shadowRoot.querySelector('paper-dropdown-menu');
    pagingTable.addEventListener('iron-select', e => { handlePaging(e, this) });
    const paginationbtns = this.shadowRoot.querySelector('exmg-paper-paging').shadowRoot.querySelector('.page-actions').querySelectorAll('paper-icon-button');
    _.each(paginationbtns, (ele, ind) => {
      ele.addEventListener('click', e => {
        _updatepaginationtext(e, self);
      });
    });
  }
}
window.customElements.define('memory-watch', memoryData);
