/*
* 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 "../../../../node_modules/@polymer/polymer/polymer-element.js";
import { api_url, notificationRef, socket_url, configObj } from '../../../shared/constants.js';
import "../../../../node_modules/@vaadin/vaadin-accordion/vaadin-accordion.js";
import "../../../../node_modules/@polymer/paper-checkbox/paper-checkbox.js";
import "../../../../node_modules/@polymer/paper-dialog/paper-dialog.js";
import "./overlay_graph.js";
import "../../../shared-styles.js";
import { GetFormattedDate, redirectToLogin, handleErrorResponse } from '../../../shared/shared-script.js';

class overlayPerformance extends PolymerElement {
  static get template() {
    return html`
      <style include="shared-styles">
        :host {
          display: block;
        }
        .sendBtn,
        .closeBtn,
        .logsBtn {
          padding: 4px 8px;
          background-color: #1E88E5;
          color: #fff;
          height: 30px;
          font-size: 14px;
          font-weight: bold;
          text-align: center;
          float: right;
          margin-top: 1.2em;
        }
        paper-dropdown-menu {
          --paper-dropdown-menu: {
            width : 100px;
          }
        }
        .configcol:nth-child(odd) {
          margin-right: 15px;
        }
        .card {
          margin: 10px 0;
        }
        .d-flex {
          display: flex;
          flex-wrap: wrap;
        }
        .configcol {
          width: calc(50% - 40px);
        }
        .hide {
          display: none;
        }
        .dropmenu::after{
          content: '';
          display: block;
          clear: both;
        }
      </style>
        <div>
          <div class="dropmenu">
            <paper-dropdown-menu always-float-label label="Number of Plot" on-iron-select="_selectedPlot" id="selectedModule">
              <paper-listbox slot="dropdown-content" class="dropdown-content" selected="0">
                <template is="dom-repeat" items={{plotLists}}>
                  <paper-item>[[item]]</paper-item>
                </template>
              </paper-listbox>
            </paper-dropdown-menu>
            <iron-icon icon="info-outline" id="loadInstructions" slot="item-icon" style="color:#ee3626;"></iron-icon>
            <paper-button raised noink id="generateoverlayplot" class="sendBtn" on-tap="_configPlot">Generate</paper-button>
            <paper-button raised noink id="closebtn" class="closeBtn" on-tap="_closePlot">Close</paper-button>
            <!-- <a href={{downloadurl}} target="_blank"><paper-button raised title="Download Log File" noink id="downloadlogs" class="logsBtn">Download</paper-button></a> -->
          </div>
          <div class="d-flex" id="userplotconfig">
            <template is="dom-repeat" items={{plotItems}} as="item">
              <div class="card configcol" data-items$={{item}} data-index$={{index}}>
                <div class="configbox">
                  <vaadin-accordion>
                    <template is="dom-repeat" items={{item.legends}} as="module">
                      <vaadin-accordion-panel data-key$={{module.key}} theme="filled reverse">
                        <div slot="summary">{{module.name}}</div>
                        <template is="dom-repeat" items={{module.options}} as="option">
                          <paper-checkbox value={{option}}>{{option}}</paper-checkbox>
                        </template>
                      </vaadin-accordion-panel>
                    </template>
                  </vaadin-accordion>
                </div>
                <div class="graph_sec hide">
                  <overlay-graph id="{{_creatingRef(index)}}" key="{{_creatingRef(index)}}"></overlay-graph>
                </div>
              </div>
            </template>
           </div>
            <paper-dialog id="instructionmodal">
              <div class="m-0 p-0 h-100">
                <div class="instructionBoard">
                  <ul>
                    <li>Select number of overlay plot</li>
                    <li>Choose the legends in which you want to watch the graph</li>
                    <li>Click on close button to stop watching</li>
                  </ul>
                </div>
              </div>
            </paper-dialog>
          </div>
          <iron-ajax id="configplot" method="post" url="[[url]]" body={{configData}} handle-as="json" content-type="application/json" last-response="{{handleResponse}}" on-error="_handleErrorResponse"></iron-ajax>
          <iron-ajax id="closeplot" method="post" url="[[closeurl]]" body={{closeData}} handle-as="json" content-type="application/json" last-response="{{handleResponse}}" on-error="_handleErrorResponse"></iron-ajax>
      `;
  }

  static get properties() {
    return {
      url: {
        type: String,
        value: `${api_url}overlayconfiguration/`
      },
      closeurl: {
        type: String,
        value: `${api_url}closeplot/`
      },
      plotLists: {
        type: Array,
        value: [0, 1, 2, 3, 4, 5, 6, 7, 8]
      },
      plotItems: {
        type: Array,
        value: []
      },
      configData: {
        type: Array,
        value: []
      },
      closeData: {
        type: Array,
        value: []
      },
      refObjects: {
        type: Array,
        value: []
      },
      downloadurl: {
        type: String,
        value: ''
      },
      currentUser: {
        type: String,
        value: 'overlay'
      },
      threadarray: {
        type: Array,
        value: []
      },
      modules: {
        type: Array,
        value: [{
          "name": "PMC",
          "key": "pmc",
          "options": ["PMC_NOC_AXI"]
        }, {
          "name": "LPD",
          "key": "lpd",
          "options": ["LPD_PMC_RPU", "LPD_AFIFS", "LPD_OCM", "LPD_to_FPD", "LPD_XPPU"]
        }, {
          "name": "FPD",
          "key": "fpd",
          "options": ["FPD_SLAVES", "FPD_to_OCM", "FPD_to_LPD", "FPD_PCIe", "FPD_AFI_FS", "FPD_NCI0", "FPD_NCI1"]
        }, {
          "name": "CPM",
          "key": "cpm",
          "options": ["CPM_AXI0", "CPM_AXI1", "CPM_PCIe"]
        }, {
          "name": "DDRMC0",
          "key": "mrd_noc_0",
          "options": ["DDRMC_NOC_0_nsu0_perf_mon_0", "DDRMC_NOC_0_nsu0_perf_mon_1", "DDRMC_NOC_0_nsu1_perf_mon_0", "DDRMC_NOC_0_nsu1_perf_mon_1", "DDRMC_NOC_0_nsu2_perf_mon_0", "DDRMC_NOC_0_nsu2_perf_mon_1", "DDRMC_NOC_0_nsu3_perf_mon_0", "DDRMC_NOC_0_nsu3_perf_mon_1"]
        }, {
          "name": "DDRMC1",
          "key": "mrd_noc_1",
          "options": ["DDRMC_NOC_1_nsu0_perf_mon_0", "DDRMC_NOC_1_nsu0_perf_mon_1", "DDRMC_NOC_1_nsu1_perf_mon_0", "DDRMC_NOC_1_nsu1_perf_mon_1", "DDRMC_NOC_1_nsu2_perf_mon_0", "DDRMC_NOC_1_nsu2_perf_mon_1", "DDRMC_NOC_1_nsu3_perf_mon_0", "DDRMC_NOC_1_nsu3_perf_mon_1"]
        }, {
          "name": "DDRMC2",
          "key": "mrd_noc_2",
          "options": ["DDRMC_NOC_2_nsu0_perf_mon_0", "DDRMC_NOC_2_nsu0_perf_mon_1", "DDRMC_NOC_2_nsu1_perf_mon_0", "DDRMC_NOC_2_nsu1_perf_mon_1", "DDRMC_NOC_2_nsu2_perf_mon_0", "DDRMC_NOC_2_nsu2_perf_mon_1", "DDRMC_NOC_2_nsu3_perf_mon_0", "DDRMC_NOC_2_nsu3_perf_mon_1"]
        }, {
          "name": "DDRMC3",
          "key": "mrd_noc_3",
          "options": ["DDRMC_NOC_3_nsu0_perf_mon_0", "DDRMC_NOC_3_nsu0_perf_mon_1", "DDRMC_NOC_3_nsu1_perf_mon_0", "DDRMC_NOC_3_nsu1_perf_mon_1", "DDRMC_NOC_3_nsu2_perf_mon_0", "DDRMC_NOC_3_nsu2_perf_mon_1", "DDRMC_NOC_3_nsu3_perf_mon_0", "DDRMC_NOC_3_nsu3_perf_mon_1"]
        }, {
          "name": "NoC",
          "key": "noc",
          "options": ["nmu_Monitor-0", "nmu_Monitor-1", "nsu_Monitor-0", "nsu_Monitor-1", "nps_0", "nps_1"]
        }, {
          "name": "AI Engine",
          "key": "ai_engine",
          "options": ["performance0", "performance1", "performance2", "performance3"]
        }, {
          "name": "PL",
          "key": "pl",
          "options": ["slot_0", "slot_1", "slot_2", "slot_3", "slot_4"]
        }, {
          "name": "DC",
          "key": "dc",
          "options": ["DC_0", "DC_1"]
        }]
      }
    };
  }

  _creatingRef(i) {
    return 'overlay_' + i + '_' + this.currentUser;
  }

  _selectedPlot(e) {
    const selected = e.target.selectedItem.innerText.trim();
    this.$.closebtn.style.display = "none";
    if (parseInt(selected)) this.$.generateoverlayplot.style.display = "block";else this.$.generateoverlayplot.style.display = "none";
    this.plotItems = [];

    for (let i = 0; i < parseInt(selected); i++) this.plotItems.push({
      'threadname': 'overlay_' + i + '_' + this.currentUser,
      'tab': 'overlay',
      'uid': this.currentUser,
      'legends': [...this.modules],
      'key': 'overlay'
    });
  }

  _closePlot() {
    let self = this;

    const bodyData = _.map(self.plotItems, ele => _.pick(ele, 'threadname'));

    self.closeData = bodyData;
    const card = self.$.userplotconfig.querySelectorAll('.configcol');
    document.querySelector("#pageloader").style.display = "block";
    self.$.closeplot.headers['uid'] = self.currentUser;
    let request = self.$.closeplot.generateRequest();
    request.completes.then(req => {
      const result = req.response;
      document.querySelector("#pageloader").style.display = "none";

      if (result.status === 'Fail') {
        notificationRef.setAttribute('text', "Please connect to board and try again");
        notificationRef.open();
        document.location.reload();
        return;
      }

      if (result.error) {
        notificationRef.setAttribute('text', result.error);
        notificationRef.open();
        return;
      }

      self.closePlot = false;
      self.plotItems = [];
      self.$.selectedModule.querySelector("paper-listbox").selected = 0;
      self.$.generateoverlayplot.style.display = "block";
      self.$.closebtn.style.display = "none";
      self.$.selectedModule.style.display = "inline-block";
      self.$.loadInstructions.style.display = "inline-block";

      _.each(card, element => {
        element.querySelector('.graph_sec').classList.add('hide');
        element.querySelector('.configbox').classList.remove('hide');
      });
    }, () => {
      if (request.status == 400) redirectToLogin();
    });
  }

  _configPlot() {
    let data = {};
    let self = this;
    let flag = 0;

    if (MyAppGlobals.boardstatus) {
      const cards = self.$.userplotconfig.querySelectorAll('.configcol');
      self.configData = [];
      cards.forEach((ele, i) => {
        const refkey = 'overlay_' + i + '_' + this.currentUser;
        configObj[refkey] = {};
        configObj[refkey]['legend'] = [];
        data = JSON.parse(ele.dataset.items);
        data['performance'] = [];
        const vaadinpanel = ele.querySelectorAll('vaadin-accordion-panel');
        let perfData = {};

        _.each(vaadinpanel, item => {
          perfData = {};
          const checkEle = item.querySelectorAll('paper-checkbox[checked]');

          if (checkEle.length > 0) {
            perfData['subtab'] = item.dataset.key;
            let checkVal = [];

            _.each(checkEle, val => {
              checkVal.push(val.value);
              configObj[refkey]['legend'].push(val.value);
            });

            perfData['plot'] = [...checkVal];
            data.performance.push(perfData);
          }
        });

        if (data.performance.length === 0) flag = 1;

        const pData = _.omit(data, 'legends');

        self.configData.push(pData);
      });

      if (flag) {
        notificationRef.setAttribute('text', "Please select atleast one from each plot");
        notificationRef.open();
        return;
      }

      document.querySelector("#pageloader").style.display = "block";
      self.$.configplot.headers['uid'] = self.currentUser;
      let request = self.$.configplot.generateRequest();
      request.completes.then(req => {
        const result = req.response;

        if (result.status === 'Fail') {
          document.querySelector("#pageloader").style.display = "none";
          notificationRef.setAttribute('text', "Please connect to board and try again");
          notificationRef.open();
          document.location.reload();
          return;
        }

        if (result.error) {
          document.querySelector("#pageloader").style.display = "none";
          notificationRef.setAttribute('text', result.error);
          notificationRef.open();
          return;
        }

        self._loadwsdata(result.response); //document.querySelector("#pageloader").style.display = "none";

      }, () => {
        if (request.status == 400) redirectToLogin();
      });
    } else {
      document.querySelector("#pageloader").style.display = "none";
      notificationRef.setAttribute('text', "Please Connect to board and try again");
      notificationRef.open();
      document.location.reload();
    }
  }

  async _loadwsdata(res) {
    let self = this;
    const keyref = 'overlayref';
    const tab_name = 'overlay';
    configObj[keyref] = '';
    self.$.generateoverlayplot.style.display = "none";
    self.$.closebtn.style.display = "block";
    self.$.selectedModule.style.display = "none";
    self.$.loadInstructions.style.display = "none";

    const threadname = _.pluck(res, 'threadname');

    const thread_createtime = _.pluck(res, 'thread_createtime');

    let threadsarr = [];

    _.each(threadname, (ele, ind) => {
      let threadObj = {};
      threadObj["threadname"] = ele;
      threadObj["thread_createtime"] = thread_createtime[ind];
      threadsarr.push(threadObj);
    });

    self.threadarray = threadsarr;
    await self._updateObjects();

    if ("WebSocket" in window) {
      let ws = new WebSocket(`ws://${socket_url}/ws`);
      const session = JSON.parse(localStorage.getItem('storedUser'));
      self.closePlot = true;

      ws.onopen = () => {
        ws.send(JSON.stringify({
          "tab": tab_name,
          "uid": session["uid"],
          "threads": threadsarr
        }));
      };

      ws.onmessage = evt => {
        self._websocketreceiver(ws, evt, session, tab_name, keyref, threadname, thread_createtime, threadsarr);
      };
    } else {
      notificationRef.setAttribute('text', "WebSocket NOT supported by your Browser!");
      notificationRef.open();
    } //document.querySelector("#pageloader").style.display = "none";

  }

  async _websocketreceiver(ws, evt, session, tab_name, keyref, threadname, thread_createtime) {
    let self = this;
    const datum = JSON.parse(evt.data);

    for (let i = 0; i < datum.length; i++) {
      const data = datum[i];

      if (data.tabname === `${tab_name}_${session.uid}`) {
        if (data.error && document.location.pathname === '/usertab') {
          notificationRef.setAttribute('text', data.error);
          notificationRef.open();
        } else notificationRef.close();

        if (data.data.length > 0) {
          await self._generateData(datum, i);
        } else {
          let threadObj = _.findWhere(self.threadarray, {
            threadname: 'overlay_' + i + '_' + this.currentUser
          });

          threadObj.time = data.time;
        }
      }
    }

    if (self.closePlot) {
      ws.send(JSON.stringify({
        "tab": tab_name,
        "uid": session["uid"],
        "threads": self.threadarray
      }));
    }
  }

  async _updateObjects() {
    let self = this;
    self.refObjects = [];
    const userBlocks = self.$.userplotconfig.querySelectorAll('.configcol');

    for (let i = 0; i < userBlocks.length; i++) {
      userBlocks[i].querySelector('.graph_sec').classList.toggle('hide');
      userBlocks[i].querySelector('.configbox').classList.toggle('hide');
      self.refObjects.push({
        "ref": userBlocks[i].querySelector('#overlay_' + i + '_' + this.currentUser),
        key: 'overlay_' + i + '_' + this.currentUser
      });
    }
  }

  async _generateData(jsondata, ind) {
    let self = this; // const userBlocks = self.$.userplotconfig.querySelectorAll('.configcol');
    // for (let i = 0; i < userBlocks.length; i++) {

    let refObj = _.findWhere(self.refObjects, {
      key: 'overlay_' + ind + '_' + this.currentUser
    });

    let refdata = _.findWhere(jsondata, {
      threadname: 'overlay_' + ind + '_' + this.currentUser
    });

    let reftime = _.findWhere(jsondata, {
      threadname: 'overlay_' + ind + '_' + this.currentUser
    });

    self.threadarray[ind]["time"] = reftime.time;
    if (refdata && refdata.data && refObj) await refObj.ref._updatedUserGraph(refdata.data, refObj.key); //}
  }

  _handleErrorResponse(req) {
    handleErrorResponse(req);
  }

  ready() {
    super.ready();
    let self = this;
    document.querySelector("#pageloader").style.display = "none";
    const session = JSON.parse(localStorage.getItem('storedUser'));
    const uid = session.uid;
    this.downloadurl = `${api_url}logfiles/${uid}/overlay.txt`;
    this.$.loadInstructions.addEventListener('mouseover', () => {
      self.$.instructionmodal.open();
    });
    this.$.loadInstructions.addEventListener('mouseleave', () => {
      self.$.instructionmodal.close();
    });
  }

  connectedCallback() {
    super.connectedCallback();
    const session = JSON.parse(localStorage.getItem('storedUser'));
    this.currentUser = session.uid;
  }

}

window.customElements.define('overlay-performance', overlayPerformance);