(function($) {

  function State() {
    this.input = null;
    this.outputUnit = null;
    this.density = null;
    this.changed = false;
  }

  State.prototype.setInput = function(value) {
    if (value != this.input) {
      this.changed = true;
      this.input = value;
    }
  };

  State.prototype.setDensity = function(value) {
    if (value != this.density) {
      this.changed = true;
      this.density = value;
    }
  };

  State.prototype.setOutputUnit = function(value) {
    if (value != this.outputUnit) {
      this.changed = true;
      this.outputUnit = value;
    }
  };

  State.prototype.is_changed = function() {
    return this.changed;
  };

  State.prototype.reset = function() {
    this.changed = false;
  };

  var ingredientSearchEngine = new Bloodhound({
    initialize: false,
    datumTokenizer: function(datum) {
      return Bloodhound.tokenizers.whitespace(datum.name);
    },
    queryTokenizer: Bloodhound.tokenizers.whitespace,
    identify: function(datum) { return datum.id; },
    sorter: function(a, b) {
      if (a.name < b.name) {
        return -1;
      } else if (b.name < a.name) {
        return 1;
      } else {
        return 0;
      }
    },
    remote: {
      url: '/calculator/ingredient_search.json?query=%QUERY',
      wildcard: '%QUERY'
    }
  });

  $(document).on("turbolinks:load", function() {

    var state = new State();
    var $input = $("#input");
    var $output = $("#output");
    var $density = $("#density");
    var $outputUnit = $("#output_unit");

    var performUpdate = _.debounce(function() {
      $.getJSON(
        "/calculator/calculate",
        {input: $input.val(), output_unit: $outputUnit.val(), density: $density.val()},
        function(data) {
          if (data.errors.length) {
            $("#errors_panel").show();
            $("#errors_container").html(data.errors.join(" "));
          } else {
            $("#errors_panel").hide();
          }

          $output.val(data.output);
        }
      );

    }, 500);

    var ingredientPicked = function(i) {
      $density.val(i.density);
      $density.trigger('change');
    };

    $input.add($outputUnit).add($density).on('change blur keyup', function(evt) {
      state.setInput($input.val());
      state.setOutputUnit($outputUnit.val());
      state.setDensity($density.val());

      if (state.is_changed()) {
        performUpdate();
        state.reset();
      }
    });

    if ($("#calculator").length) {
      ingredientSearchEngine.initialize(false);

      $("#ingredient").typeahead({},
          {
            name: 'ingredients',
            source: ingredientSearchEngine,
            display: function(datum) {
              return datum.name;
            }
          })
          .on("typeahead:select", function(evt, value) {
            ingredientPicked(value);
          })
          .on("typeahead:autocomplete", function(evt, value) {
            ingredientPicked(value);
          });
    }

  });

})(jQuery);