{%extends "base.html"%}
{%from "flash_messages.html" import flash_all_messages%}
{%from "upload_progress_indicator.html" import upload_progress_indicator%}

{%block title%}Upload R/qtl2 Bundle{%endblock%}

{%block contents%}
{%macro rqtl2_file_help()%}
<span class="form-text text-muted">
  <p>
    Provide a valid R/qtl2 zip file here. In particular, ensure your zip bundle
    contains exactly one control file and the corresponding files mentioned in
    the control file.
  </p>
  <p>
    The control file can be either a YAML or JSON file. <em>ALL</em> other data
    files in the zip bundle should be CSV files.
  </p>
  <p>See the
    <a href="https://kbroman.org/qtl2/assets/vignettes/input_files.html"
       target="_blank">
      R/qtl2 file format specifications
    </a>
    for more details.
  </p>
</span>
{%endmacro%}
{{upload_progress_indicator()}}

<div id="resumable-file-display-template"
     class="panel panel-info"
     style="display: none">
  <div class="panel-heading"></div>
  <div class="panel-body"></div>
</div>


<h2 class="heading">Upload R/qtl2 Bundle</h2>

<div id="resumable-drop-area"
     style="display:none;background:#eeeeee;min-height:12em;border-radius:0.5em;padding:1em;">
  <p>
    <a id="resumable-browse-button" href="#"
       class="btn btn-info">Browse</a>
  </p>
  <p class="form-text text-muted">
    You can drag and drop your file here, or click the browse button.
    Click on the file to remove it.
  </p>
  {{rqtl2_file_help()}}
  <div id="resumable-selected-files"
       style="display:flex;flex-direction:row;flex-wrap: wrap;justify-content:space-around;gap:10px 20px;"></div>
  <div id="resumable-class-buttons" style="text-align: right;">
    <button id="resumable-upload-button"
            class="btn btn-primary"
            style="display: none">start upload</button>
    <button id="resumable-cancel-upload-button"
            class="btn btn-danger"
            style="display: none">cancel upload</button>
  </div>
  <div id="resumable-progress-bar" class="progress" style="display: none">
    <div class="progress-bar"
         role="progress-bar"
         aria-valuenow="60"
         aria-valuemin="0"
         aria-valuemax="100"
         style="width: 0%;">
      Uploading: 60%
    </div>
  </div>
</div>

<form id="frm-upload-rqtl2-bundle"
      action="{{url_for('expression-data.rqtl2.upload_rqtl2_bundle',
	      species_id=species.SpeciesId,
	      population_id=population.InbredSetId)}}"
      method="POST"
      enctype="multipart/form-data"
      data-resumable-target="{{url_for(
                             'expression-data.rqtl2.upload_rqtl2_bundle_chunked_post',
                             species_id=species.SpeciesId,
                             population_id=population.InbredSetId)}}">
  <input type="hidden" name="species_id" value="{{species.SpeciesId}}" />
  <input type="hidden" name="population_id"
	 value="{{population.InbredSetId}}" />

  {{flash_all_messages()}}

  <div class="form-group">
    <legend class="heading">file upload</legend>
    <label for="file-rqtl2-bundle" class="form-label">R/qtl2 bundle</label>
    <input type="file" id="file-rqtl2-bundle" name="rqtl2_bundle_file"
	   accept="application/zip, .zip"
	   required="required"
           class="form-control" />
    {{rqtl2_file_help()}}
  </div>

  <button type="submit"
          class="btn btn-primary"
          data-toggle="modal"
          data-target="#upload-progress-indicator">upload R/qtl2 bundle</button>
</form>

{%endblock%}

{%block javascript%}
<script src="{{url_for('base.node_modules',
             filename='resumablejs/resumable.js')}}"></script>
