{% extends "nopaque.html.j2" %}

{% set full_width = True %}

{% block page_content %}
<!-- Query Form -->
<form id="query-form">
  <div class="col s12">
    <ul class="collapsible expandable">
      <li class="active">
        <!-- <div class="collapsible-header">
          <i class="material-icons">search</i>CQP Query
        </div> -->
        <!-- Div element above is part of valid materialize collapsible.
        Commented out to prevent the user from collapsing it and also to save
        space -->
        <div class="collapsible-body" style="padding-top: 10px;
                                             padding-right: 2rem;
                                             padding-bottom: 0px;
                                             padding-left: 2rem;">
          <div class="row">
            <div class="col s12 m11">
              <div class="input-field">
                <i class="material-icons prefix">search</i>
                {{ query_form.query() }}
                {{ query_form.query.label }}
                <span class="helper-text" data-error="wrong" data-success="right">
                  <a href="http://cwb.sourceforge.net/files/CQP_Tutorial/">
                    <i class="material-icons" style="font-size: inherit;">help
                    </i> CQP query language tutorial
                  </a>
                </span>
                {% for error in query_form.query.errors %}
                  <span class="helper-text red-text">{{ error }}</span>
                {% endfor %}
              </div>
            </div>
            <div class="col s12 m1">
              <p class="hide-on-small-only" style="
      margin: 0px;">&nbsp;</p>
              <button class="waves-effect waves-light btn-small right"
                      type="submit">Send
                <i class="material-icons right">send</i>
              </button>
            </div>
          </div>
        </div>
      </li>
      <li class="hoverable">
        <div class="collapsible-header">
          <i class="material-icons">settings</i>Display Options
        </div>
        <div class="collapsible-body">
          <div class="row">
            <div class="col s6">
              <div class="input-field" id="hits-per-page">
                <i class="material-icons prefix">format_list_numbered</i>
                {{ query_form.hits_per_page() }}
                {{ query_form.hits_per_page.label }}
                {% for error in query_form.hits_per_page.errors %}
                <span class="helper-text red-text">{{ error }}</span>
                {% endfor %}
              </div>
            </div>
            <div class="col s6">
              <div class="input-field" id ="context-per-item">
                <i class="material-icons prefix">short_text</i>
                {{ query_form.context() }}
                {{ query_form.context.label }}
                {% for error in query_form.context.errors %}
                <span class="helper-text red-text">{{ error }}</span>
                {% endfor %}
              </div>
            </div>
          </div>
          <div class="row">
            <div class="switch">
              <label>
                Expert Mode
                <input type="checkbox" id="expert-mode-switch">
                <span class="lever"></span>
              </label>
            </div>
          </div>
        </div>
      </li>
    </ul>
  </div>
</form>

<!-- Export query results modal -->
<div id="export-query-results-modal"
     class="modal modal-fixed-footer no-autoinit">
  <div class="modal-content">
    {{ query_download_form.hidden_tag() }}
    <h4>Download current query Results</h4>
    <p>The results of the current query can be downlaoded as several files like csv or json. Those files can be used in other software like excel. Also it is easy to publish your results as raw data like this!</p>
    <table>
      <tr>
        <td>JSON</td>
        <td>
          <a class="btn waves-effect waves-light" id="download-results-json">Download
            <i class="material-icons right">file_download</i>
          </a>
        </td>
      </tr>
      <tr>
        <td>CSV</td>
        <td>
          <a class="btn waves-effect waves-light" id="download-results-csv">Download
            <i class="material-icons right">file_download</i>
          </a>
        </td>
      </tr>
      <tr>
        <td>EXCEL</td>
        <td>
          <a class="btn waves-effect waves-light disabled">Download
            <i class="material-icons right">file_download</i>
          </a>
        </td>
      </tr>
      <tr>
        <td>HTML</td>
        <td>
          <a class="btn waves-effect waves-light disabled">Download
            <i class="material-icons right">file_download</i>
          </a>
        </td>
      </tr>
    </table>
  </div>
  <div class="modal-footer">
    <a href="#!" class="modal-close waves-effect waves-light red btn">Close</a>
  </div>
</div>

<!-- Loading animation card when query results are being loaded -->
<div class="row">
  <div class="col s12 hide" id="getting-query-results">
    <div class="card">
      <div class="card-content">
        <span class="card-title">Fetching your results!</span>
        <div>
          <div class="progress">
            <div class="indeterminate"></div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

