(function($) {

  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;
      }
    },
    prefetch: {
      url: '/ingredients/prefetch.json',
      cache: false
    },
    remote: {
      url: '/ingredients/search.json?query=%QUERY',
      wildcard: '%QUERY'
    }
  });

  function reorder($container) {
    $container.find("div.nested-fields").each(function(idx, editor) {
      var $editor = $(editor);
      $editor.find('input.sort_order').val(idx + 1).trigger("changed");
    })
  }

  function initializeStepEditor($container) {
    // $container is either an element that contains many editors, or a single editor.
    var $editors = $container.find("textarea.step").closest(".step-editor");

    $editors.each(function(idx, elem) {
      var $editor = $(elem);
      var $step = $editor.find("textarea.step");
      autosize($step);

      setTimeout(function() { autosize.update($step); }, 250);
    });
  }

  function initializeIngredientEditor($container, ingredientSearchEngine) {
    // $container is either an element that contains many editors, or a single editor.
    var $editors = $container.find(".ingredient-typeahead").closest(".nested-fields");

    $editors.each(function(idx, elem) {
      var $editor = $(elem);
      var $ingredientId = $editor.find("input.ingredient_id");
      var $group = $editor.find("div.typeahead-group");

      $editor.find(".ingredient-typeahead").typeahead({},
        {
          name: 'ingredients',
          source: ingredientSearchEngine,
          display: function(datum) {
            return datum.name;
          }
        });

      if ($ingredientId.val().length) {
        $group.addClass("has-success");
      }
    });
  }

  function ingredientItemPicked($typeahead, datum) {
    var $container = $typeahead.closest(".nested-fields");
    var $ingredientId = $container.find("input.ingredient_id");
    var $group = $container.find("div.typeahead-group");

    $ingredientId.val(datum.id);
    $typeahead.typeahead('val', datum.name);
    $group.addClass("has-success");
  }

  function ingredientNameChange($typeahead, ingredientSearchEngine) {
    var $container = $typeahead.closest(".nested-fields");
    var $ingredientId = $container.find("input.ingredient_id");
    var $group = $container.find("div.typeahead-group");

    var id = $ingredientId.val();
    var value = $typeahead.typeahead('val');

    if (id && id.length) {
      var found = ingredientSearchEngine.get([id]);
      if (found && found[0] && found[0].name != value) {
        // User has chosen something custom
        $ingredientId.val('');

        $group.removeClass("has-success");
      }
    }
  }

  function addIngredient(item) {
    $("#ingredient-list").one("cocoon:before-insert", function(e, $container) {
      var $ingredientId = $container.find("input.ingredient_id");
      var $name = $container.find("input.ingredient-typeahead");
      var $quantity = $container.find("input.quantity");
      var $units = $container.find("input.units");
      var $preparation = $container.find("input.preparation");

      $name.val(item.name);
      $ingredientId.val(item.ingredient_id);
      $units.val(item.units);
      $quantity.val(item.quantity);
      $preparation.val(item.preparation);
    });

    $("#addIngredientButton").trigger("click");
  }

  function getIngredients() {
    var data = [];
    $("#ingredient-list .ingredient-editor").each(function() {
      var $container = $(this);

      var $ingredientId = $container.find("input.ingredient_id");
      var $name = $container.find("input.ingredient-typeahead.tt-input");
      var $quantity = $container.find("input.quantity");
      var $units = $container.find("input.units");
      var $preparation = $container.find("input.preparation");

      data.push({ingredient_id: $ingredientId.val(), name: $name.typeahead("val"), quantity: $quantity.val(), units: $units.val(), preparation: $preparation.val()});
    });

    return data;
  }

  function addStep(step) {
    $("#step-list").one("cocoon:before-insert", function(e, $container) {
      var $step = $container.find("textarea.step");
      $step.val(step);
    });

    $("#addStepButton").trigger("click");
  }

  function getSteps() {
    var data = [];
    $("#step-list .step-editor").each(function() {
      var $container = $(this);

      var $step = $container.find("textarea.step");

      data.push($step.val());
    });

    return data;
  }

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

    var $ingredientList = $("#ingredient-list");
    var $stepList = $("#step-list");

    if ($ingredientList.length) {
      ingredientSearchEngine.initialize(false);
    }

    initializeStepEditor($stepList);

    $stepList
      .on("cocoon:after-insert", function(e, item) {
        reorder($(this));
        initializeStepEditor(item);
      })
      .on("cocoon:after-remove", function(e, item) {
        if (item.find(".remove-button.existing").length) {
          item.detach().appendTo("#deleted_steps");
        }
        reorder($(this));
      })
      .on('changed', 'input.sort_order', function() {
        var $this = $(this);
        var $span = $this.closest(".nested-fields").find(".sort-order-display");
        $span.html($this.val());
      });


    initializeIngredientEditor($ingredientList, ingredientSearchEngine);

    $ingredientList
      .on("cocoon:after-insert", function(e, item) {
        reorder($ingredientList);
        initializeIngredientEditor(item, ingredientSearchEngine);
      })
      .on("cocoon:after-remove", function(e, item) {
        if (item.find(".remove-button.existing").length) {
          item.detach().appendTo("#deleted_ingredients");
        }
        reorder($ingredientList);
      })
      .on("typeahead:change", function(evt, value) {
        ingredientNameChange($(evt.target), ingredientSearchEngine);
      })
      .on("typeahead:select", function(evt, value) {
        ingredientItemPicked($(evt.target), value);
      })
      .on("typeahead:autocomplete", function(evt, value) {
        ingredientItemPicked($(evt.target), value);
      })
      .on("click", "button.ingredient_convert_btn", function(evt) {

      });

    $('#convert_modal')
      .on('show.bs.modal', function (event) {
        var $button = $(event.relatedTarget);
        var $modal = $(this);

        var $editor = $button.closest(".ingredient-editor");

        $modal.data('ingredient-editor', $editor);

        var $quantity = $editor.find("input.quantity");
        var $units = $editor.find("input.units");
        var $ingredientId = $editor.find("input.ingredient_id");

        var $modalQuantity = $modal.find("input.quantity");
        var $modalUnits = $modal.find("input.units");
        var $modalIngredientId = $modal.find("input.ingredient_id");

        $modalQuantity.val($quantity.val());
        $modalUnits.val($units.val());
        $modalIngredientId.val($ingredientId.val());
      })
      .on("ajax:success", "form", function(evt, data, status, xhr) {
        var $modal = $("#convert_modal");
        var $editor = $modal.data('ingredient-editor');

        if (data.success) {
          var $quantity = $editor.find("input.quantity");
          var $units = $editor.find("input.units");

          var $modalOutUnits = $modal.find("input.output_units");

          $quantity.val(data.output_quantity);
          if ($modalOutUnits.val().length) {
            $units.val($modalOutUnits.val());
          }

          $modal.modal('hide');
        } else {

        }

        $("#modal_form_container").replaceWith($(data.form_html));
      });

    var $bulkIngredientsModal = $("#bulk_ingredients_modal");
    var $ingredientBulkInput =  $("#ingredient_bulk_input");
    var $ingredientBulkList = $("#ingredient_bulk_parsed_list");
    autosize($ingredientBulkInput);

    var parseBulkIngredients = function() {
      var data = $ingredientBulkInput.val();
      $ingredientBulkList.empty();

      var parsed = [];
      var x;

      var lines = data.replace("\r", "").split("\n");

      var regex = /^(?:([\d\/.]+(?:\s+[\d\/]+)?)\s+)?(?:([\w-]+)(?:\s+of)?\s+)?([^,]*)(?:,\s*(.*))?$/i;

      var magicFunc = function(str) {
        if (str == "-") {
          return "";
        } else {
          return str;
        }
      };

      for (x = 0; x < lines.length; x++) {
        var line = lines[x].trim();
        if (line.length == 0) { continue; }

        var barIndex = line.lastIndexOf("|");
        var afterBar = null;

        if (barIndex >= 0) {
          afterBar = line.slice(barIndex + 1);
          line = line.slice(0, barIndex);
        }

        var match = line.match(regex);

        if (match) {
          item = {quantity: magicFunc(match[1]), units: magicFunc(match[2]), name: magicFunc(match[3]), preparation: magicFunc(match[4])};
          if (afterBar) {
            item.name = item.name + ", " + item.preparation;
            item.preparation = afterBar;
          }
          parsed.push(item);
        } else {
          parsed.push(null);
        }
      }

      $bulkIngredientsModal.data("bulkData", parsed);

      for (x = 0; x < parsed.length; x++) {
        var item = parsed[x];
        if (item != null) {
          $ingredientBulkList.append(
            $("<tr />")
              .append($("<td />").addClass("quantity").text(item.quantity))
              .append($("<td />").addClass("units").text(item.units))
              .append($("<td />").addClass("name").text(item.name))
              .append($("<td />").addClass("preparation").text(item.preparation))
          );
        } else {
          $ingredientBulkList.append(
            $("<tr />")
              .append($("<td />").attr("colspan", "4").text("<Cannot Parse>"))
          );
        }
      }
    };

    $bulkIngredientsModal
      .on('show.bs.modal', function (event) {
        var data = getIngredients();
        var x;
        var text = [];

        for (x = 0; x < data.length; x++) {
          var item = data[x];

          text.push(
            item.quantity + " " +
              (item.units || "-") + " " +
              item.name +
              (item.preparation ? (", " + item.preparation) : "")
          );
        }

        $ingredientBulkInput.val(text.join("\n"));

        setTimeout(function() {
          parseBulkIngredients();
          autosize.update($ingredientBulkInput);
        }, 250);
      });

    $ingredientBulkInput.on('keyup', function() {
      parseBulkIngredients();
    });

    $("#bulkIngredientAddSubmit").on("click", function() {
      var parsed = $bulkIngredientsModal.data("bulkData");
      var x;

      $("#ingredient-list").find(".remove-button").trigger("click");

      if (parsed && parsed.length) {
        for (x = 0; x < parsed.length; x++) {
          var item = parsed[x];
          if (item) {
            addIngredient(item)
          }
        }
      }

      $bulkIngredientsModal.modal('hide')
    });


    // ===========================================
    // ===========================================


    var $bulkStepsModal = $("#bulk_steps_modal");
    var $stepBulkInput =  $("#step_bulk_input");
    var $stepBulkList = $("#step_bulk_parsed_list");
    autosize($stepBulkInput);

    var parseBulkSteps = function() {
      var data = $stepBulkInput.val();
      $stepBulkList.empty();

      var parsed = [];
      var x;

      var lines = data.replace("\r", "").split("\n\n");

      for (x = 0; x < lines.length; x++) {
        var line = lines[x].trim().replace(/^\d+\./, "").trim();
        if (line.length == 0) { continue; }

        parsed.push(line);
      }

      $bulkStepsModal.data("bulkData", parsed);

      for (x = 0; x < parsed.length; x++) {
        var item = parsed[x];
        if (item != null) {
          $stepBulkList.append(
            $("<tr />")
              .append($("<td />").addClass("step").text(x + 1))
              .append($("<td />").addClass("direction").text(item))
          );
        } else {
          $stepBulkList.append(
            $("<tr />")
              .append($("<td />").attr("colspan", "2").text("<Cannot Parse>"))
          );
        }
      }
    };

    $bulkStepsModal
      .on('show.bs.modal', function (event) {
        var data = getSteps();
        $stepBulkInput.val(data.join("\n\n"));
        $stepBulkList.empty();

        setTimeout(function() {
          parseBulkSteps();
          autosize.update($stepBulkInput);
        }, 250);
      });

    $stepBulkInput.on('keyup', function() {
      parseBulkSteps();
    });

    $("#bulkStepAddSubmit").on("click", function() {
      var parsed = $bulkStepsModal.data("bulkData");
      var x;

      $("#step-list").find(".remove-button").trigger("click");

      if (parsed && parsed.length) {
        for (x = 0; x < parsed.length; x++) {
          var item = parsed[x];
          if (item) {
            addStep(item);
          }
        }
      }

      $bulkStepsModal.modal('hide')
    });

  });


})(jQuery);