<script type="text/javascript" src="/static/js/upload_progress.js"></script>
<script type="text/javascript">
  function readBinaryFile(file) {
      return new Promise((resolve, reject) => {
          var _reader = new FileReader();
          _reader.onload = (event) => {resolve(_reader.result);};
          _reader.readAsArrayBuffer(file);
      });
  }

  function computeFileChecksum(file) {
      return readBinaryFile(file)
          .then((content) => {
              return window.crypto.subtle.digest(
                  "SHA-256", new Uint8Array(content));
          }).then((digest) => {
              return Uint8ArrayToHex(new Uint8Array(digest))
          });
  }

  function Uint8ArrayToHex(arr) {
      var toHex = (val) => {
          _hex = val.toString(16);
          if(_hex.length < 2) {
              return "0" + val;
          }
          return _hex;
      };
      _hexstr = ""
      arr.forEach((val) => {_hexstr += toHex(val)});
      return _hexstr
  }

  var r = Resumable({
      target: $("#frm-upload-rqtl2-bundle").attr("data-resumable-target"),
      fileType: ["zip"],
      maxFiles: 1,
      forceChunkSize: true,
      generateUniqueIdentifier: (file, event) => {
          return computeFileChecksum(file).then((checksum) => {
              var _relativePath = (file.webkitRelativePath
                                   || file.relativePath
                                   || file.fileName
                                   || file.name);
              return checksum + "-" + _relativePath.replace(
                  /[^a-zA-Z0-9_-]/img, "");
          });
      }
  });

  if(r.support) {
      //Hide form and display drag&drop UI
      $("#frm-upload-rqtl2-bundle").css("display", "none");
      $("#resumable-drop-area").css("display", "block");

      // Define UI elements for browse and drag&drop
      r.assignDrop(document.getElementById("resumable-drop-area"));
      r.assignBrowse(document.getElementById("resumable-browse-button"));

      // Event handlers

      function display_files(files) {
          displayArea = $("#resumable-selected-files")
          displayArea.empty();
          files.forEach((file) => {
              var displayElement = $(
                  "#resumable-file-display-template").clone();
              displayElement.removeAttr("id");
              displayElement.css("display", "");
              displayElement.find(".panel-heading").text(file.fileName);
              list = $("<ul></ul>");
              list.append($("<li><strong>Name</strong>: "
                            + (file.name
                               || file.fileName
                               || file.relativePath
                               || file.webkitRelativePath)
                            + "</li>"));
              list.append($("<li><strong>Size</strong>: "
                            + (file.size / (1024*1024)).toFixed(2)
                            + " MB</li>"));
              list.append($("<li><strong>Unique Identifier</strong>: "
                            + file.uniqueIdentifier + "</li>"));
              list.append($("<li><strong>Mime</strong>: "
                            + file.file.type
                            + "</li>"));
              displayElement.find(".panel-body").append(list);
              displayElement.appendTo("#resumable-selected-files");
          });
      }

      r.on("filesAdded", function(files) {
          display_files(files);
          $("#resumable-upload-button").css("display", "");
          $("#resumable-upload-button").on("click", (event) => {
              r.upload();
          });
      });

      r.on("uploadStart", (event) => {
          $("#resumable-upload-button").css("display", "none");
          $("#resumable-cancel-upload-button").css("display", "");
          $("#resumable-cancel-upload-button").on("click", (event) => {
              r.files.forEach((file) => {
                  if(file.isUploading()) {
                      file.abort();
                  }
              });
              $("#resumable-cancel-upload-button").css("display", "none");
              $("#resumable-upload-button").on("click", (event) => {
                  r.files.forEach((file) => {file.retry();});
              });
              $("#resumable-upload-button").css("display", "");
          });
      });

      r.on("progress", () => {
          var progress = (r.progress() * 100).toFixed(2);
          var pbar = $("#resumable-progress-bar > .progress-bar");
          $("#resumable-progress-bar").css("display", "");
          pbar.css("width", progress+"%");
          pbar.attr("aria-valuenow", progress);
          pbar.text("Uploading: " + progress + "%");
      })

      r.on("fileSuccess", (file, message) => {
          if(message != "OK") {
              var uri = (window.location.protocol
                         + "//"
                         + window.location.host
                         + message);
              window.location.replace(uri);
          }
      });

      r.on("error", (message, file) => {
          filename = (file.webkitRelativePath
                      || file.relativePath
                      || file.fileName
                      || file.name);
          jsonmsg = JSON.parse(message);
          alert("There was an error while uploading your file '"
                + filename
                + "'. The error message was:\n\n\t"
                + jsonmsg.error
                + " ("
                + jsonmsg.statuscode
                + "): " + jsonmsg.message);
      })
  } else {
      setup_upload_handlers(
          "frm-upload-rqtl2-bundle", make_data_uploader(
	      function (form) {
	          var formdata = new FormData();
	          formdata.append(
		      "species_id",
		      form.querySelector('input[name="species_id"]').value);
	          formdata.append(
		      "population_id",
		      form.querySelector('input[name="population_id"]').value);
	          formdata.append(
		      "rqtl2_bundle_file",
		      form.querySelector("#file-rqtl2-bundle").files[0]);
	          return formdata;
	      }));
  }
</script>
{%endblock%}