<!doctype html>
<title>Diamond - JSON Blaster</title>
<script type="text/javascript" src="{{ static_url('testui/jquery.js') }}"></script>

<style type="text/css">
.hidden {
  display: none;
}

#filters, .filter {
  margin-top: 2em;
}

#static-params {
  margin-top: 1em;
}

table {
  table-layout: fixed;
}

th {
  text-align: right;
  padding-right: 0.5em;
  width: 8em;
}
</style>

<div id="prototype" class="hidden">
  <div class="filter">
    <table>
      <tr><th>Name<td><input type="text" name="name" size="40">
      <tr><th>Filter<td><input type="file" name="code"><img class="hidden" src="{{ static_url('testui/spinner.gif') }}">
      <tr><th>Arguments<td><input class="multiple" type="text" name="arguments" size="40">
      <tr><th>Blob argument<td><input type="file" name="blob"><img class="hidden" src="{{ static_url('testui/spinner.gif') }}">
      <tr><th>Dependencies<td><input class="multiple" type="text" name="dependencies" size="40">
      <tr><th>Minimum score<td><input type="text" name="min_score" size="40">
      <tr><th>Maximum score<td><input type="text" name="max_score" size="40">
      <tr><th><td><input class="delete" type="submit" value="Delete filter">
    </table>
  </div>
</div>

<input id="add" type="submit" value="Add filter">
<input id="search" class="execute" type="submit" value="Search">

<table id="static-params">
  <tr><th>Scope cookie<td id="scope"><!-- input dynamically inserted here --><img class="hidden" src="{{ static_url('testui/spinner.gif') }}">
  <tr><th>Local object<td id="local"><!-- input dynamically inserted here --><input id="evaluate" class="execute" type="submit" value="Evaluate"><img class="hidden" src="{{ static_url('testui/spinner.gif') }}">
</table>

<div id="filters">
</div>