<!-- table showing the query results -->
<div class="col s12" id="recieved-query-results">
  <div class="card">
    <div class="card-content" id="result-list">
      <span class="card-title">Query Results</span>
      <p id="query-results-metadata">
        <button id="export-query-results" class="waves-effect waves-light btn-small right hide" type="submit">Export Results<i class="material-icons right">file_download</i></button>
      </p>
      <ul class="pagination paginationTop"></ul>
      <table class="responsive-table highlight">
        <thead>
          <tr>
            <th style="width: 2%">Nr.</th>
            <th style="width: 3%">Title</th>
            <th style="width: 25%">Left context</th>
            <th style="width: 45%">Match</th>
            <th style="width: 25%">Right Context</th>
          </tr>
        </thead>
        <tbody class="list" id="query-results">
        </tbody>
      </table>
      <ul class="pagination paginationBottom"></ul>
    </div>
  </div>
</div>

<!-- Loding animation modal that waits for the CQP server container to be ready
-->
<div id="loading-modal" class="modal no-autoinit">
  <div class="modal-content">
    <h4>Waiting for analysis software</h4>
    <div class="progress">
      <div class="indeterminate"></div>
    </div>
  </div>
</div>

<!-- Context modal used for detailed information about one match -->
<div id="context-modal" class="modal modal-fixed-footer">
  <div class="modal-content">
    <h4>Match context and information</h4>
    <div id="context-modal-loading">
      <div class="progress">
        <div class="indeterminate"></div>
      </div>
    </div>
    <div id="context-modal-ready" class="hide">
      <div id="context-results"></div>
    </div>
  </div>
  <div class="modal-footer">
    <a href="#!" class="left waves-effect waves-light btn">Export</a>
    <a href="#!" class="modal-close waves-effect waves-light red btn">Close</a>
  </div>
</div>

