var AccountInfo = Class.create({
  initialize: function(elem) {
    this.orders = elem.down('div.orders');
    this.html_orders_count = elem.down('span.orders_count');
    this.html_order_items_count = elem.down('span.order_items_count');
    elem.down('div.info a').observe('mouseover', this.show.bindAsEventListener(this));
    this.hideBound = this.hide.bindAsEventListener(this);
  },

  hide: function(event) {
    this.orders.hide();
    $(document.body).stopObserving('click', this.hideBound);
  },

  orderItemCount: function(count) {
    if (count == undefined) return;
    var text = count + ' item' + (count == 1 ? '' : 's');
    this.html_order_items_count.update(text);
    new Effect.Highlight(this.html_order_items_count, { endcolor: '#FFFFFF', restorecolor: '#FFFFFF', startcolor: '#FFFF99' });
  },

  ordersCount: function(count) {
    if (count == undefined) return;
    var text = count + ' order' + (count == 1 ? '' : 's');
    this.html_orders_count.update(text);
    new Effect.Highlight(this.html_orders_count, { endcolor: '#FFFFFF', restorecolor: '#FFFFFF', startcolor: '#FFFF99' });
  },

  ordersTable: function(content) {
    this.orders.update(content);
  },

  show: function(event) {
    event.stop();
    this.orders.show();
    $(document.body).observe('click', this.hideBound);
  }
});

Object.extend(AccountInfo, {
  init: function() {
    if (!this.account_info) this.account_info = new AccountInfo($('account_info'));
    return this.account_info;
  },

  orderItemCount: function(count) {
    this.init().orderItemCount(count);
  },

  ordersCount: function(count) {
    this.init().ordersCount(count);
  },

  ordersTable: function(content) {
    this.init().ordersTable(content);
  }
});


var AccountSelector = Class.create({
  accounts: [],
  elems: [],
  highlighted: null,
  loaded: false,
  q: '',
  selected: null,
  template: new Template('<tr><td><a rel="#{index}"></a>#{uid}</td><td>#{name}</td><td>#{postcode}</td></tr>'),

  initialize: function() {
    $(document.body).insert('<div id="account_selector_container"><div id="account_selector"><input name="q" type="text" autocomplete="off" /><div><table></table></div><p class="cancel"><span>Cancel</span></p></div></div>');
    this.overlay = $('account_selector_container');
    this.table = this.overlay.down('table');
    this.input = this.overlay.down('input');
    this.input.observe('keyup', this.filter.bindAsEventListener(this));
    this.overlay.down('p.cancel span').observe('click', this.hide.bindAsEventListener(this));
    this.load();
  },

  center: function(elem) {
    var div = this.table.up();
    var root = div.cumulativeOffset()[1];
    var h = div.getHeight() / 2;
    var row = elem.getHeight();
    var y = elem.cumulativeOffset()[1] - root + row;
    div.scrollTop = y - h;
  },

  down: function() {
    if (this.highlighted == null) {
      this.highlight(this.elems.detect(function(elem) { return elem.visible(); }));
    } else {
      var next = this.highlighted.nextSiblings().detect(function(elem) { return elem.visible(); });
      if (next) this.highlight(next);
    }
  },

  filter: function(event) {
    var q = this.input.value.toLowerCase().strip();
    if (q == this.q) return;
    if (![38, 40].include(event.keyCode)) this.highlight();
    if (q.blank()) {
      this.elems.invoke('show');
    } else {
      this.table.scrollTop = 0;
      var subs = q.split(/\W+/);
      var account, elem, s, matches;
      for (var i = 0; i < this.accounts.length; i++) {
        account = this.accounts[i];
        elem = this.elems[account.index];
        matches = 0;
        for (s = 0; s < subs.length; s++) {
          if (account._index.include(subs[s])) matches++;
        }
        matches == subs.length ? elem.show() : elem.hide();
      }
    }
    this.q = q;
    cycle(this.elems);
  },

  hide: function() {
    shortcut.remove('Esc');
    shortcut.remove('Down');
    shortcut.remove('Up');
    shortcut.remove('Enter');
    this.overlay.hide();
  },

  highlight: function(elem) {
    if (this.highlighted) this.highlighted.removeClassName('highlighted');
    if (elem) {
      this.highlighted = elem;
      this.highlighted.addClassName('highlighted');
      this.center(this.highlighted);
    } else {
      this.highlighted = null;
    }
  },

  load: function() {
    new Ajax.Request(AccountSelector.href, { method: 'get',
      onSuccess: this.onData.bind(this)
    });
  },

  onData: function(response) {
    var json = response.responseJSON;
    this.loaded = true;
    this.accounts = json.accounts;
    this.accounts.each(function(account, index) {
      account.index = index;
      account._index = [
        account.name.toLowerCase(),
        account.postcode.toLowerCase(),
        account.uid.toLowerCase()
      ].join(' ');
    });
    this.table.update(this.accounts.map(function(account) {
      return this.template.evaluate(account);
    }, this).join(''));
    this.elems = this.table.select('tr');
    this.elems.each(function(elem) {
      elem.observe('click', function(event) { this.select(elem); }.bind(this))
    }.bind(this));
    this.selected = this.elems[this.accounts.detect(function(account) {
      return account.id == json.selected;
    }).index];
    if (this.selected) {
      this.selected.addClassName('selected');
      this.center(this.selected);
    }
    cycle(this.elems);
  },

  // Overwrite with your own function.
  onSelect: function(id) {},

  select: function(elem) {
    if (elem) {
      var index = elem.down('a').rel;
      this.onSelect(this.accounts[index].id);
    }
  },

  show: function() {
    this.overlay.show();
    this.input.focus();
    shortcut.add('Esc', this.hide.bind(this));
    shortcut.add('Up', this.up.bind(this));
    shortcut.add('Down', this.down.bind(this));
    shortcut.add('Enter', function() {
      this.select(this.highlighted);
    }.bind(this));
    if (this.loaded) this.center(this.selected);
  },

  up: function() {
    if (this.highlighted != null) {
      var prev = this.highlighted.previousSiblings().detect(function(elem) { return elem.visible(); });
      if (prev) this.highlight(prev);
    }
  }
});

