{% extends "base.html" %}

{% block js_media %}
  <script type="text/javascript">
    window.valid_files = {{valid_files_json}};
    window.big_input = (window.valid_files.length > 100);
  </script>
  <script type="text/javascript" src="{{ static('jquery-ui.min.js') }}"></script>
  <script type="text/javascript" src="{{ static('libs/featherlight/featherlight.min.js') }}"></script>
  <script type="text/javascript" src="{{ static('fine-uploader/jquery.fine-uploader.js') }}"></script>
  <script type="text/javascript">
    $(function () {
      $("#problem-data-zipfile_fine_uploader").fineUploader({
        request: {
          endpoint: "{{url('problem_zip_upload', problem.code)}}",
          params: {
            'csrfmiddlewaretoken': '{{ csrf_token }}'
          }
        },
        chunking: {
          enabled: true,
          partSize: 40000000,
        },
        resume: {
          enabled: true
        },
        validation: {
          allowedExtensions: ['zip'],
        },
      }).on('complete', function (event, id, name, responseJSON) {
        console.log(responseJSON);
        if (!responseJSON.success) {
          alert('Fail to upload: ' + responseJSON.error);
        }
        else {
          $('#submit-button').click();
        }
      });;

      function update_select2() {
        $('tbody:not(.extra-row-body) .type-column select').select2({
          minimumResultsForSearch: -1
        });
      }

      $("#id_problem-data-checker").select2();
      update_select2();

      function autofill_if_exists($select, file) {
        if (!$select.val() && ~window.valid_files.indexOf(file))
        $select.val(file).trigger('change');
      }

      var $table = $('#case-table');
      $table.on('add-row', function (e, $tr) {
        // update_select2();
        $tr.find('input').filter('[id$=file]').each(function () {
          var $select, val = $(this).replaceWith($select = $('<select>').attr({
            id: $(this).attr('id'),
            name: $(this).attr('name'),
            style: 'width: 100%'
          })).val();
          $select.select2({
            data: window.big_input ? [val] : window.valid_files,
            allowClear: true,
            placeholder: ''
          }).val(val).trigger('change').on('change', function () {
            var val = $select.val();
            if (val) {
              if ($select.attr('id').endsWith('input_file'))
              autofill_if_exists($tr.find('select[id$=output_file]'), val.replace(/in(?!.*?in)/, 'out'));
              else
              autofill_if_exists($tr.find('select[id$=input_file]'), val.replace(/out(?!.*?out)/, 'in'));
            }
          });
        });
      });

      var order = 0;

      function handle_table_reorder() {
        var in_batch = false;
        $table.find('tbody:first tr').each(function () {
          switch ($(this).attr('data-type')) {
            case 'C':
              $(this).find('input[id$=pretest]').toggle(!in_batch);
              break;
            case 'S':
              in_batch = true;
              break;
            case 'E':
              in_batch = false;
          }
        });
      }

      function try_parse_json(json) {
        try {
          return JSON.parse(json);
        } catch (e) {
          return {};
        }
      }

      function swap_row($a, $b) {
        var $a_order = $a.find('input[id$=order]'), $b_order = $b.find('input[id$=order]');
        var order = $a_order.val();
        $a_order.val($b_order.val());
        $b_order.val(order);
        $b.after($a);
        $a.find('span.order').text($a_order.val());
        $b.find('span.order').text($b_order.val());
        handle_table_reorder();
      }

      function checker_precision($checker) {
        var $td = $checker.parent();
        var $args = $td.closest('table').find('#id_problem-data-checker_args');
        var $precision = $('<input>', {
          type: 'number',
          value: try_parse_json($args.val()).precision || 6,
          title: 'precision (decimal digits)',
          style: 'width: 4em'
        }).change(function () {
          if ($checker.val().startsWith('floats'))
          $args.val(JSON.stringify({precision: parseInt($(this).val())}));
          else
          $args.val('');
        }).appendTo($td);

        $checker.change(function () {
          $precision.toggle($checker.val().startsWith('floats')).change();
        }).change();
      }

      (function toggle_custom() {
        let $checker = $('#id_problem-data-checker')

        let $custom_checker = $('#id_problem-data-custom_checker');
        let $validator = $('#id_problem-data-custom_validator');
        let $interactive = $('#id_problem-data-interactive_judge');
        let $sig_handler = $('#id_problem-data-signature_handler');
        let $sig_header = $('#id_problem-data-signature_header');
        let $ioi_signature = $("#id_problem-data-use_ioi_signature");

        $tr_checker = $custom_checker.parent().parent();
        $tr_validator = $validator.parent().parent();
        $tr_interactive = $interactive.parent().parent();
        $tr_sig_handler = $sig_handler.parent().parent();
        $tr_sig_header = $sig_header.parent().parent();

        $td = $checker.parent();
        var $sample = $("<a/>",{
          text: "{{_('Instruction')}}",
          style: "margin-left:3em;",
          target: "_blank",
          href: "{{url('custom_checker_sample')}}"
        }).appendTo($td);

        $("<a/>",{
          text: " ({{_('Instruction')}})",
          target: "_blank",
          href: "{{url('custom_checker_sample')}}"
        }).appendTo($ioi_signature.parent());

        $checker.change(function () {
          $tr_checker.toggle($checker.val() == 'custom').change();
          $tr_validator.toggle($checker.val() == 'customval' || $checker.val() == 'testlib').change();

          $sample.toggle(['custom', 'customval', 'interact'].includes($checker.val())).change();
        }).change();

        $ioi_signature.change(function() {
          $tr_interactive.toggle($ioi_signature.is(':checked')).change();
          $tr_sig_header.toggle($ioi_signature.is(':checked')).change();
          $tr_sig_handler.toggle($ioi_signature.is(':checked')).change();
        }).change();
      })();

      checker_precision($('#id_problem-data-checker'));

      $table.on('add-row', function (e, $tr) {
        var $order = $tr.find('input').filter('[id$=order]').attr('type', 'hidden').val(++order);
        $order.after($('<span>', {'class': 'order'}).text($order.val()))
          .after($('<i>', {'class': 'fa fa-fw fa-lg fa-ellipsis-v'}));

        var $opts = $tr.find('input').slice(2, 6);
        var $files = $tr.find('select').slice(1, 3);
        var $delete = $files.end().last();
        $tr.find('select[id$=type]').change(function () {
          var $this = $(this), val = $this.val(), disabled;
          switch (val) {
            case 'S':
            case 'E':
              disabled = val == 'S';
              $opts.toggle(val == 'S');
              $files.siblings('.select2').hide();
              $delete.toggle(val == 'S');
              break;
            default:
              $opts.toggle(val == 'C');
              $files.siblings('.select2').toggle(val == 'C');
              $delete.toggle(val == 'C');
              var $prevs = $tr.prevAll('tr[data-type=S], tr[data-type=E]');
              disabled = $prevs.length && $prevs.get(0).getAttribute('data-type') == 'S';
              $tr.find('input[id$=pretest]').toggle(val == 'C' && !disabled);
          }
          $tr.attr('data-type', val).nextUntil('tr[data-type=S], tr[data-type=E], tr[data-type=""]')
            .find('input[id$=pretest]').toggle(!disabled);
        }).change();

        var tooltip_classes = 'tooltipped tooltipped-s';
        $tr.find('a.edit-generator-args').mouseover(function () {
          switch ($tr.attr('data-type')) {
            case 'C':
            case 'S':
              var $this = $(this).addClass(tooltip_classes);
              $this.attr('aria-label', $this.prev().val() || '(none)');
          }
        }).mouseout(function () {
          $(this).removeClass(tooltip_classes).removeAttr('aria-label');
        }).featherlight($('.generator-args-editor'), {
          beforeOpen: function () {
            switch ($tr.attr('data-type')) {
              case 'C':
              case 'S':
                return true;
              default:
                return false;
            }
          },
          afterOpen: function () {
            var $input = this.$currentTarget.prev();
            this.$instance.find('.generator-args-editor')
              .find('textarea').val($input.val()).end()
              .find('.button').click(function () {
              $input.val($(this).prev().val());
              $.featherlight.current().close();
            }).end()
              .show();
          }
        });

        checker_precision($tr.find('select[id$=checker]'));
      }).find('tbody:first').find('tr').each(function () {
        $table.trigger('add-row', [$(this)]);
      });

      $('form').submit(function () {
        $table.find('tbody:first').find('tr').each(function () {
          var filled = false;
          $(this).find('input, select').each(function () {
            var $this = $(this);
            if (!$this.attr('name'))
            return;
            if ($this.attr('type') === 'checkbox')
            filled |= $this.is(':checked');
            else if (!$this.attr('name').endsWith('order'))
            filled |= !!$this.val();
          });
          if (!filled)
          $(this).find('input[id$=order]').val('');
        });
      });

      var $total = $('#id_cases-TOTAL_FORMS');

      $('a#add-case-row').click(function () {
        var $tr;
        $table.find('tbody:first').append($tr = $($table.find('.extra-row-body').html()
            .replace(/__prefix__/g, $total.val())));
        $tr.find('.type-column select option[value="C"]').attr('selected', true);
        $total.val(parseInt($total.val()) + 1);
        $table.trigger('add-row', [$tr]);
        window.scrollBy(0, $tr.height());
        return false;
      });

      function isInpFile(x) {
        let tail = ['.in', '.inp', '.IN', '.INP']
        for (let i of tail) {
          if (x.endsWith(i)) {
            return true;
          }
        }
        return false;
      }
      function isOutFile(x) {
        let tail = ['.out', '.OUT', '.ans', '.ANS']
        for (let i of tail) {
          if (x.endsWith(i)) {
            return true;
          }
        }
        return false;
      }

      $('a#fill-testcases').click(function (e) {
        e.preventDefault();
        var inFiles = [], outFiles = [];
        for (let file of window.valid_files) {
          if (isInpFile(file)) {
            inFiles.push(file);
          }
          if (isOutFile(file)) {
            outFiles.push(file);
          }
        }
        if (inFiles.length == 0) {
          alert("No input/output files. Make sure your files' suffices are .in(p)/.out");
          return false;
        }
        if (inFiles.length != outFiles.length) {
          alert("The input files do not match the output files!");
          return false;
        }

        inFiles.sort();
        outFiles.sort();

        // big number of input
        if (inFiles.length > 100) {
          window.big_input = true;
        }

        var batch_starts = $('#batch_starts').val();
        batch_starts = batch_starts.split(',');
        batch_starts = batch_starts.filter(e => {
          return e.length && e == +e;
        });
        batch_starts = new Set(batch_starts.map(x => Math.min(Math.max(1, parseInt(x)), inFiles.length - 1)));
        batch_starts.add(inFiles.length + 1);

        var numRows = inFiles.length + 2 * batch_starts.size - 2;
        while ($total.val() < numRows) {
          $('a#add-case-row').click();
        }

        // fill cases
        var row = 0;
        for (var i = 0; i < inFiles.length; i++) {
          if (batch_starts.has(i + 1)) {
            $("#id_cases-"+row+"-type").val('S').change();
            row += 1;
          }
          var $input = $("#id_cases-"+row+"-input_file");
          $input.select2('destroy').empty().select2({ data: [inFiles[i]] });
          $input.val(inFiles[i]).change();
          var $output = $("#id_cases-"+row+"-output_file");
          $output.select2('destroy').empty().select2({ data: [outFiles[i]] });
          $output.val(outFiles[i]).change();

          if ($("#problem-type").val() == "ICPC") {
            $("#id_cases-"+row+"-points").val('0').change();
          }
          else {
            $("#id_cases-"+row+"-points").val('1').change();
          }
          row += 1;

          if (batch_starts.has(i + 2)) {
            $("#id_cases-"+(row-1)+"-points").val('1').change();
            $("#id_cases-"+row+"-type").val('E').change();
            row += 1;
          }
        }
        update_select2();
        return false;
      });

      var oldIndex;
      $('#case-table tbody').sortable({
        itemSelector: 'tr',
        handle: 'i.fa-ellipsis-v',
        start: function (event, ui) {
          $item = ui.item;
          oldIndex = $item.index();
        },
        stop: function (event, ui) {
          $item = ui.item;
          var newIndex = $item.index();
          if (newIndex > oldIndex) {
            var order = parseInt($item.parent().children().slice(oldIndex, newIndex).each(function () {
              var $order = $(this).find('input[id$=order]');
              $order.val(parseInt($order.val()) - 1).siblings('span.order').text($order.val());
            }).last().after($item).find('input[id$=order]').val());
            $item.find('input[id$=order]').val(order + 1).siblings('span.order').text(order + 1);
          } else if (newIndex < oldIndex) {
            var order = parseInt($item.parent().children().slice(newIndex + 1, oldIndex + 1).each(function () {
              var $order = $(this).find('input[id$=order]');
              $order.val(parseInt($order.val()) + 1).siblings('span.order').text($order.val());
            }).first().before($item).find('input[id$=order]').val());
            $item.find('input[id$=order]').val(order - 1).siblings('span.order').text(order - 1);
          }
          if (newIndex != oldIndex)
          handle_table_reorder();
        }
      });

      $('input#delete-all').change(function() {
        if (this.checked) {
          $("input[name$='DELETE']").attr('checked', true);
        }
        else {
          $("input[name$='DELETE']").attr('checked', false);
        }
      });

      // Change to OI if the first row point > 0
      if($("#id_cases-0-points").val() != '0') $('#problem-type').val('OI');
      $("#problem-type").select2();

      // Change batch_starts based on current tests
      function update_batch_starts() {
        var numBatches = 0;
        var batchStarts = [];
        $("#case-table tbody:first tr").each(function(idx) {
          $select = $('#id_cases-' + idx + '-type');
          if ($select.val() == 'S') {
            batchStarts.push(idx + 1 - 2 * numBatches);
            numBatches++;
          }
        });
        if (batchStarts) {
          $("#batch_starts").val(batchStarts.join(', '));
        }
      }
      update_batch_starts();

    }).change();
  </script>
  {% include 'fine_uploader/script.html' %}
{% endblock %}

