// Generated by CoffeeScript 1.3.3
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
  __hasProp = {}.hasOwnProperty,
  __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };

define(['environ', 'mediator', 'jquery', 'underscore', 'backbone', 'serrano'], function(environ, mediator, $, _, Backbone, Serrano) {
  var BooleanControl, Control, DEFAULT_EVENTS, EnumerableControl, NEGATION_OPERATORS, NumberControl, SearchableControl, formActionsTemplate, placeholderText;
  formActionsTemplate = _.template('\
        <div class=form-actions>\
            <button class="btn btn-mini btn-danger pull-left" name=remove title="Remove filter">Remove</button>\
            <button class="btn btn-mini btn-warning" name=exclude title="Exclude results from query">Exclude</button>\
            <button class="btn btn-mini btn-success" name=include title="Include results in query">Include</button>\
        </div>\
    ');
  NEGATION_OPERATORS = {};
  DEFAULT_EVENTS = {
    'click [name=remove]': 'clearFilter',
    'click [name=include]': 'submitInclude',
    'click [name=exclude]': 'submitExclude',
    'change [name=operator]': 'toggleOperator'
  };
  Control = (function(_super) {

    __extends(Control, _super);

    function Control() {
      this.loadValues = __bind(this.loadValues, this);

      this.loadOperators = __bind(this.loadOperators, this);

      this.loadStats = __bind(this.loadStats, this);
      return Control.__super__.constructor.apply(this, arguments);
    }

    Control.prototype.template = _.template('\
            <div class=control-group>\
                <h4 class=control-label>{{ label }} <small class=units>({{ units }})</small></h4>\
                <div class=controls>\
                    <select class=span4 name=operator></select>\
                    <input class=span4 type=text name=value>\
                    <p class=help-block>{{ help }}</p>\
                </div>\
            </div>\
        ');

    Control.prototype.events = DEFAULT_EVENTS;

    Control.prototype.deferred = {
      loadStats: true,
      loadValues: true
    };

    Control.prototype.initialize = function(options) {
      var _this = this;
      Control.__super__.initialize.apply(this, arguments);
      this.options = options;
      return mediator.subscribe("datacontext/" + this.model.id + "/edit", function(node) {
        if (node === _this.node) {
          return;
        }
        return _this.set(node);
      });
    };

    Control.prototype.getTemplateData = function() {
      return {
        label: this.model.get('alt_name') || this.model.get('name'),
        units: this.model.get('plural_unit'),
        help: this.model.get('description')
      };
    };

    Control.prototype.renderTemplate = function() {
      this.setElement(this.template(this.getTemplateData()));
      return this.$el.append(formActionsTemplate());
    };

    Control.prototype.render = function() {
      this.renderTemplate();
      this.$label = this.$('.control-label');
      this.$value = this.$('[name=value]');
      this.$operator = this.$('[name=operator]');
      this.$controls = this.$('.controls');
      this.$actions = this.$('.form-actions');
      this.$include = this.$('[name=include]');
      this.$exclude = this.$('[name=exclude]');
      this.$remove = this.$('[name=remove]').hide();
      if (this.options.label === false) {
        this.$label.hide();
      }
      if (!(this.getTemplateData().units)) {
        this.$('.units').hide();
      }
      this.loadOperators();
      this.loadValues();
      this.loadStats();
      return this.$el;
    };

    Control.prototype.show = function() {
      return this.resolve();
    };

    Control.prototype.hide = function() {
      return this.pending();
    };

    Control.prototype.preventDefault = function(event) {
      return event.preventDefault();
    };

    Control.prototype.toggleOperator = function(event) {
      return this.toggleActions();
    };

    Control.prototype.toggleActions = function(event) {
      if (NEGATION_OPERATORS[this.$operator.val()]) {
        return this.$exclude.prop('disabled', false);
      } else {
        return this.$exclude.prop('disabled', true);
      }
    };

    Control.prototype.submitInclude = function(event) {
      event.preventDefault();
      return this.submit(this.get());
    };

    Control.prototype.submitExclude = function(event) {
      event.preventDefault();
      return this.submit(this.get({
        negated: true
      }));
    };

    Control.prototype.clearFilter = function(event) {
      event.preventDefault();
      return this.clear();
    };

    Control.prototype.clear = function() {
      if (this.node) {
        this.submit();
      }
      return this.$remove.hide();
    };

    Control.prototype.validate = function() {};

    Control.prototype.loadStats = function() {
      var stats,
        _this = this;
      if (!(stats = this.model.get('_links').stats)) {
        return;
      }
      return Backbone.ajax({
        url: stats.href,
        success: function(resp) {
          var key, text, value;
          text = [];
          for (key in resp) {
            value = resp[key];
            if (key !== '_links' && value !== null) {
              key = key.replace(/[_\-\s]+/, ' ').trim();
              key = key.charAt(0).toUpperCase() + key.substr(1);
              if (_.isNumber(value)) {
                value = App.Numbers.prettyNumber(value);
              }
              text.push("" + key + ": " + value);
            }
          }
          if (text.length) {
            return $('<p>').addClass('help-block').text(text.join(', ')).appendTo(_this.$controls);
          }
        }
      });
    };

    Control.prototype.loadOperators = function() {
      var operator, operators, text, _i, _len, _ref, _ref1;
      _ref = (operators = this.model.get('operators'));
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        _ref1 = _ref[_i], operator = _ref1[0], text = _ref1[1];
        if (operator.charAt(0) === '-') {
          NEGATION_OPERATORS[operator.substr(1)] = operator;
          continue;
        }
        this.$operator.append("<option value=\"" + operator + "\">" + text + "</option>");
      }
      if (this.$operator.children().length === 1) {
        return this.$operator.hide();
      }
    };

    Control.prototype.loadValues = function() {
      return this.set();
    };

    Control.prototype.coerceValue = function(value) {
      var type;
      type = this.model.get('simple_type');
      if (value === 'null') {
        return null;
      }
      switch (type) {
        case 'boolean':
          value = value === 'true' ? true : false;
          break;
        case 'number':
          value = parseFloat(value);
      }
      return value;
    };

    Control.prototype.getValue = function(options) {
      var val, value;
      if (this.$value.is('[type=checkbox],[type=radio]')) {
        value = this.$value.prop('checked');
      } else {
        value = this.$value.val();
        if (value === '' || value === null) {
          return;
        }
        if (this.$value.is('select[multiple]')) {
          value = (function() {
            var _i, _len, _results;
            _results = [];
            for (_i = 0, _len = value.length; _i < _len; _i++) {
              val = value[_i];
              _results.push(this.coerceValue(val));
            }
            return _results;
          }).call(this);
        } else {
          value = this.coerceValue(value);
        }
      }
      return value;
    };

    Control.prototype.getOperator = function(options) {
      var operator;
      if (options == null) {
        options = {};
      }
      operator = this.$operator.val();
      if (options.negated && NEGATION_OPERATORS[operator]) {
        operator = NEGATION_OPERATORS[operator];
      }
      return operator;
    };

    Control.prototype.setValue = function(value) {
      if (value == null) {
        value = null;
      }
      if (this.$value.is('[type=checkbox],[type=radio]')) {
        return this.$value.prop('checked', value);
      } else {
        return this.$value.val(value);
      }
    };

    Control.prototype.setOperator = function(value) {
      this.$operator.val(value);
      return this.toggleOperator();
    };

    Control.prototype.get = function(options) {
      return {
        id: this.model.id,
        operator: this.getOperator(options),
        value: this.getValue(options)
      };
    };

    Control.prototype.set = function(node) {
      var operator, value;
      node = node || this.node;
      if (!node) {
        return;
      }
      this.node = node;
      value = this.node.get('value');
      operator = this.node.get('operator');
      if (/^-/.test(operator)) {
        operator = operator.substr(1);
      }
      this.setOperator(operator);
      this.setValue(value);
      return this.$remove.show();
    };

    Control.prototype.submit = function(data) {
      var message;
      if (data == null) {
        data = {};
      }
      if (data.value === void 0) {
        if (this.node) {
          this.setOperator();
          this.setValue();
          mediator.publish(Serrano.DATACONTEXT_REMOVE, this.node);
          delete this.node;
          this.$remove.hide();
        }
        return;
      }
      if ((message = this.validate(data))) {
        this.trigger('error', message);
        return;
      }
      if (this.node) {
        this.node.set(data);
      } else {
        this.node = new Serrano.DataContextNode(data);
      }
      mediator.publish(Serrano.DATACONTEXT_ADD, this.node);
      return this.$remove.show();
    };

    return Control;

  })(Backbone.View);
  _.extend(Control.prototype, Backbone.Events);
  NumberControl = (function(_super) {

    __extends(NumberControl, _super);

    function NumberControl() {
      return NumberControl.__super__.constructor.apply(this, arguments);
    }

    NumberControl.prototype.template = _.template('\
            <div class=control-group>\
                <h4 class=control-label>{{ label }} <small class=units>({{ units }})</small></h4>\
                <div class=controls>\
                    <select class=span4 name=operator></select>\
                    <input class=span4 type=text name=value>\
                    <input class=span4 type=text name=value-2>\
                    <p class=help-block>{{ help }}</p>\
                </div>\
            </div>\
        ');

    NumberControl.prototype.render = function() {
      NumberControl.__super__.render.apply(this, arguments);
      this.$value2 = this.$('[name=value-2]').hide();
      return this.$el;
    };

    NumberControl.prototype.getValue = function(options) {
      var value, value2;
      if (!(value = NumberControl.__super__.getValue.apply(this, arguments))) {
        return;
      }
      if (/range/.test(this.getOperator())) {
        value2 = this.coerceValue(this.$value2.val());
        return [value, value2];
      } else {
        return value;
      }
    };

    NumberControl.prototype.setValue = function(value) {
      if (value == null) {
        value = null;
      }
      if (/range/.test(this.getOperator())) {
        this.$value.val(value[0]);
        return this.$value2.val(value[1]).show();
      } else {
        return this.$value.val(value);
      }
    };

    NumberControl.prototype.toggleOperator = function() {
      NumberControl.__super__.toggleOperator.apply(this, arguments);
      if (/range/.test(this.getOperator())) {
        return this.$value2.show();
      } else {
        return this.$value2.hide();
      }
    };

    return NumberControl;

  })(Control);
  placeholderText = function(values, parse) {
    var examples, i, idx, indexes, len, value, _i, _ref;
    len = Math.max(values.length - 1, 0);
    if (!len) {
      return;
    }
    examples = [];
    indexes = [];
    for (i = _i = 0, _ref = Math.min(3, len); 0 <= _ref ? _i <= _ref : _i >= _ref; i = 0 <= _ref ? ++_i : --_i) {
      idx = parseInt(Math.random() * len);
      if (indexes.indexOf(idx) === -1) {
        indexes.push(idx);
        if ((value = parse(values[idx]))) {
          examples.push(value);
        }
      }
    }
    return "e.g. " + (examples.join(', '));
  };
  EnumerableControl = (function(_super) {

    __extends(EnumerableControl, _super);

    function EnumerableControl() {
      this.loadValues = __bind(this.loadValues, this);

      this.loadOperators = __bind(this.loadOperators, this);
      return EnumerableControl.__super__.constructor.apply(this, arguments);
    }

    EnumerableControl.prototype.template = _.template('\
            <div class=control-group>\
                <h4 class=control-label>{{ label }} <small class=units>({{ units }})</small></h4>\
                <div class=controls>\
                    <select class=span4 name=operator></select>\
                    <div class="input-prepend">\
                        <span class=add-on><i class=icon-search></i></span><input type=text name=value autocomplete=off>\
                    </div>\
                    <p class=help-block>{{ help }}</p>\
                </div>\
            </div>\
        ');

    EnumerableControl.prototype.initialize = function(options) {
      return EnumerableControl.__super__.initialize.apply(this, arguments);
    };

    EnumerableControl.prototype.setValue = function(value) {
      if (value) {
        return this.$value.val(value.join(', '));
      }
    };

    EnumerableControl.prototype.getValue = function() {
      var data, val, values;
      data = this.$value.data('typeahead');
      values = (function() {
        var _i, _len, _ref, _results;
        _ref = data.selections;
        _results = [];
        for (_i = 0, _len = _ref.length; _i < _len; _i++) {
          val = _ref[_i];
          _results.push(this.coerceValue(data.parse(val)));
        }
        return _results;
      }).call(this);
      if (!values.length) {
        return;
      }
      return values;
    };

    EnumerableControl.prototype.loadOperators = function() {
      EnumerableControl.__super__.loadOperators.apply(this, arguments);
      return this.$operator.val('in').hide();
    };

    EnumerableControl.prototype.loadValues = function() {
      var typeahead,
        _this = this;
      this.$value.typeahead({
        mode: 'multiple'
      });
      typeahead = this.$value.data('typeahead');
      return Backbone.ajax({
        url: this.model.get('_links').values.href,
        beforeSend: function() {
          return typeahead.$menu.addClass('loading');
        },
        success: function(resp) {
          var text;
          typeahead.source = resp;
          typeahead.$menu.removeClass('loading');
          _this.set();
          if ((text = placeholderText(resp, function(x) {
            return x.value;
          }))) {
            return _this.$value.attr('placeholder', text);
          }
        }
      });
    };

    return EnumerableControl;

  })(Control);
  SearchableControl = (function(_super) {

    __extends(SearchableControl, _super);

    function SearchableControl() {
      this.loadValues = __bind(this.loadValues, this);
      return SearchableControl.__super__.constructor.apply(this, arguments);
    }

    SearchableControl.prototype.loadValues = function() {
      var lastQuery, url,
        _this = this;
      this.set();
      url = this.model.get('_links').values.href;
      lastQuery = null;
      Backbone.ajax({
        url: "" + url + "?random=3",
        success: function(resp) {
          var text;
          if ((text = placeholderText(resp, function(x) {
            return x.value;
          }))) {
            return _this.$value.attr('placeholder', text);
          }
        }
      });
      return this.$value.typeahead({
        mode: 'multiple',
        items: 20,
        source: _.debounce(function(query, typeahead) {
          if (query === lastQuery) {
            return;
          }
          typeahead.show().$menu.addClass('loading');
          _this.$value.prop('disabled', true);
          Backbone.ajax({
            url: "" + url + "?query=" + query,
            success: function(resp) {
              lastQuery = query;
              typeahead.$menu.removeClass('loading');
              typeahead.process(resp);
              return _this.$value.prop('disabled', false);
            }
          });
        }, 500)
      });
    };

    return SearchableControl;

  })(EnumerableControl);
  BooleanControl = (function(_super) {

    __extends(BooleanControl, _super);

    function BooleanControl() {
      return BooleanControl.__super__.constructor.apply(this, arguments);
    }

    BooleanControl.prototype.template = _.template('\
            <div class=control-group>\
                <h4 class=control-label>{{ label }} <small class=units>({{ units }})</small></h4>\
                <div class=controls>\
                    <select class=span4 name=operator></select>\
                    <select class=span4 name=value>\
                        <option value=>---</option>\
                    </select>\
                    <p class=help-block>{{ help }}</p>\
                </div>\
            </div>\
        ');

    BooleanControl.prototype.loadOperators = function() {
      BooleanControl.__super__.loadOperators.apply(this, arguments);
      return this.$operator.val('exact').hide();
    };

    BooleanControl.prototype.loadValues = function() {
      var _this = this;
      this.$value.addClass('loading');
      return Backbone.ajax({
        url: this.model.get('_links').values.href,
        success: function(resp) {
          var option, _i, _len;
          _this.$value.removeClass('loading');
          for (_i = 0, _len = resp.length; _i < _len; _i++) {
            option = resp[_i];
            _this.$value.append("<option value=\"" + option.value + "\">" + option.label + "</option>");
          }
          return _this.set();
        }
      });
    };

    return BooleanControl;

  })(Control);
  return {
    Control: Control,
    NumberControl: NumberControl,
    EnumerableControl: EnumerableControl,
    SearchableControl: SearchableControl,
    BooleanControl: BooleanControl
  };
});