<script>
 // Initialising some modals for later usage
  var contextModal;
  var loadingModal;
  var exportModal;
  document.addEventListener("DOMContentLoaded", function() {
    contextModal = M.Modal.init(document.getElementById("context-modal"),
                                {"onCloseEnd": function() {
                                   document.getElementById("context-modal-loading").classList.remove("hide");
                                   document.getElementById("context-modal-ready").classList.add("hide");}});
    loadingModal = M.Modal.init(document.getElementById("loading-modal"),
                                {"dismissible": false});
    exportModal = M.Modal.init(document.getElementById("export-query-results-modal"),
                                {"dismissible": true});
    M.Collapsible.init(elem, {accordion: false});
    loadingModal.open();
    nopaque.socket.emit("corpus_analysis_init", {{ corpus_id }});
  });

  // close loading modal if container for analysis has started
  nopaque.socket.on("corpus_analysis_init", function(response) {
    if (response.code === 201) {
      loadingModal.close();
    } else {
      console.log("[ERROR] corpus_analysis_init");
      console.log(response);
    }
  });

  // getting some HTML-elements to use/hide/remove/show or add some other elements to them
  var queryResultsElement = document.getElementById("query-results");
  var queryResultsMetadataElement = document.getElementById("query-results-metadata");
  var exportQueryResults = document.getElementById("export-query-results");
  exportQueryResults.onclick = function() {
    exportModal.open();
  };
  var contextResultsElement = document.getElementById("context-results");
  var queryLoadingElement = document.getElementById("getting-query-results");
  var queryResultsTableElement = document.getElementById("recieved-query-results");
  ;
  // create some global variables
  var hitsPerPage;
  var result;
  var resultList;

  //function to get queryData
  function getQueryData(queryFormElement) {
    // Get query form element and save its data on submit and send this data via
    formData = new FormData(queryFormElement);
    queryData = {"context": formData.get("context"), // global declaration
                 "hits_per_page": formData.get("hits_per_page"),
                 "query": formData.get("query")};
    return queryData
  }

  // socket.io analysis submit to the CQP server
  let queryFormElement = document.getElementById("query-form");
  queryFormElement.addEventListener("submit", sendQuery);

  function sendQuery(event) {
    event.preventDefault();
    queryData = getQueryData(queryFormElement);
    nopaque.socket.emit("corpus_analysis", queryData);
    // full results object declaration, kind of global maybe store it later?
    // will always be reset if a query is sent, so that only the chunks of the
    // current query will be saved in it
    result = {};
    result["matches"] = [];
    result["cpos_lookup"] = {};
    result["text_lookup"] = {};
    result["loaded_match_count"] = 0;
    result["match_count"] = 0;
    result["query"] = "";
    // some hiding/showing for loading animation
    queryLoadingElement.classList.remove("hide");
    queryResultsTableElement.classList.add("hide");
    nopaque.toast("Query has been sent!");

    resultListOptions = {page: queryData["hits_per_page"],
      pagination: [{
        name: "paginationTop",
        paginationClass: "paginationTop",
        innerWindow: 8,
        outerWindow: 1
      }, {
        paginationClass: "paginationBottom",
        innerWindow: 8,
        outerWindow: 1
      }],
      valueNames: ["titles", "lc", "hit", "rc", {data: ["index"]}],
      item: `<span class="hidden"></span>`};
      resultList = new ResultList('result-list', resultListOptions);
      resultList.clear(); // empty list for new query
  }

  // live update of hits per page
  var hitsPerPageInputElement = document.getElementById("hits-per-page");
  hitsPerPageInputElement.addEventListener("change", changeResultList);

  function changeResultList(event) {
    let queryFormElement = document.getElementById("query-form");
    queryData = getQueryData(queryFormElement);
    try {
      resultList.page = queryData["hits_per_page"];
      resultList.update();
      nopaque.toast("Updated matches per page.")
    } catch (e) {
      console.log("resultList has no results right now. Live update of items per page is useless for now.");
    }
  }

  // live update of lr context per item
  var contextPerItemElement = document.getElementById("context-per-item");
  contextPerItemElement.addEventListener("change", changeContext);

  function changeContext(event) {
    let queryFormElement = document.getElementById("query-form");
    queryData = getQueryData(queryFormElement);
    console.log(queryData);
    try {
      nopaque.toast("Loading more context.");
      sendQuery(event);
    } catch (e) {
      console.log("No query given.");
    }
  }

  // socket.on triggered when result chunks are recieved
  nopaque.socket.on("corpus_analysis_query", function(response) {
    // ERROR code checking
    if (response["code"] === 0) {
      console.log("[SUCCESS] corpus_analysis_init");
      console.log("Code:" + response["code"]);
      // further code execution of this code block starting in line 342
    } else if (response["code"] === 1) {
      queryResultsTableElement.classList.add("hide");
      queryLoadingElement.classList.add("hide");
      nopaque.toast("Invalid query entered!", "red");
      console.log("[ERROR] corpus_analysis_init");
      console.log("Code:" + response["code"]);
      return; // no further code execution of this code block
    } else {
      console.log("[ERROR] corpus_analysis_init");
      console.log("Code:" + response["code"]);
      return; // no further code execution of this code block
    }
    // logs the current recieved chunk
    chunk = {};
    chunk = response["result"];
    console.log("### corpus_analysis chunk ###");
    console.log(chunk);
    // logs and extends/push/update the current recieved chunk to the
    // result Object
    console.log("### corpus analysis updated result json ###");
    result["matches"].push(...chunk["matches"]);
    Object.assign(result["cpos_lookup"], chunk["cpos_lookup"]);
    Object.assign(result["text_lookup"], chunk["text_lookup"]);
    result["match_count"] = chunk["match_count"];
    console.log("Before Current match count", result["loaded_match_count"]);
    result["query"] = queryData["query"];
    console.log(result);
    // Some hiding and showing of loading animations
    queryLoadingElement.classList.add("hide");
    queryResultsTableElement.classList.remove("hide");
    queryResultsElement.innerHTML = "";

    // check if query has any results
    if (chunk["matches"].length === 0) {
      queryResultsTableElement.classList.add("hide");
      nopaque.toast("No results for this query!");
      return;
    }

    // List building/appending the chunks when query had results
    match_count = chunk["match_count"];
    let count_corpus_files = Object.keys(result["text_lookup"]).length;

    var resultItems = []; // list for holding every row item
    // get infos for full match row
    for (let [index, match] of chunk["matches"].entries()) {
      resultItems.push({...match, ...{"index": index + result["loaded_match_count"]}});
    }
    resultList.add(resultItems, items => {
      for (let item of items) {
        item.elm = resultList.createResultRowElement(item, chunk);}
      resultList.update();
    });
    result["loaded_match_count"] += Object.keys(chunk["matches"]).length;
    console.log("After current match count", result["loaded_match_count"]);
    queryResultsMetadataElement.innerHTML = `<p>The query resulted in a total of ${chunk["match_count"]} matches. </p> <p> ${result["loaded_match_count"]} of ${result["match_count"]} matches in ${count_corpus_files} corpus files have been loaded.</p>`;
    queryResultsMetadataElement.appendChild(exportQueryResults);
    exportQueryResults.classList.remove("hide");
    });

    // inspect match functions
    function inspect(dataIndex) {
      console.log("Inspect!");
      console.log(result["matches"][dataIndex]["hit"]);
      contextModal.open();
      nopaque.socket.emit("inspect_match", {"cpos": result["matches"][dataIndex]["hit"]});
    }

    function downloadRessource(downloadElement, mimeTypeString, filenameSlug) {
      // get and create metadata
      console.log("Create Metadata!");
      var today = new Date();
      var currentDate = today.getUTCFullYear() + '-' + (today.getUTCMonth() +1) + '-' + today.getUTCDate();
      var currentTime = today.getUTCHours() + ":" + today.getUTCMinutes() + ":" + today.getUTCSeconds();
      var safeFilename = result['query'].replace(/[^a-z0-9_-]/gi, "_");
      var resultFilename = "UTC-" + currentDate + "_" + currentTime + "_" + safeFilename;
      // stringify JSON object for json download
      var dataStr = JSON.stringify(result, undefined, 2);
      // get downloadResultsElement
      downloadElement = document.getElementById("download-results-json");
      // start actual download
      download(downloadElement, dataStr, resultFilename, mimeTypeString, filenameSlug)
    }
    // add onclick to download buttons
    var downloadResultsJSONElement = document.getElementById("download-results-json");
    downloadResultsJSONElement.onclick = function() {downloadRessource(downloadResultsJSONElement, "text/json", ".json")};
    var downloadResultsCSVElement = document.getElementById("download-results-csv");
    downloadResultsCSVElement.onclick = function() {downloadRessource(downloadResultsCSVElement, "text/plain", ".txt")};

    // Function to download data to a file
    function download(downloadElem, data, filename, type, filenameSlug) {
      console.log("Start Download!");
      filename += filenameSlug;
      var file = new Blob([data], {type: type});
      if (window.navigator.msSaveOrOpenBlob) // IE10+
          window.navigator.msSaveOrOpenBlob(file, filename);
      else { // Others
          var url = URL.createObjectURL(file);
          downloadElem.href = url;
          downloadElem.download = filename;
        }
    }

  // epxert mode table view
  var expertModeSwitchElement = document.getElementById("expert-mode-switch");
  expertModeSwitchElement.addEventListener("change", function(event) {
    var currentTokenElements = document.getElementsByClassName("token");
    var paginationElements = document.getElementsByClassName("pagination");
    if (event.target.checked) {
      console.log("Checked!");
      expertModeOn(currentTokenElements, result);
      for (element of paginationElements) {
        element.addEventListener("click", eventHandlerCheck);
        element.tokenElements = currentTokenElements;
      }
    } else {
      console.log("Unchecked!");
      expertModeOff(currentTokenElements);
      console.log("unchecked! Destroy");
    }
  })

  function eventHandlerCheck(event) {
    console.log("pagination used!");
    console.log(expertModeSwitchElement.checked);
    if (expertModeSwitchElement.checked) {
      expertModeOn(event.currentTarget.tokenElements, result);
    } else if (!expertModeSwitchElement.checked) {
      event.preventDefault();
      console.log("prevented! Destroy");
      expertModeOff(event.currentTarget.tokenElements);
    }
  }

  function expertModeOff(tokenElements) {
    console.log("expertModeOff!");
    for (tokenElement of tokenElements) {
      tokenElement.classList.remove("chip");
      tokenElement.classList.remove("hoverable");
      tokenElement.classList.remove("expert-view");
      tokenElement.outerHTML = tokenElement.outerHTML; // TODO fix this in a proper way
      // console.log("Token", tokenElement);
      // console.log("Tooltip property:", tokenElement.M_Tooltip);
      // tokenElement.M_Tooltip.destroy();
      // console.log("Destroy!");
    }
  }

  function expertModeOn(tokenElements, result_lookup) {
    console.log("expertModeOn!");
    for (tokenElement of tokenElements) {
      tokenElement.classList.add("chip");
      tokenElement.classList.add("hoverable");
      tokenElement.classList.add("expert-view");
      token = result_lookup["cpos_lookup"][tokenElement.dataset.cpos];
      tokenElement.addEventListener("mouseover", function(event) {
        console.log("Mouseover!");
        console.log(event.target);
        token = result_lookup["cpos_lookup"][event.target.dataset.cpos];
        addToolTipToTokenElement(event.target, token);
      })
    }
  }

  function addToolTipToTokenElement(tokenElement, token) {
    M.Tooltip.init(tokenElement,
                   {"html": `<table>
                               <tr>
                                 <th>Token information</th>
                                 <th>Source information</th>
                               </tr>
                               <tr>
                                 <td class="left-align">
                                   Word: ${token["word"]}<br>
                                   Lemma: ${token["lemma"]}<br>
                                   POS: ${token["pos"]}<br>
                                   Simple POS: ${token["simple_pos"]}<br>
                                   NER: ${token["ner"]}
                                 </td>
                                 <td class="left-align">
                                   Title: ${result["text_lookup"][token["text"]]["title"]}<br>
                                   Author: ${result["text_lookup"][token["text"]]["author"]}<br>
                                   Publishing year: ${result["text_lookup"][token["text"]]["publishing_year"]}
                                 </td>
                               </tr>
                             </table>`,
                   "inDuration": 1500,
                   "margin": 15,
                   "position": "top",
                   "transitionMovement": 0});
  }
  // collapsible display options
  var elem = document.querySelector('.collapsible.expandable');
</script>
{% endblock %}