{% block media %}
  <link href="{{ static ('fine-uploader/fine-uploader.css') }}" rel="stylesheet">
  <style>
    #case-table .select2 {
      text-align: initial;
    }

    .order-column {
      width: 1em;
    }

    span.order {
      padding-right: 0.5em;
    }

    body.dragging, body.dragging * {
      cursor: move !important;
    }

    .dragged {
      position: absolute;
      opacity: 0.5;
      z-index: 2000;
    }

    i.fa-ellipsis-v {
      cursor: move;
    }

    #case-table tbody td {
      white-space: nowrap;
    }

    .type-column {
      width: 8em;
    }

    ul.errorlist {
      border: 3px red solid;
      border-radius: 5px;
      padding-top: 1em;
      padding-bottom: 1em;
      background: #e99;
    }
  </style>
{% endblock %}

{% block header %}
  {% if data_form.instance.has_yml %}
    <div class="title-line-action">
      [<a href="{{ url('problem_data_init', problem.code) }}">{{ _('View YAML') }}</a>]
    </div>
  {% endif %}
{% endblock %}

{% block body %}
  {% if data_form.instance.feedback %}
    <ul class="errorlist">
      <li>{{ data_form.instance.feedback }}</li>
    </ul>
  {% endif %}
  <form class="problem-data-form" action="" method="POST" enctype="multipart/form-data">
    {% csrf_token %}
    {{ cases_formset.management_form }}
    <table class="table">
      {{ data_form.as_table() }}
      <th>
        <label>{{_('Autofill testcases')}}:</label>
      </th>
      <td>
        <div>
          {{_('Problem type')}}:
          <select id="problem-type" style="width: 5em">
            <option value="ICPC">ICPC</option>
            <option value="OI">OI</option>
          </select>
          <a id="fill-testcases" href="#">
            <i class="fa fa-circle"></i>
            {{_('Fill testcases')}}
          </a>
        </div>
        <div style="margin-top: 1em;">
          {{_("Batch start positions")}}:
          <input id="batch_starts">
        </div>
        <div>
          {{_("Leave empty if not use batch. If you want to divide to three batches [1, 4], [5, 8], [9, 10], enter: 1, 5, 9")}}
        </div>
      </td>
    </table>
    <input type="submit" value="{{ _('Apply!') }}" class="button" id="submit-button">
    <table id="case-table" class="table">
      <thead>
        <tr>
          <th class="order-column"></th>
          <th class="type-column">{{ _('Type') }}</th>
          <th>{{ _('Input file') }}</th>
          <th>{{ _('Output file') }}</th>
          <th>{{ _('Points') }}</th>
          <th>{{ _('Pretest?') }}</th>
          {% if cases_formset.can_delete %}
            <th>{{ _('Delete?') }}
              <br>
              <input type="checkbox" name="delete-all" id="delete-all">
            </th>
          {% endif %}
        </tr>
      </thead>
      <tbody>
        {% for form in all_case_forms %}
          {% if form.non_field_errors() %}
            <tr>
              <td colspan="{{ 9 + cases_formset.can_delete }}">{{ form.non_field_errors() }}</td>
            </tr>
          {% endif %}
          {% if form.prefix and '__prefix__' in form.prefix %}
            </tbody>
            <tbody class="extra-row-body" style="display: none">
          {% endif %}
          <tr data-type="{{ form['type'].value() }}">
            <td>
              {{ form.id }}{{ form.order.errors }}{{ form.order }}
            </td>
            <td class="type-column">{{ form.type.errors }}{{ form.type }}</td>
            <td{% if not (form.empty_permitted or form['type'].value() != 'C' or
              form['input_file'].value() in valid_files) %} class="bad-file"{% endif %}>
        {{ form.input_file.errors }}{{ form.input_file }}
      </td>
      <td{% if not (form.empty_permitted or form['type'].value() != 'C' or
form['output_file'].value() in valid_files) %} class="bad-file"{% endif %}>
  {{ form.output_file.errors }}{{ form.output_file }}
</td>
<td>{{ form.points.errors }}{{ form.points }}</td>
<td>{{ form.is_pretest.errors }}{{ form.is_pretest }}</td>
{% if cases_formset.can_delete %}
  <td>{{ form.DELETE }}</td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
<input type="submit" value="{{ _('Apply!') }}" class="button" id="submit-button">
<a id="add-case-row" href="#"><i class="fa fa-plus"></i> {{ _('Add new case') }}</a>
</form>
{% endblock %}