Object.extend(AccountSelector, {
  account_selector: false, href: '/accounts',

  select_account: function(id) {
    new Ajax.Request('/accounts/' + id + '/select', { method: 'post',
      asynchronous: false, parameters: { authenticity_token: AUTH_TOKEN },
      onComplete: function(response) {
        var url = response.getHeader('Location');
        if (url) location.replace(url);
      }
    });
  },

  show: function(callback) {
    if (!this.account_selector) this.account_selector = new AccountSelector();
    AccountSelector.addMethods({ onSelect: callback || this.select_account });
    this.account_selector.show();
  }
});


var OrderItemTable = Class.create({
  initialize: function(table, totals) {
    this.table = table;
    this.rows = [];
    this.table.select('tbody tr').each(function(tr) {
      if (!tr.hasClassName('grouping')) {
        this.rows.push(new OrderItemTableRow(this, tr));
      }
    }.bind(this));
    this.totals = totals;
  },

  refeshAlternateRows: function() {
    cycle(this.table.select('tbody tr'));
  },

  removeEmptyGroupings: function() {
    var sibling;
    this.table.select('tbody tr.grouping').each(function(elem) {
      sibling = elem.next();
      if (sibling == undefined || sibling.match('tr.grouping')) {
        elem.remove();
      }
    });
  },

  updateTotals: function(hash) {
    this.totals.down('p.total span').update(hash.order_total);
    this.totals.down('p.vat span').update(hash.order_tax);
    this.totals.down('p.inc_vat span').update(hash.order_total_inc_tax);
    AccountInfo.orderItemCount(hash.order_items_count);
  }
});

