text: /*global jQuery, HDO, Handlebars */
  
  (function ($, HDO, Handlebars) {
      HDO.issueEditor = {
          create: function (opts) {
              var instance = Object.create(this);
              instance.root = $(opts.root);
              instance.url = opts.url;
              instance.issueId = opts.id;
  
              return instance;
          },
  
          init: function () {
              this.setupTemplates();
              this.renderForm();
  
              HDO.markdownEditor();
  
              this.form                  = $('form.edit_issue, form.new_issue');
              this.saveButton            = this.root.find('button[name=save]');
              this.editorSelect          = this.root.find('select#issue_editor_id');
              this.categorySelect        = this.root.find('select#issue_category_ids');
              this.positionPartySelects  = this.root.find('select.position-parties');
              this.newPositionButton     = this.root.find('#new-position');
              this.newPartyCommentButton = this.root.find('#new-party-comment');
              this.tagList               = this.root.find('input[name=tags]');
              this.promiseSearchTab      = this.root.find('#promise-search-tab');
              this.promiseSpinner        = this.root.find('#promise-spinner');
              this.propositionConnectTab = this.root.find('#proposition-connections-tab');
              this.propositionSearchTab  = this.root.find('#proposition-search-tab');
              this.propositionSpinner    = this.root.find('#proposition-spinner');
              this.errorElement          = this.root.find('.error-message');
  
              this.saveButton.click(this.save.bind(this));
              this.newPositionButton.click(this.newPosition.bind(this));
              this.newPartyCommentButton.click(this.newPartyComment.bind(this));
              this.root.delegate('[data-expands]', 'click', this.toggleRow.bind(this));
  
              this.editorSelect.chosen();
              this.categorySelect.chosen();
              this.positionPartySelects.chosen();
  
              this.root.find('.position-form').hide();
              this.root.delegate('.position-remove', 'click', this.removePosition.bind(this));
  
              this.setupTagList();
              this.setupCarts();
  
              this.facetSearch({
                  baseUrl:  '/promises',
                  root:     this.promiseSearchTab,
                  spinner:  this.promiseSpinner,
                  template: this.templates['promise-search-template'],
                  cart:     this.promiseCart,
                  issueId:  this.issueId
              });
  
              this.facetSearch({
                  baseUrl:  '/propositions',
                  root:     this.propositionSearchTab,
                  spinner:  this.propositionSpinner,
                  template: this.templates['proposition-search-template'],
                  cart:     this.propositionCart,
                  issueId:  this.issueId
              });
          },
  
          save: function (e) {
              e.preventDefault();
              this.toggleSpin();
  
              var self, currentSection;
  
              self = this;
              currentSection = this.root.find('.in').data('key');
  
              $.ajax({
                  url: this.url,
                  method: 'POST',
                  data: this.form.serialize(),
                  success: function (data) {
                      // trololol
                      window.location.href = currentSection ?
                          data.location + ('?section=' + encodeURIComponent(currentSection)) : data.location;
                  },
                  error: function (xhr) {
                      self.toggleSpin();
                      self.errorElement.html(xhr.responseText).show();
                  }
              });
          },
  
          toggleSpin: function () {
              this.root.find('.accordion-group').toggle();
              $('#spinner').toggle();
          },
  
          newPosition: function (e) {
              e.preventDefault();
  
              var position, created, template;
              this.newPositionId = this.newPositionId || 0;
  
              position = {
                  id: --this.newPositionId,
                  party_ids: [],
                  priority: 0
              };
  
              template = this.templates['position-template'];
  
              created = $(template(position)).prependTo('.positions');
              created.addClass('new');
              created.find('.expandable, .expanded').toggleClass('expandable expanded');
              created.find('.position-parties').chosen();
  
              HDO.markdownEditor({root: created});
          },
  
          newPartyComment: function (e) {
              e.preventDefault();
  
              var comment, created, template;
  
              this.newPartyCommentId = this.newPartyCommentId || 0;
  
              comment = {
                  id: --this.newPartyCommentId
              };
  
              template = this.templates['party-comment-template'];
              created = $(template(comment)).prependTo('.party-comments');
              created.addClass('new');
  
              HDO.markdownEditor({root: created});
          },
  
          removePosition: function (e) {
              e.preventDefault();
  
              var target  = $(e.target),
                  id        = target.data('id'),
                  parties   = target.data('parties'),
                  title     = target.data('title'),
                  container = target.closest('.position');
  
              container.html('<del>' + parties + '<strong>' + title + '</strong>' + '</del>');
              container.append(
                  $('<input/>')
                      .attr('type', 'hidden')
                      .attr('name', 'positions[' + id + '][deleted]')
                      .val('true')
              );
          },
  
          setupTagList: function () {
              var el = this.tagList;
              el.tagsManager({
                  prefilled: el.data('current-tags').split(','),
                  preventSubmitOnEnter: true,
                  typeahead: true,
                  typeaheadSource: el.data('all-tags').split(','),
                  hiddenTagListName: 'issue[tag_list]'
              });
          },
  
          setupTemplates: function () {
              var templates;
              this.templates = templates = {};
  
              $('script[type="text/x-handlebars-template"]').each(function () {
                  var el, name, partialName;
  
                  el = $(this);
                  name = el.data('name');
                  partialName = name.match(/^(\w+?)-partial$/);
                  partialName = partialName && partialName[1];
  
                  if (partialName) {
                      Handlebars.registerPartial(partialName, el.html());
                  } else {
                      templates[name] = Handlebars.compile(el.html());
                  }
              });
  
              Handlebars.registerHelper('selectedIfEqual', function (a, b) {
                  return a === b && 'selected';
              });
  
              Handlebars.registerHelper('selectedIfInclude', function (a, b) {
                  if (b.indexOf(a) !== -1) {
                      return 'selected';
                  }
              });
          },
  
          // TODO: get rid of all the duplication
          setupCarts: function () {
              var toggleRow, promiseTemplate, propositionTemplate;
  
              this.promiseCart = this.createCart($('.cart[data-type=promises]'));
              this.propositionCart = this.createCart($('.cart[data-type=propositions]'));
  
              toggleRow = this.toggleRow;
              promiseTemplate = this.templates['promise-connection-template'];
              propositionTemplate = this.templates['proposition-connection-template'];
  
              this.promiseCart.on('use', function (items) {
                  if (items.length === 0) {
                      return;
                  }
  
                  $('a[href=#promise-connections-tab]').click();
  
                  $.ajax({
                      url: '/admin/issues/promises/' + items.join(','),
                      dataType: 'json',
                      success: function (data) {
                          $.each(data, function () {
                              this.status = 'related';
                              var created = $(promiseTemplate(this)).prependTo('#promise-connections-tab');
                              created.addClass('new');
                          });
                      },
                      error: function (xhr) {
                          window.alert('Uffda, noe gikk helt galt ' + xhr.status);
                      },
                      complete: function () {
                          // TODO: spinner
                      }
                  });
              });
  
              this.propositionCart.on('use', function (items) {
                  if (items.length === 0) {
                      return;
                  }
  
                  $('a[href=#proposition-connections-tab]').click();
  
                  $.ajax({
                      url: '/admin/issues/propositions/' + items.join(','),
                      dataType: 'json',
                      success: function (data) {
                          $.each(data, function () {
                              var created = $(propositionTemplate(this)).prependTo('#proposition-connections-tab');
                              created.addClass('new');
                              HDO.markdownEditor({root: created});
                          });
                      },
                      error: function (xhr) {
                          window.alert('Uffda, noe gikk helt galt ' + xhr.status);
                      },
                      complete: function () {
                          // TODO: spinner
                      }
                  });
              });
          },
  
          toggleRow: function (e) {
              var target, el;
  
              target = $(e.target);
  
              if (target.hasClass('permalink') || e.originalEvent.defaultPrevented) {
                  return;
              }
  
              el = target.parents('.row-fluid:first');
              el.find('.expandable, .expanded').toggleClass('expandable expanded');
              $(el.data('expands')).slideToggle('fast');
          },
  
          notImplemented: function (e) {
              e.preventDefault();
              window.alert('ikke enda');
          },
  
          renderForm: function () {
              function render(template, i, e) {
                  var el = $(e);
                  el.html(template(el.data('context')));
              }
  
              $('.proposition-connection').each(render.bind(null, this.templates['proposition-connection-template']));
              $('.promise-connection').each(render.bind(null, this.templates['promise-connection-template']));
              $('.position').each(render.bind(null, this.templates['position-template']));
          },
  
          facetSearch: function (opts) {
              var baseUrl, root, template, spinner, query, cart, issueId;
  
              baseUrl  = opts.baseUrl;
              root     = opts.root;
              template = opts.template;
              spinner  = opts.spinner || $('#spinner');
              query    = opts.root.find('input[name=q]');
              cart     = opts.cart;
              issueId  = opts.issueId;
  
              function prepareData(data) {
                  $.each(data.results, function (i, e) {
                      e.selected = cart.isSelected(Number(e.id));
                      e.connected = e.issue_ids.indexOf(issueId) !== -1;
                  });
  
                  return data;
              }
  
              function render(url) {
                  spinner.toggleClass('hidden');
  
                  $.ajax({
                      url: url || baseUrl,
                      dataType: 'json',
                      success: function (data) { root.html(template(prepareData(data))); },
                      error: function (xhr) { window.alert('Uffda, noe gikk helt galt ' + xhr.status); },
                      complete: function () { spinner.toggleClass('hidden'); }
                  });
              }
  
              function filterHandler(e) {
                  e.preventDefault();
                  render(e.target.href);
              }
  
              function queryHandler(e) {
                  if (e.which === 13) {
                      e.preventDefault();
  
                      var target = $(this),
                          url = decodeURI(target.data('url-template'));
  
                      url = url.replace('{query}', encodeURIComponent(target.val()));
                      render(url);
                  }
              }
  
              function toggleResult() {
                  var el = $(this), id;
  
                  if (el.hasClass('connected')) {
                      return;
                  }
  
                  id = el.data('id');
                  el.toggleClass('selected');
  
                  if (el.hasClass('selected')) {
                      cart.add(id);
                  } else {
                      cart.remove(id);
                  }
              }
  
              cart.on('clear', function () {
                  root.find('.search-result.selected').removeClass('selected');
              });
  
              root.delegate('.navigators a, a[data-xhr]', 'click', filterHandler);
              root.delegate('input[name=q]', 'keypress', queryHandler);
              root.delegate('.search-result', 'click', toggleResult);
  
              render();
          },
  
          createCart: function (el) {
              var items, template, callbacks;
  
              items = [];
              template = this.templates['shopping-cart-template'];
              callbacks = {clear: [], use: []};
  
              function invokeCallbacks(type) {
                  $(callbacks[type]).each(function (i, cb) {
                      cb(items);
                  });
              }
  
              function render() {
                  el.html(template({items: items}));
              }
  
              function isSelected(id) {
                  return items.indexOf(id) !== -1;
              }
  
              function add(id) {
                  items.push(id);
                  render();
              }
  
              function remove(id) {
                  var idx = items.indexOf(id);
                  if (idx > -1) {
                      items.splice(idx, 1);
                      render();
                  }
              }
  
              function clear() {
                  items = [];
                  invokeCallbacks('clear');
                  render();
              }
  
              function use() {
                  invokeCallbacks('use');
                  clear();
              }
  
              function addCallback(type, cb) {
                  if (typeof cb !== 'function') {
                      throw new TypeError('expected function, got ' + typeof cb);
                  }
  
                  if (Object.keys(callbacks).indexOf(type) === -1) {
                      throw new Error('invalid callback type ' + type);
                  }
  
                  callbacks[type].push(cb);
              }
  
              el.delegate('a[data-action=use]', 'click', function (e) {
                  e.preventDefault();
                  use();
              });
  
              el.delegate('a[data-action=clear]', 'click', function (e) {
                  e.preventDefault();
                  clear();
              });
  
              render();
  
              return {
                  isSelected: isSelected,
                  add: add,
                  remove: remove,
                  on: addCallback
              };
          }
  
      };
  }(jQuery, HDO, Handlebars));
  