/**
 * Grocerus list quickadd.
 */

YAHOO.namespace( "views" );

/**
 * A list object that caches a price list generated from a grocery list.
 */
YAHOO.views.PriceList = function(listelm) {
  this.completelist_ = {};
  this.incompletelist_ = {};
  this.hasAnyCompleteItems_ = undefined;
  this.hasAnyIncompleteItems_ = undefined;
  this.listelm_ = listelm;

  this.divprefix_ = 'pricelistitem';
}

/**
 * Fires off the required requests to update this list from an array of categories.
 */
YAHOO.views.PriceList.prototype.fire_request = function(list) {
  if( list.length > 0 ) {
    $('bystorecol').style.visibility = 'visible';
    if( this.transaction_ ) {
      YAHOO.util.Connect.abort(this.transaction_)
    }
    this.transaction_ =
      YAHOO.util.Connect.asyncRequest('POST',
        req_price_list_by_store, this.notify(), 'list=' + list);
  } else {
    $('bystorecol').style.visibility = 'hidden';
    this.listelm_.innerHTML = '';
  }
};

/**
 * @return an object that can receive the result of the asynchronous request for the price list.
 */
YAHOO.views.PriceList.prototype.notify = function() {
  return {
    success: function(o) {
      var result = YAHOO.lang.JSON.parse(o.responseText);

      this.completelist_ = {};
      this.incompletelist_ = {};
      this.hasAnyCompleteItems_ = false;
      this.hasAnyIncompleteItems_ = false;

      if( result.valid ) {
        for( var index in result.complete ) {
          var item = result.complete[index];
          var id = this.divprefix_ + item.id;
          this.completelist_[id] = new YAHOO.views.PriceList.Item(item, id, this);
        }
        if( result.complete.length > 0 ) {
          this.hasAnyCompleteItems_ = true;
        }

        for( var index in result.incomplete ) {
          var item = result.incomplete[index];
          var id = this.divprefix_ + item.id;
          this.incompletelist_[id] = new YAHOO.views.PriceList.Item(item, id, this);
        }
        if( result.incomplete.length > 0 ) {
          this.hasAnyIncompleteItems_ = true;
        }
      }
      this.update();
      delete this.transaction_;
    },

    failure: function(o) {
      delete this.transaction_;
    },

    scope: this
  };
};

/**
 * Update the list UI.
 */
YAHOO.views.PriceList.prototype.update = function() {
  if( !this.hasAnyCompleteItems_ && !this.hasAnyIncompleteItems_ ) {
    this.listelm_.innerHTML = '<b>It seems we can\'t construct a list from those items.</b>'
  } else {
    this.listelm_.innerHTML = '';
    if( this.hasAnyCompleteItems_ ) {
      var ranking = 1;
      for( var index in this.completelist_ ) {
        var item = this.completelist_[index];
        this.listelm_.appendChild(item.as_html_element(ranking++));
      }
    }
    if( this.hasAnyIncompleteItems_ ) {
      this.listelm_.innerHTML += '<h2 class="incomplete">Incomplete lists</h2>';
      var ranking = 1;
      for( var index in this.incompletelist_ ) {
        var item = this.incompletelist_[index];
        this.listelm_.appendChild(item.as_html_element(ranking++));
      }
    }
  }
};

/**
 * A list item object that caches a price list item generated from a grocery list.
 */
YAHOO.views.PriceList.Item = function(item, id, list) {
  this.store_ = {
    id: item.id,
    name: item.name,
    address: item.address
  };
  this.categories_ = item.categories;
  this.sumprice_ = item.sumprice;
  this.id_ = id;
  this.parentlist_ = list;
};

/**
 * Shutdown the item by cancelling any active transactions.
 */
YAHOO.views.PriceList.Item.prototype.shutdown = function() {
};

/**
 * Create an HTML Element out of this item.
 */