var OrderItemTableRow = Class.create({
  initialize: function(table, tr) {
    this.table = table;
    this.tr = tr;
    this.update_input = this.tr.down('form.order_item_packs input[name="order_item[packs]"]');
    this.update_input.observe('change', this.update.bindAsEventListener(this));
    this.update_form = this.update_input.form;
    this.update_form.observe('submit', this.update.bindAsEventListener(this));
    this.remove_form = this.tr.down('form.remove_from_order');
    this.remove_form.observe('submit', this.remove.bindAsEventListener(this));
  },

  onRemove: function(response) {
    this.table.updateTotals(response.responseJSON);
  },

  onUpdate: function(response) {
    var json = response.responseJSON;
    this.tr.down('td.quantity').update(json.quantity);
    this.tr.down('td.price').update(json.price);
    this.table.updateTotals(json);
  },

  remove: function(event) {
    event.stop();
    this.remove_form.request({ onSuccess: this.onRemove.bind(this) });
    this.tr.remove();
    this.table.removeEmptyGroupings();
    this.table.refeshAlternateRows();
  },

  update: function(event) {
    event.stop();
    this.update_form.request({ onComplete: this.onUpdate.bind(this) });
  }
});


var QuickOrder = Class.create({
  initialize: function(form) {
    this.form = $(form);
    this.form.observe('submit', this.submit.bindAsEventListener(this));
    this.sku = this.form.down('input[name=sku]');
    this.sku.focus();
    this.form.insert({ bottom: '<div class="message"></div>' });
    this.message = this.form.down('div.message');
    this.message.hide();
  },

  messageFade: function() {
    clearInterval(this.timer);
    this.timer = null;
    this.message.fade({ duration: 0.5 });
  },

  notFound: function(q) {
    this.message.show();
    this.message.update("Couldn't find <em>\"#{q}\"</em>.".interpolate({ q: escape(q) }));
    clearInterval(this.timer);
    this.timer = setInterval(this.messageFade.bind(this), 2000);
  },

  onComplete: function(response) {
    if (Ajax.activeRequestCount == 1) this.form.removeClassName('spinner');
    if (response.status == 404) {
      this.notFound(response.responseText);
    } else {
      this.removeEmptyMessage();
    }
  },

  removeEmptyMessage: function() {
    var elem = $("products").down("tr.empty_message");
    if (elem) elem.remove();
  },

  submit: function(event) {
    event.stop();
    if (this.sku.value.strip().blank()) {
      return;
    } else {
      this.form.addClassName('spinner');
      this.form.request({ onComplete: this.onComplete.bind(this) });
    }
    this.sku.clear();
    this.sku.focus();
  }
});


var Tabbable = Class.create({
  initialize: function(container) {
    this.container = $(container);
    this.modules   = [];
    this.tabs      = [];
    this.selected  = null;

    var template = new Template('<li><a id="#{id}" href="##{anchor}">#{title}</a></li>');
    var id = this.container.id + '_tabs';
    var lis = [];

    // Collect tabbable modules
    this.container.select('div.tabbable').each(function(module, index) {
      // Get module id or assign one
      module.id = module.id || this.container.id + index;

      tab = module.down('.ti');
      tab.hide();
      lis.push(template.evaluate( { anchor: module.id,
                                    id: this.container.id + 't' + index,
                                    title: tab.innerHTML } ));

      module.hide();
      module.addClassName('tabbed');
      this.modules.push(module);
    }.bind(this));

    if (this.modules.length == 0) return;

    // Insert tabs into DOM
    this.container.insert({ top: '<ul id="#{id}" class="tabs">#{lis}</ul>'.interpolate({ id: id, lis: lis.join('') }) });

    // Collect tab elements
    $(id).childElements().each(function(tab) {
      this.tabs.push(tab);
      tab.observe('click', this.onClickTab.bindAsEventListener(this));
    }.bind(this));

    // Default to show first tab
    var selected = 0;
    var hash = location.hash.substr(1);

    if (hash) {
      // A hash exists, if it matches a tab select it
      this.modules.each(function(module, index) {
        if (hash == module.id) {
          selected = index;
          throw $break;
        }
      });
    }

    this.select(selected);
  },

  onClickTab: function(event) {
    event.stop();
    this.select(event.element().id.match(/\d+$/));
    return false;
  },

  select: function(index) {
    if (this.selected != null) {
      this.modules[this.selected].hide();
      this.tabs[this.selected].removeClassName('selected');
    }
    this.modules[index].show();
    this.tabs[index].addClassName('selected');
    this.selected = index;
  }
});
