// Generated by CoffeeScript 1.10.0
(function() {
  var PHRASE_COMPLETE_EVENT, PHRASE_DESELECTED_EVENT, PHRASE_MOVE_LEFT_EVENT, PHRASE_MOVE_RIGHT_EVENT, PHRASE_REMOVE_EVENT, PHRASE_SELECTED_EVENT, PHRASE_WIDTH_CHANGED_EVENT, PhraseElement, Suggest, createSuggestElement, getLeftPadding, grammarInputPrepare, suggestInputPrepare;

  createSuggestElement = function(position) {
    var el;
    el = $("<div class='suggest'><ul class='choices'></ul></div>");
    el.appendTo('body');
    el.css(position);
    return el;
  };

  grammarInputPrepare = function(grammar) {
    grammar.input.focus(function(event) {
      return grammar.clearSelection();
    });
    return grammar.input.keydown(function(event) {
      if (event.keyCode === 37) {
        if (grammar.input.val()) {
          return;
        }
        return grammar.selectLastPhrase();
      } else if (event.keyCode === 8) {
        if (grammar.input.val()) {
          return;
        }
        event.preventDefault();
        return grammar.selectLastPhrase();
      }
    });
  };

  suggestInputPrepare = function(suggest) {
    suggest.input.attr('autocomplete', 'off');
    suggest.input.focus(function() {
      return suggest.open();
    });
    suggest.input.focusout(function() {
      return setTimeout(function() {
        if (!suggest.input.is(':focus')) {
          return suggest.close();
        }
      }, 200);
    });
    return suggest.input.keydown(function(event) {
      if (event.keyCode === 13) {
        event.preventDefault();
        return suggest.useSelected();
      } else if (event.keyCode === 27) {
        return suggest.close();
      } else if (event.keyCode === 40) {
        if (!suggest.isOpened) {
          return suggest.open();
        } else {
          return suggest.moveSelectedDown();
        }
      } else if (event.keyCode === 38) {
        if (!suggest.isOpened) {
          return suggest.open();
        } else {
          return suggest.moveSelectedUp();
        }
      } else {
        return setTimeout(function() {
          return suggest.refresh();
        }, 10);
      }
    });
  };

  getLeftPadding = function(input) {
    var inputPadding, rawInputPadding;
    rawInputPadding = input.css('padding-left');
    inputPadding = Number(rawInputPadding.substring(0, rawInputPadding.length - 2));
    return inputPadding;
  };

  Suggest = (function() {
    function Suggest(input1, phrases1) {
      this.input = input1;
      this.phrases = phrases1;
      this.selectHandlers = [];
      this.isOpened = false;
      suggestInputPrepare(this);
    }

    Suggest.prototype.open = function() {
      var inputHeight, inputWidth, position;
      if (this.isOpened) {
        return;
      }
      this.isOpened = true;
      position = this.input.offset();
      this.element = createSuggestElement(position);
      inputHeight = this.input.outerHeight();
      this.element.css('margin-top', inputHeight);
      inputWidth = this.input.outerWidth();
      this.element.css('width', inputWidth);
      return this.refresh();
    };

    Suggest.prototype.close = function() {
      if (!this.isOpened) {
        return;
      }
      this.isOpened = false;
      return this.element.remove();
    };

    Suggest.prototype.refresh = function() {
      var filterText, j, k, len, len1, phrase, phraseItem, phraseText, phrases, ref;
      if (!this.isOpened) {
        return;
      }
      this.element.find('.choices li, .no-items').remove();
      phrases = [];
      ref = this.phrases;
      for (j = 0, len = ref.length; j < len; j++) {
        phrase = ref[j];
        filterText = this.input.val().toLowerCase();
        phraseText = phrase.text.toLowerCase();
        if (phraseText.indexOf(filterText) === 0) {
          phrases.push(phrase);
        }
      }
      if (phrases.length) {
        for (k = 0, len1 = phrases.length; k < len1; k++) {
          phrase = phrases[k];
          phraseItem = $("<li>" + phrase.text + "</li>");
          phraseItem.data(phrase);
          phraseItem.click((function(_this) {
            return function(event) {
              var ref1, tagName;
              _this.select($(event.target).data());
              tagName = (ref1 = $(':focus').prop('tagName')) != null ? ref1.toLocaleLowerCase() : void 0;
              if (!tagName || tagName !== 'input') {
                return _this.input.focus();
              }
            };
          })(this));
          this.element.find('.choices').append(phraseItem);
        }
        return this.element.find('.choices li').first().addClass('selected');
      } else {
        return this.element.append('<div class="no-items">Нет элементов для выбора...</div>');
      }
    };

    Suggest.prototype.addSelectHandler = function(handler) {
      return this.selectHandlers.push(handler);
    };

    Suggest.prototype.select = function(phrase) {
      var handler, j, len, ref;
      ref = this.selectHandlers;
      for (j = 0, len = ref.length; j < len; j++) {
        handler = ref[j];
        handler(phrase);
      }
      this.input.val('');
      return this.refresh();
    };

    Suggest.prototype.useSelected = function() {
      var phrase, selectedElement;
      selectedElement = this.element.find('.choices li.selected');
      if (!selectedElement.length) {
        return;
      }
      phrase = selectedElement.data();
      return this.select(phrase);
    };

    Suggest.prototype.moveSelectedDown = function() {
      var nextElement;
      nextElement = $('.choices li.selected').next();
      if (!nextElement.length) {
        nextElement = this.element.find('.choices li').first();
      }
      this.element.find('.choices li').removeClass('selected');
      return nextElement.addClass('selected');
    };

    Suggest.prototype.moveSelectedUp = function() {
      var prevElement;
      prevElement = $('.choices li.selected').prev();
      if (!prevElement.length) {
        prevElement = this.element.find('.choices li').last();
      }
      this.element.find('.choices li').removeClass('selected');
      return prevElement.addClass('selected');
    };

    return Suggest;

  })();

  PHRASE_MOVE_LEFT_EVENT = 'PHRASE_MOVE_LEFT';

  PHRASE_MOVE_RIGHT_EVENT = 'PHRASE_MOVE_RIGHT';

  PHRASE_REMOVE_EVENT = 'PHRASE_REMOVE';

  PHRASE_SELECTED_EVENT = 'PHRASE_SELECTED';

  PHRASE_DESELECTED_EVENT = 'PHRASE_DESELECTED';

  PHRASE_WIDTH_CHANGED_EVENT = 'PHRASE_WIDTH_CHANGED';

  PHRASE_COMPLETE_EVENT = 'PHRASE_COMPLETE';

  PhraseElement = (function() {
    function PhraseElement(phrase1, position, data) {
      var contentHtml, i, input, j, len, ref;
      this.phrase = phrase1;
      this.hasParams = this.phrase.text.indexOf('_') !== -1;
      contentHtml = this.phrase.text;
      contentHtml = contentHtml.replace(/_/g, "<input></input>");
      this.el = $("<div tabindex='0' class='phrase'>" + contentHtml + "</div>");
      if (!this.hasParams) {
        this.el.addClass('no-params');
      }
      this.el.appendTo('body');
      this.el.css(position);
      this.width = this.el.outerWidth(true);
      if (this.hasParams) {
        this.select();
        this.lastFocusedInput = void 0;
        this.el.find('input').focus((function(_this) {
          return function(e) {
            return _this.lastFocusedInput = $(e.target);
          };
        })(this));
        if (data) {
          ref = this.el.find('input');
          for (i = j = 0, len = ref.length; j < len; i = ++j) {
            input = ref[i];
            $(input).val(data[i]);
          }
          this._renderInputs();
        }
      }
      this.el.click((function(_this) {
        return function(event) {
          var doNotChangeFocusPosition, ref1, targetTag;
          targetTag = (ref1 = $(event.target)) != null ? ref1.prop('tagName').toLocaleLowerCase() : void 0;
          doNotChangeFocusPosition = targetTag && targetTag === 'input';
          return setTimeout(function() {
            return _this.select(doNotChangeFocusPosition);
          }, 100);
        };
      })(this));
      this.el.keydown((function(_this) {
        return function(event) {
          var isTargetInput, processed, target;
          setTimeout(function() {
            return _this._renderInputs();
          }, 100);
          target = $(event.target);
          isTargetInput = target.prop('tagName').toLocaleLowerCase() === 'input';
          if (event.keyCode === 37) {
            processed = _this.moveSelectionLeft();
            if (processed) {
              return event.preventDefault();
            }
          } else if (event.keyCode === 39) {
            processed = _this.moveSelectionRight();
            if (processed) {
              return event.preventDefault();
            }
          } else if (event.keyCode === 46) {
            if (isTargetInput && target.val().length) {
              return;
            }
            _this.moveSelectionRight();
            return _this.remove();
          } else if (event.keyCode === 8) {
            if (isTargetInput && target.val().length) {
              return;
            }
            event.preventDefault();
            _this.moveSelectionLeft();
            return _this.remove();
          } else if (event.keyCode === 13) {
            _this.complete();
            return event.preventDefault();
          }
        };
      })(this));
    }

    PhraseElement.prototype.complete = function() {
      var e;
      this.deselect();
      e = $.Event(PHRASE_COMPLETE_EVENT, {
        phraseElement: this
      });
      return $(this).trigger(e);
    };

    PhraseElement.prototype.select = function(doNotChangeFocusPosition) {
      var e, setInputFocus;
      this.el.addClass('selected');
      if (this.hasParams) {
        setInputFocus = !doNotChangeFocusPosition;
        if (setInputFocus) {
          this._setInputFocus(setInputFocus);
        }
      } else {
        this.el.focus();
      }
      e = $.Event(PHRASE_SELECTED_EVENT, {
        phraseElement: this
      });
      return $(this).trigger(e);
    };

    PhraseElement.prototype.deselect = function(noBlur) {
      var doBlur, e;
      this.el.removeClass('selected');
      e = $.Event(PHRASE_DESELECTED_EVENT, {
        phraseElement: this
      });
      $(this).trigger(e);
      doBlur = !noBlur;
      if (doBlur) {
        this.el.blur();
        return this.getInputs().blur();
      }
    };

    PhraseElement.prototype.isSelected = function() {
      return this.el.hasClass('selected');
    };

    PhraseElement.prototype.getText = function() {
      return this.phrase.text;
    };

    PhraseElement.prototype.getWidth = function() {
      return this.width;
    };

    PhraseElement.prototype.getLeftPosition = function() {
      var left, rawLeft;
      rawLeft = this.el.css('left');
      left = Number(rawLeft.substring(0, rawLeft.length - 2));
      return left;
    };

    PhraseElement.prototype.setLeftPosition = function(left) {
      return this.el.css('left', left);
    };

    PhraseElement.prototype.remove = function() {
      var e;
      this.el.remove();
      e = $.Event(PHRASE_REMOVE_EVENT, {
        phraseElement: this
      });
      return $(this).trigger(e);
    };

    PhraseElement.prototype.moveSelectionLeft = function() {
      var e, focusedInput, position, prevInput;
      if (this.hasParams) {
        focusedInput = this.el.find('input:focus');
        position = focusedInput.caret();
        if (position > 0) {
          return false;
        }
        prevInput = focusedInput.prev();
        if (prevInput.length) {
          prevInput.focus();
          return true;
        }
      }
      this.deselect();
      e = $.Event(PHRASE_MOVE_LEFT_EVENT, {
        phraseElement: this
      });
      $(this).trigger(e);
      return true;
    };

    PhraseElement.prototype.moveSelectionRight = function() {
      var chars, e, focusedInput, nextInput, position;
      if (this.hasParams) {
        focusedInput = this.el.find('input:focus');
        position = focusedInput.caret();
        chars = focusedInput.val().length;
        if (position < chars) {
          return false;
        }
        nextInput = focusedInput.next();
        if (nextInput.length) {
          nextInput.focus();
          return true;
        }
      }
      this.deselect();
      e = $.Event(PHRASE_MOVE_RIGHT_EVENT, {
        phraseElement: this
      });
      $(this).trigger(e);
      return true;
    };

    PhraseElement.prototype.getInputs = function() {
      return this.el.find("input");
    };

    PhraseElement.prototype.getData = function() {
      var data, input, j, len, ref;
      if (this.hasParams) {
        data = [];
        ref = this.getInputs();
        for (j = 0, len = ref.length; j < len; j++) {
          input = ref[j];
          data.push($(input).val());
        }
        return data;
      } else {
        return 1;
      }
    };

    PhraseElement.prototype._setInputFocus = function() {
      var input, j, len, ref;
      if (this.lastFocusedInput) {
        this.lastFocusedInput.focus();
        return;
      }
      ref = this.getInputs();
      for (j = 0, len = ref.length; j < len; j++) {
        input = ref[j];
        input = $(input);
        if (!input.val()) {
          input.focus();
          return;
        }
      }
      return input.focus();
    };

    PhraseElement.prototype._renderInputs = function() {
      var e, input, j, len, newWidth, ref, scrollWidth, tmpInput;
      ref = this.getInputs();
      for (j = 0, len = ref.length; j < len; j++) {
        input = ref[j];
        input = $(input);
        tmpInput = $("<input style='width:10px' value='" + (input.val()) + "' />").appendTo('body');
        scrollWidth = tmpInput.prop('scrollWidth');
        tmpInput.remove();
        input.width(scrollWidth);
      }
      newWidth = this.el.outerWidth(true);
      if (newWidth !== this.width) {
        this.width = newWidth;
        e = $.Event(PHRASE_WIDTH_CHANGED_EVENT, {
          phraseElement: this
        });
        return $(this).trigger(e);
      }
    };

    return PhraseElement;

  })();

  this.GrammarText = (function() {
    function GrammarText(input, phrasesUrl) {
      var data, dataJSON, inputName, phrase, phraseData, phraseText;
      this.phrasesUrl = phrasesUrl;
      this.input = $(input);
      this.originalInputLeftPadding = getLeftPadding(this.input);
      this.phrases = [];
      this.suggestPhrases = [];
      this.selectedPhrases = [];
      this.suggest = new Suggest(this.input, this.suggestPhrases);
      this.suggest.addSelectHandler((function(_this) {
        return function(phrase) {
          return _this.renderPhrase(phrase);
        };
      })(this));
      this.phraseElements = [];
      grammarInputPrepare(this);
      inputName = this.input.prop('name');
      this.input.removeProp('name');
      this.valueInput = $("<input type='hidden' name='" + inputName + "' />");
      this.valueInput.insertAfter(this.input);
      dataJSON = this.input.val();
      if (dataJSON) {
        this.input.val('');
        this.valueInput.val(dataJSON);
        data = JSON.parse(dataJSON);
        for (phraseText in data) {
          phraseData = data[phraseText];
          phrase = {
            'text': phraseText
          };
          this.renderPhrase(phrase, phraseData);
        }
        this.clearSelection();
      }
      this.input.parents().find('form').submit((function(_this) {
        return function() {
          return _this.refreshInputValue();
        };
      })(this));
    }

    GrammarText.prototype.getData = function() {
      var data, j, len, phraseElement, ref;
      data = {};
      ref = this.phraseElements;
      for (j = 0, len = ref.length; j < len; j++) {
        phraseElement = ref[j];
        data[phraseElement.getText()] = phraseElement.getData();
      }
      return data;
    };

    GrammarText.prototype.loadPhrases = function() {
      return $.get(this.phrasesUrl, (function(_this) {
        return function(result) {
          var j, len, phrase;
          for (j = 0, len = result.length; j < len; j++) {
            phrase = result[j];
            _this.phrases.push(phrase);
          }
          return _this.refreshSuggestPhrases();
        };
      })(this));
    };

    GrammarText.prototype.clearSelection = function() {
      var j, len, phraseElement, ref, results;
      ref = this.phraseElements;
      results = [];
      for (j = 0, len = ref.length; j < len; j++) {
        phraseElement = ref[j];
        results.push(phraseElement.deselect());
      }
      return results;
    };

    GrammarText.prototype.renderPhrase = function(phrase, data) {
      var inputPadding, phraseElement, position;
      position = this.input.offset();
      inputPadding = getLeftPadding(this.input);
      position.left += inputPadding;
      position.top -= 4;
      phraseElement = new PhraseElement(phrase, position, data);
      $(phraseElement).bind(PHRASE_MOVE_LEFT_EVENT, (function(_this) {
        return function(e) {
          return _this.moveLeftHandler(e);
        };
      })(this));
      $(phraseElement).bind(PHRASE_MOVE_RIGHT_EVENT, (function(_this) {
        return function(e) {
          return _this.moveRightHandler(e);
        };
      })(this));
      $(phraseElement).bind(PHRASE_COMPLETE_EVENT, (function(_this) {
        return function(e) {
          return _this.moveRightHandler(e);
        };
      })(this));
      $(phraseElement).bind(PHRASE_REMOVE_EVENT, (function(_this) {
        return function(e) {
          return _this.removePhraseHandler(e);
        };
      })(this));
      $(phraseElement).bind(PHRASE_SELECTED_EVENT, (function(_this) {
        return function(e) {
          return _this.selectPhraseHandler(e);
        };
      })(this));
      $(phraseElement).bind(PHRASE_WIDTH_CHANGED_EVENT, (function(_this) {
        return function(e) {
          return _this.widthChangedHandler();
        };
      })(this));
      $(phraseElement).bind(PHRASE_DESELECTED_EVENT, (function(_this) {
        return function(e) {
          return _this.deselectHandler(e);
        };
      })(this));
      this.phraseElements.push(phraseElement);
      this.refreshInputLeftPadding();
      this.selectedPhrases.push(phrase);
      return this.refreshSuggestPhrases();
    };

    GrammarText.prototype.getSelectedPhraseElement = function() {
      var j, len, phraseElement, ref;
      ref = this.phraseElements;
      for (j = 0, len = ref.length; j < len; j++) {
        phraseElement = ref[j];
        if (phraseElement.isSelected()) {
          return phraseElement;
        }
      }
    };

    GrammarText.prototype.getSelectedPhraseIndex = function() {
      var index, selectedPhraseElement;
      selectedPhraseElement = this.getSelectedPhraseElement();
      if (!selectedPhraseElement) {
        return;
      }
      index = this.phraseElements.indexOf(selectedPhraseElement);
      if (index === -1) {
        return;
      }
      return index;
    };

    GrammarText.prototype.getPhraseIndex = function(phrase) {
      var i, j, len, phraseElement, ref, selectedIndex;
      selectedIndex = void 0;
      ref = this.phraseElements;
      for (i = j = 0, len = ref.length; j < len; i = ++j) {
        phraseElement = ref[i];
        if (phrase.text === phraseElement.getText()) {
          selectedIndex = i;
          break;
        }
      }
      return selectedIndex;
    };

    GrammarText.prototype.selectLastPhrase = function() {
      var lastPhraseElement;
      if (!this.phraseElements.length) {
        return;
      }
      lastPhraseElement = this.phraseElements[this.phraseElements.length - 1];
      return lastPhraseElement.select();
    };

    GrammarText.prototype.selectPhraseByIndex = function(index) {
      var phraseElement;
      if (!this.phraseElements.length) {
        return;
      }
      phraseElement = this.phraseElements[index];
      return phraseElement.select();
    };

    GrammarText.prototype.refreshInputLeftPadding = function() {
      var j, len, padding, phraseElement, ref;
      padding = this.originalInputLeftPadding;
      ref = this.phraseElements;
      for (j = 0, len = ref.length; j < len; j++) {
        phraseElement = ref[j];
        padding += phraseElement.getWidth();
      }
      return this.input.css('padding-left', padding);
    };

    GrammarText.prototype.refreshSuggestPhrases = function() {
      var j, k, len, len1, phrase, ref, ref1, results, selected, selectedPhrase;
      this.suggestPhrases.length = 0;
      ref = this.phrases;
      results = [];
      for (j = 0, len = ref.length; j < len; j++) {
        phrase = ref[j];
        selected = false;
        ref1 = this.selectedPhrases;
        for (k = 0, len1 = ref1.length; k < len1; k++) {
          selectedPhrase = ref1[k];
          if (selectedPhrase.text === phrase.text) {
            selected = true;
          }
        }
        if (!selected) {
          results.push(this.suggestPhrases.push(phrase));
        } else {
          results.push(void 0);
        }
      }
      return results;
    };

    GrammarText.prototype.refreshInputValue = function() {
      var data, dataJSON;
      data = this.getData();
      dataJSON = JSON.stringify(data);
      return this.valueInput.val(dataJSON);
    };

    GrammarText.prototype.moveLeftHandler = function(e) {
      var nextIndex, nextPhraseElement, phrase, phraseIndex;
      phrase = e.phraseElement.phrase;
      phraseIndex = this.getPhraseIndex(phrase);
      nextIndex = phraseIndex - 1;
      if (nextIndex < 0) {
        nextIndex = 0;
      }
      nextPhraseElement = this.phraseElements[nextIndex];
      return nextPhraseElement.select();
    };

    GrammarText.prototype.moveRightHandler = function(e) {
      var lastIndex, nextIndex, nextPhraseElement, phrase, phraseIndex;
      phrase = e.phraseElement.phrase;
      phraseIndex = this.getPhraseIndex(phrase);
      nextIndex = phraseIndex + 1;
      lastIndex = this.phraseElements.length - 1;
      if (nextIndex <= lastIndex) {
        nextPhraseElement = this.phraseElements[nextIndex];
        return nextPhraseElement.select();
      } else {
        return this.input.focus();
      }
    };

    GrammarText.prototype.removePhraseHandler = function(e) {
      var deleteIndex, el, j, left, len, phraseElement, phrasePadding, ref;
      phraseElement = e.phraseElement;
      deleteIndex = this.getPhraseIndex(phraseElement.phrase);
      this.phraseElements.splice(deleteIndex, 1);
      phrasePadding = phraseElement.getWidth();
      this.refreshInputLeftPadding();
      ref = this.phraseElements.slice(deleteIndex);
      for (j = 0, len = ref.length; j < len; j++) {
        el = ref[j];
        left = el.getLeftPosition() - phrasePadding;
        el.setLeftPosition(left);
      }
      _.remove(this.selectedPhrases, {
        text: phraseElement.getText()
      });
      this.refreshSuggestPhrases();
      this.suggest.refresh();
      if (!this.phraseElements.length) {
        return this.input.focus();
      }
    };

    GrammarText.prototype.selectPhraseHandler = function(e) {
      var j, len, phraseElement, ref, results, selectedPhraseElement;
      selectedPhraseElement = e.phraseElement;
      ref = this.phraseElements;
      results = [];
      for (j = 0, len = ref.length; j < len; j++) {
        phraseElement = ref[j];
        if (phraseElement.phrase.text !== selectedPhraseElement.phrase.text) {
          results.push(phraseElement.deselect());
        } else {
          results.push(void 0);
        }
      }
      return results;
    };

    GrammarText.prototype.widthChangedHandler = function(e) {
      var j, left, len, phraseElement, ref, results;
      this.refreshInputLeftPadding();
      if (this.phraseElements.length) {
        left = this.phraseElements[0].getLeftPosition();
        ref = this.phraseElements;
        results = [];
        for (j = 0, len = ref.length; j < len; j++) {
          phraseElement = ref[j];
          phraseElement.setLeftPosition(left);
          results.push(left += phraseElement.getWidth());
        }
        return results;
      }
    };

    GrammarText.prototype.deselectHandler = function(e) {
      return this.refreshInputValue();
    };

    return GrammarText;

  })();

}).call(this);