YAHOO.views.PriceList.Item.prototype.as_html_element = function(ranking) {
  var itemElm = new YAHOO.util.Element(document.createElement('div'),
    { id: this.id_ }
  );
  itemElm.addClass('item');

  var rankingElm = new YAHOO.util.Element(document.createElement('div'),
    { innerHTML: '#' + ranking }
  );
  rankingElm.addClass('ranking');
  rankingElm.addClass('place' + ranking);

  var sumPriceElm = new YAHOO.util.Element(document.createElement('span'),
    { innerHTML: '$' + this.sumprice_ }
  );
  sumPriceElm.addClass('totalprice');
  rankingElm.appendChild(document.createElement('br'));
  rankingElm.appendChild(sumPriceElm);

  var contentElm = new YAHOO.util.Element(document.createElement('div'));
  contentElm.addClass('content');

  var nameElm;
  if( groc_ui_iphone ) {
    nameElm = new YAHOO.util.Element(document.createElement('span'),
      { innerHTML: this.store_.name }
    );
  } else {
    nameElm = new YAHOO.util.Element(document.createElement('a'),
      { href: groc_root_url + 'store/' + this.store_.id,
        innerHTML: this.store_.name }
    );
  }
  nameElm.addClass('store');

  var addressElm = new YAHOO.util.Element(document.createElement('span'),
    { innerHTML: this.store_.address }
  );
  addressElm.addClass('address');

  itemElm.appendChild(rankingElm);
  contentElm.appendChild(nameElm);
  contentElm.appendChild(document.createElement('br'));
  contentElm.appendChild(addressElm);
  contentElm.appendChild(document.createElement('hr'));

  for( var index in this.categories_ ) {
    var category = this.categories_[index];
    var categoryElm = new YAHOO.util.Element(document.createElement('div'));

    var nameElm = new YAHOO.util.Element(document.createElement('span'),
      { innerHTML: ' of ' + category.name }
    );
    nameElm.addClass('name');

    var priceElm = new YAHOO.util.Element(document.createElement('span'),
      { innerHTML: (category.count > 1 ? category.count + ' for ' : '') + '$' + category.price }
    );
    priceElm.addClass('price');

    var ratioElm = new YAHOO.util.Element(document.createElement('span'),
      { innerHTML: ' ($' + category.ratio + '/' + category.ratiotype + ')' }
    );
    ratioElm.addClass('ratio');

    var sizeElm = new YAHOO.util.Element(document.createElement('span'),
      { innerHTML: ' - ' + category.quantity + ' ' + category.type }
    );
    sizeElm.addClass('size');

    if( category.days_left !== null && category.days_left >= 0 ) {
      nameElm.addClass('sale');
      priceElm.addClass('sale');
      priceElm.set('title', category.days_left == 0 ? 'This is the last day it\'s on sale!' :
                                                      category.days_left + ' days left of the sale.');
      ratioElm.addClass('sale');
      sizeElm.addClass('sale');
    }

    categoryElm.appendChild(priceElm);
    categoryElm.appendChild(ratioElm);
    categoryElm.appendChild(sizeElm);
    categoryElm.appendChild(nameElm);

    contentElm.appendChild(categoryElm);
  }

  itemElm.appendChild(contentElm);

  return itemElm.get('element');
};



YAHOO.namespace( "quickadd" );

/**
 * A List object that stores an array of List.Item.
 *
 * @constructor
 */
YAHOO.quickadd.List = function(listelm) {
  // The list of items, stored as a map of id strings to YAHOO.quickadd.List.Items.
  this.list_ = {};

  // The HTMLElement that this object represents.
  this.listelm_ = listelm;

  // Used internally to generate the unique ids for the list items.
  this.nextid_ = 0;

  this.divprefix_ = 'item';
};

/**
 * Add a new list item to the list.
 * Automatically generates a new id for this new element.
 */
YAHOO.quickadd.List.prototype.add = function(text) {
  if( text.length > 0 ) {
    var id = this.divprefix_ + this.nextid_;
    this.list_[id] = new YAHOO.quickadd.List.Item(text, id, this);

    ++this.nextid_;
    
    this.queue_commit();
  }
};

/**
 * Remove an item from the list with the given id.
 */
YAHOO.quickadd.List.prototype.remove = function(id) {
  this.list_[id].shutdown();
  delete this.list_[id];
  this.listelm_.removeChild($(id));
  YAHOO.views.bystore.fire_request(this.category_ids());

  this.queue_commit();

  if( !groc_ui_iphone ) {
    $('quickadditem').focus();
  }
};

/**
 * Queue up a commit to the grocery list to the server.
 */
YAHOO.quickadd.List.prototype.queue_commit = function() {
  if( this.queued_commit_ ) {
    clearTimeout(this.queued_commit_);
    this.queued_commit_ = null;
  }
  this.queued_commit_ = setTimeout('YAHOO.quickadd.activelist.commit_()', 250);
}

/**
 * Commit the grocery list to the server.
 */
YAHOO.quickadd.List.prototype.commit_ = function() {
  var items = [];
  for( var index in this.list_ ) {
    var item = this.list_[index];
    if( item.category_ ) {
      items[items.length] = item.category_.id;
    } else {
      items[items.length] = escape(item.name_);
    }
  }
  this.transaction_ =
    YAHOO.util.Connect.asyncRequest('POST', req_commit_list, this.notify(), 'list=' + items);
};

/**
 * Get a list of all known category ids.
 */
YAHOO.quickadd.List.prototype.category_ids = function(id) {
  var cats = [];
  for( var index in this.list_ ) {
    var item = this.list_[index];
    if( item.category_ ) {
      cats[cats.length] = item.category_.id;
    }
  }
  return cats;
};

/**
 * @return an object that can receive the result of the asynchronous request for the list commit.
 */
YAHOO.quickadd.List.prototype.notify = function() {
  return {
    success: function(o) {
      var result = YAHOO.lang.JSON.parse(o.responseText);
      if( result.success ) {
      }
      delete this.transaction_;
    },

    failure: function(o) {
      delete this.transaction_;
    },

    scope: this
  };
};

/**
 * A single list item. Each item stores a cached value of its html and its corresponding div id.
 *
 * @constructor
 */