<script type="text/javascript">
$(function() {
  var filterIndex = 1;
  var pendingIO = 0;

  // Start an I/O operation.
  function _pending_inc() {
    pendingIO++;
    $('.execute').attr('disabled', 'disabled');
  }

  // Finish an I/O operation.
  function _pending_dec() {
    if (!--pendingIO) {
      $('.execute').removeAttr('disabled');
    }
  }

  // Upload a blob when a file is selected.
  function _blob_selection_handler() {
    var input = this;
    var file = this.files[0];
    var reader = new FileReader();
    _pending_inc();
    function finish() {
      $(input).nextAll('img').hide();
      _pending_dec();
    }
    reader.onloadend = function() {
      if (reader.error) {
        alert('Error reading file.');
        $(input).removeData('uri');
        finish();
      } else {
        $.ajax({
          type: 'POST',
          url: '/blob',
          contentType: 'application/octet-stream',
          data: file,
          processData: false,
          success: function(data, textStatus, jqXHR) {
            $(input).data('uri', jqXHR.getResponseHeader('Location'));
            finish();
          },
          error: function(jqXHR, textStatus, errorThrown) {
            alert('Error uploading file.')
            $(input).removeData('uri');
            finish();
          },
        });
      }
    }
    $(input).nextAll('img').show();
    reader.readAsBinaryString(file);
  }

  // Handle loading of a scope cookie.  Dynamically create the cookie
  // input so some browsers won't prepopulate the field (incorrectly, since
  // our handler doesn't get a chance to run).
  var scope_input = $('<input name="cookie" type="file">').
      prependTo($('#scope'));
  scope_input.change(function() {
    var input = this;
    var reader = new FileReader();
    _pending_inc();
    reader.onloadend = function() {
      if (reader.error) {
        alert('Error reading file.');
        $(input).removeData('data');
      } else {
        $(input).data('data', reader.result);
      }
      $(input).nextAll('img').hide();
      _pending_dec();
    }
    $(input).nextAll('img').show();
    reader.readAsText(this.files[0]);
  });

  // Handle loading of a local object.  Dynamically create the file input
  // so some browsers won't prepopulate the field (incorrectly, since our
  // handler doesn't get a chance to run).
  var local_input = $('<input name="object" type="file">').
      prependTo($('#local'));
  local_input.change(_blob_selection_handler);

  function _multiple_keypress_handler() {
    // Handle the first keypress in the last field of the
    // arguments/dependencies lists.
    var new_row = $('<tr><th><td><input type="text" size="40">');
    new_row.find('input').attr('name', $(this).attr('name'));
    new_row.find('input').one('keypress', _multiple_keypress_handler);
    $(this).closest('tr').after(new_row);
  }

  $('#add').click(function(ev) {
    // Add a filter.
    ev.preventDefault();
    var form = $('#prototype').contents().clone();
    form.find('[name=name]').attr('value', 'Filter-' + filterIndex++);

    // Bind the multiple-item list fields.
    form.find('.multiple').one('keypress', _multiple_keypress_handler);

    // Bind the delete button.
    form.find('.delete').click(function() {
      $(this).closest('.filter').slideUp('fast', function() {
        $(this).remove();
      });
    });

    // Handle file selection in the filter/blob argument fields.
    form.find('[type=file]').change(_blob_selection_handler);

    // Add the form to the DOM.
    form.hide();
    $('#filters').append(form);
    form.slideDown('fast');
  });

  // Copy a string from a text field into an object.
  function _load_string(out, obj, name) {
    var value = $(obj).find('[name=' + name + ']').attr('value');
    if (value !== '') {
      out[name] = value;
    }
  }

  // Copy a floating-point number from a text field into an object.
  function _load_number(out, obj, name) {
    var value = $(obj).find('[name=' + name + ']').attr('value');
    if (value !== '') {
      value = parseFloat(value);
      if (isNaN(value)) {
        throw 'Invalid number';
      }
      out[name] = value;
    }
  }

  // Copy a list of strings from a set of text fields into an object.
  function _load_list(out, obj, name) {
    var list = [];
    $(obj).find('[name=' + name + ']').each(function(i, el) {
      var value = $(el).attr('value');
      if (value !== '') {
        list.push(value);
      }
    });
    if (list.length) {
      out[name] = list;
    }
  }

  // Copy metadata on a chosen file from a file input field to an object.
  function _load_file(out, obj, name) {
    var uri = $(obj).find('[name=' + name + ']').data('uri');
    if (typeof uri !== 'undefined') {
      out[name] = {
        uri: uri,
      };
    }
  }

  // Handle the search and evaluate buttons.
  $('.execute').click(function(ev) {
    ev.preventDefault();

    // Filters
    var fconfigs = [];
    try {
      $('#filters').find('.filter').each(function(i, filter) {
        var fconfig = {}
        _load_string(fconfig, filter, 'name');
        _load_list(fconfig, filter, 'arguments');
        _load_list(fconfig, filter, 'dependencies');
        _load_number(fconfig, filter, 'min_score');
        _load_number(fconfig, filter, 'max_score');
        _load_file(fconfig, filter, 'code');
        _load_file(fconfig, filter, 'blob');
        fconfigs.push(fconfig);
      });
    } catch (err) {
      if (err === 'Invalid number') {
        alert('Invalid score value.');
      }
      throw err;
    }

    // Cookies
    var cookies = [];
    var cookie_data = $('#scope [name=cookie]').data('data');
    if (typeof cookie_data !== 'undefined') {
      cookies.push(cookie_data);
    }

    // Open a window to receive the search results while we still have
    // the browser's attention
    var child_window = window.open('');
    var results_url = '{{ reverse_url("ui-results") }}';
    var result_url = '{{ reverse_url("ui-result") }}';

    // Create the search
    var search = {
      cookies: cookies,
      filters: fconfigs,
    };
    var want_evaluate = $(this).prop('id') === 'evaluate';
    $.ajax({
      type: 'POST',
      url: '/',
      contentType: 'application/json', 
      data: JSON.stringify(search),
      dataType: 'json',
      success: function(data, textStatus, jqXHR) {
        if (want_evaluate) {
          var evaluate = {};
          _load_file(evaluate, $('#local'), 'object');

          $.ajax({
            type: 'POST',
            url: data.evaluate_url,
            contentType: 'application/json',
            data: JSON.stringify(evaluate),
            dataType: 'json',
            success: function(data, textStatus, jqXHR) {
              child_window.location = result_url + '#' + data._ResultURL.data;
            },
            error: function(jqXHR, textStatus, errorThrown) {
              child_window.location = results_url + '#e' +
                  escape(jqXHR.responseText);
            },
          });
        } else {
          child_window.location = results_url + '#s' + data.search_key;
        }
      },
      error: function(jqXHR, textStatus, errorThrown) {
        child_window.location = results_url + '#e' +
            escape(jqXHR.responseText);
      },
    });
  });
});
</script>