YAHOO.quickadd.List.Item = function(name, id, list) {
  this.name_ = name;
  this.id_ = id;
  this.category_ = null;
  this.parentlist_ = list;

  // TODO(jverkoey Nov 15, 2008): Is there an easier way to create an element?
  var deleteelm = new YAHOO.util.Element(document.createElement('input'),
    {'type': 'button', 'value': 'X'});
  deleteelm.addClass('delete');

  deleteelm.on('click', function() {
    list.remove(id);
  });

  // TODO(jverkoey Nov 15, 2008): Is there an easier way to create an element?
  this.textelm_ = new YAHOO.util.Element(document.createElement('span'),
    {'innerHTML': name});
  this.textelm_.addClass('name');

  this.elm_ = document.createElement('div');
  this.elm_.id = id;
  this.elm_.appendChild(deleteelm.get('element'));
  this.elm_.appendChild(this.textelm_.get('element'));

  list.listelm_.appendChild(this.elm_);

  this.transaction_ =
    YAHOO.util.Connect.asyncRequest('POST', req_category_exists, this.notify(), 'name=' + name);
};

/**
 * Shutdown the item by cancelling any active transactions.
 */
YAHOO.quickadd.List.Item.prototype.shutdown = function() {
  if( this.transaction_ ) {
    YAHOO.util.Connect.abort(this.transaction_);
    this.transaction_ = null;
  }
};

/**
 * Handle the blur event of the combo box for this element used to narrow down the results.
 *
 * Assumes that this.listitem_ has been set for the calling element.
 */
YAHOO.quickadd.List.Item.narrow = function() {
  var id = this.get('value');

  if( id && id.search(/Narrow/) == -1 ) {
    // Cancel any existing requests first.
    if( this.listitem_.transaction_ ) {
      YAHOO.util.Connect.abort(this.listitem_.transaction_);
    }

    this.listitem_.transaction_ =
      YAHOO.util.Connect.asyncRequest('GET', req_category_by_id + id, this.listitem_.notify(), null);
  }
  return true;
};


/**
 * @return an object that can receive the result of the asynchronous request for the category
 *  information.
 */
YAHOO.quickadd.List.Item.prototype.notify = function() {
  return {
    success: function(o) {
      var result = YAHOO.lang.JSON.parse(o.responseText);
      if( result.exists ) {
        this.category_ = result.category;

        this.textelm_.addClass('recognized');
        this.textelm_.set('innerHTML', result.category.name);

        if( this.chooseelm_ ) {
          this.elm_.removeChild(this.chooseelm_.get('element'));
        }

        if( result.children.length > 0 ) {
          this.children_ = result.children;
          // Create a combo box that the user can narrow the category down with.

          this.chooseelm_ = new YAHOO.util.Element(document.createElement('select'));
          this.chooseelm_.addClass('narrow');
          this.chooseelm_.listitem_ = this;
          this.chooseelm_.on('click', YAHOO.quickadd.List.Item.narrow);
          this.chooseelm_.on('blur', YAHOO.quickadd.List.Item.narrow);

          var optionelm = new YAHOO.util.Element(document.createElement('option'),
            {'innerHTML': ' - Narrow - '});
          this.chooseelm_.appendChild(optionelm);

          for( var index in result.children ) {
            var child = result.children[index];
            var optionelm = new YAHOO.util.Element(document.createElement('option'),
              {'innerHTML': child.name,
               'value': child.id});
            this.chooseelm_.appendChild(optionelm);
          }

          // We have to insert this before the text element so that it floats properly.
          this.elm_.insertBefore(this.chooseelm_.get('element'), this.textelm_.get('element'));
        }

        this.parentlist_.queue_commit();
      }
      YAHOO.views.bystore.fire_request(this.parentlist_.category_ids());
      delete this.transaction_;
    },

    failure: function(o) {
      delete this.transaction_;
    },

    scope: this
  };
};


/**
 * The interface for the quickadd form. Fires when the user hits enter or clicks the "Add" button.
 */
YAHOO.quickadd.add_item = function(e) {
  var quickadditem = $('quickadditem');
  var items = quickadditem.value.replace(/[\/\\\[\]\{\}]/g, '').split(',');
  for( var index in items ) {
    var item = YAHOO.lang.trim(items[index]).replace(/<\S[^><]*>/g, '');
    YAHOO.quickadd.activelist.add(item);
  }
  quickadditem.value = '';
  quickadditem.focus();

  // Cancel this event so that the form does not submit.
  YAHOO.util.Event.stopEvent(e);
}

YAHOO.quickadd.activelist = new YAHOO.quickadd.List($('quickaddlist'));
YAHOO.views.bystore = new YAHOO.views.PriceList($('bystore'));
YAHOO.util.Event.addListener($('quickaddform'), 'submit', YAHOO.quickadd.add_item);
YAHOO.util.Event.addListener($('quickaddbtn'), 'click', YAHOO.quickadd.add_item);

$('quickadditem').focus();
