// Models and Collections
var Product = Backbone.Model.extend({
  initialize: function(){
  },
  types: function(){
    var tags = this.get('tags');
    return _(tags).select(function(tag){
      return tag.name.indexOf("tipo_") >= 0
    });
  },
  
  typeNames: function(){
    return _(this.types()).map(function(tag){
      return tag.name.replace(/^tipo_/, "");
    });
  },
  
  tagIds: function(){
    return _(this.get('tags')).pluck('id');
  },
  
  hasReference: function(reference){
    return this.get('ref') == reference;
  },
  
  hasTagId: function(id){
    var id = _(this.tagIds()).detect(function(tagId){
      return tagId == id;
    }); 
    return id != null;
  }
});

var Products = Backbone.Collection.extend({
  model: Product,
  perPage: 6,
  
  paginate: function(page, perPage){
    perPage || (perPage = this.perPage);
    var page = (page < 0) ? 0 : page;
    var from = page * perPage;
    var to = from + perPage;
    var collection = new Products(this.select(function(i, context){
      return context >= from && context < to;
    }));
    // when creating a new collection the default comparator is setted, so we need to set the current comparator
    collection.comparator = this.comparator;
    // and then sort the collection by it
    collection.sort();
    return collection;
  },
  
  totalPages: function(){
    return Math.ceil(this.size() / this.perPage);
  },
  
  comparator: function(product){
    return -product.get('relevance');
  },
  
  filteredByTag: function(id){
    return this.filtered(function(product){
      return product.hasTagId(id);
    });
  },
  
  filteredByRef: function(reference){
    return this.filtered(function(product){
      return product.hasReference(reference);
    });
  },
  
  filteredByPrice: function(price){
    return this.filtered(function(product){
      return product.get('price') <= price;
    });
  },
  
  filtered: function(criteriaFunction){
    return new Products(this.select(criteriaFunction));
  },
  
  byPriceUp: function(){
    return this.sortedBy(function(product){
      return product.get('price');
    });
  },
  
  byPriceDown: function(){
    return this.sortedBy(function(product){
      return -product.get('price');
    });
  },
  
  sortedBy: function(comparator){
    var sortedCollection = new Products(this.models);
    sortedCollection.comparator = comparator;
    sortedCollection.sort();
    return sortedCollection;
  }
});

window.Products = Products;

// Views
var FilterView = Backbone.View.extend({

  events: {
    'click [data-command=display-list]':   'displayList',
    'click [data-command=display-images]': 'displayImages',
    'click [data-command=orderBy-priceUp]': 'orderByPriceUp',
    'click [data-command=orderBy-priceDown]': 'orderByPriceDown',
    'submit #search' : 'searchByRef',
    'click [data-command=searchBy-ref]' : 'searchByRef',
    'change [data-command=filterBy-tag]': 'filterByTag',
    'change [data-command=filterBy-maxPrice]': 'filterByMaxPrice'
  },
  
  initialize: function(){
    _(this).bindAll('displayList', 'displayImages', 'orderByPriceUp', 'orderByPriceDown', 'searchByRef', 'filterByTag', 'filterByMaxPrice');
    this.templates = {
      'imageItem': _.template($('#productImageTemplate').html()),
      'listItem': _.template($('#productListTemplate').html())
    }
    this.collectionView = this.options.collectionView;
  },
  
  displayList: function(){
    this.listType = "list";
    var location_href = "#"+this.listType;
    if (this.price && this.price != -1){
      location_href += "/price/"+this.price;
    }
    if(this.tags && this.tags.length > 0){
      location_href += "/tags/" + this.tags.join("/");
    }
    location.href = location_href;
    return false;
  },
  
  displayImages: function(){
    this.listType = "images";
    var location_href = "#"+this.listType;
    if (this.price && this.price != -1){
      location_href += "/price/"+this.price;
    }
    if(this.tags && this.tags.length > 0){
      location_href += "/tags/" + this.tags.join("/");
    }
    location.href = location_href;
    return false;
  },
  
  searchByRef: function(){
    var ref = $('#search_ref').val();
    if(ref.length > 0){
      // reset filters
      $('#search select').find('option:first').each(function(i,o){ $(o).attr('selected', true)});
      location.href = '#'+this.listType+'/search/'+ref;
    }else{
      return false;
      //location.href = '#'+this.listType;
    }
    return false;
  },
  
  filterByTag: function(){
    var tags = this.$('[data-command=filterBy-tag]');
    tags = tags.map(function(i, tag){ return $(tag).val(); });
    tags = _(tags).select(function(tag){ return tag != "-1" });
    var location_href = "#"+this.listType;
    if (this.price && this.price != -1){
      location_href += "/price/"+this.price;
    }
    if(tags.length > 0){
      location_href += "/tags/" + tags.join("/");
    }
    location.href = location_href;
  },
  
  filterByMaxPrice: function(){
    var price = this.$('[data-command=filterBy-maxPrice]').val();
    var location_href = "#"+this.listType;
    if (price != -1){
      location_href += "/price/"+price;
    }
    if(this.tags){
      location_href += "/tags/" + this.tags.join("/");
    }
    location.href = location_href;
  },
  
  orderByPriceUp: function(){
    this.collectionView.orderByPriceUp();
    return false;
  },
  
  orderByPriceDown: function(){
    this.collectionView.orderByPriceDown();
    return false;
  },
  render: function(){
    this.$('.active').removeClass('active');
    if(this.listType == 'images'){
      this.$('[data-command=display-images]').parent().addClass('active');
    }else{
      this.$('[data-command=display-list]').parent().addClass('active');
    }
    if(this.price){
      this.$('[data-command=filterBy-maxPrice]').val(this.price);
    }else{
      this.$('[data-command=filterBy-maxPrice]').val(-1);
    }
    if(this.tags){
      var $selects = this.$('[data-command=filterBy-tag]');
      var $option;
      _(this.tags).each(function(tag){
        $option = $selects.find('option[value='+tag+']');
        if($option){
          $option.parents('select').val(tag);
        }
      });
    }
  }
});

var MoreView = Backbone.View.extend({
  template: function(){ 
    return $('#moreViewLinksTemplate').html();
  },
  
  events: {
    'click [data-command="next-page"]': 'nextPage',
    'click [data-command="prev-page"]': 'prevPage'
  },
  
  initialize: function(){
    _(this).bindAll('render', 'nextPage', 'prevPage');
    this.collectionView = this.options.collectionView;
  },
  
  nextPage: function(){
    var nextPage = this.collectionView.page + 1;
    if (nextPage >= this.collectionView.totalPages()){
      this.collectionView.page = this.collectionView.totalPages() - 1;
    }else{
      this.collectionView.page = nextPage;
    }
    this.collectionView.render();
    this.render();
    return false;
  },
  
  prevPage: function(){
    var prevPage = this.collectionView.page - 1;
    if (prevPage < 0){
      this.collectionView.page = 0;
    }else{
      this.collectionView.page = prevPage;
    }
    this.collectionView.render();
    this.render();
    return false;
  },
    
  render: function(){
    var nextPages = this.collectionView.collection.size() - ((this.collectionView.page + 1) * this.collectionView.perPage);
    nextPages = (nextPages > this.collectionView.perPage) ? this.collectionView.perPage : nextPages;
    
    var out = _.template(this.template())({
      isFirstPage: (this.collectionView.page == 0),
      isLastPage: (this.collectionView.page + 1 >= this.collectionView.totalPages()),
      nextPages:  nextPages,
      prevPages: this.collectionView.perPage
    });
    $(this.el).html(out);
  }
});

var CollectionView = Backbone.View.extend({
  initialize: function(){
    this.templates = {
      'imageItem': _.template($('#productImageTemplate').html()),
      'listItem': _.template($('#productListTemplate').html())
    }
    _(this).bindAll('nextPage', 'totalPages', 'displayList', 'displayImages', 'renderItem', 'orderByPriceUp', 'orderByPriceDown', 'render', 'unrender');
    this.collection = this.options.collection;
    this.page = 0;
    this.perPage = this.collection.perPage;
    this.displayImages();
  },
  
  nextPage: function(){
    var nextPage = this.page + 1;
    if(nextPage >= this.collection.totalPages()){
      nextPage = this.collection.totalPages() - 1;
    }else{
      nextPage += 1;
    }
    return nextPage;
  },
  
  totalPages: function(){
    return this.collection.totalPages();
  },
    
  displayList: function(){
    this.template = this.templates['listItem'];
    this.render();
    return false;
  },
  
  displayImages: function(){
    this.template = this.templates['imageItem'];
    this.render();
    return false;
  },
  
  renderItem: function(product){
    var out = this.template({ product: product});
    $(this.el).append(out);
  },
  
  orderByPriceUp: function(){
    this.collection = this.collection.byPriceUp();
    this.render();
    return false;
  },
  
  orderByPriceDown: function(){
    this.collection = this.collection.byPriceDown();
    this.render();
    return false;
  },
  
  render: function(){
    this.unrender();
    if(this.collection.size() > 0){
      $('.no-results').hide();
      this.collection.paginate(this.page, this.perPage).each(this.renderItem);
      this.$('.search_result_img_box').filter(":nth-child(3n)").addClass('last');
    }else{
      $('.no-results').show();
    }
  },
  
  unrender: function(){
    $(this.el).empty();
  }
});


// Routers

var Router = Backbone.Router.extend({
  routes: {
    "" :  "index",
    ":listType" : "byListType",
    ":listType/tags/*tags" : "byTags",
    ":listType/price/:price" :       "byMaxPrice",
    ":listType/price/:price/tags/*tags" : "byMaxPriceAndTags",
    ":listType/search/:reference":   "byReference"
  },
  
  initialize: function(options){
    this._collection = options.collection;
    this.collectionView = new CollectionView({
      collection: this._collection,
      el: '#search_results'
    });
    this.filterView = new FilterView({
      collectionView: this.collectionView,
      el: '#displayOptions'
    });
    this.moreView = new MoreView({
      collectionView: this.collectionView,
      el: '#more'
    });
  },
  
  index: function(){
    this.byListType('images');
    this.navigate('images')
  },

  byListType: function(listType){
    this.collection = this._collection;
    this.listType = listType;
    this.price = null;
    this.tags = null;

    this._list();
  },
  
  byMaxPrice: function(listType, price){
    this.collection = this._collection.filteredByPrice(parseInt(price));
    this.listType = listType;
    this.price = price;
    this.tags = null;

    this._list();
  },
  
  byTags: function(listType, tags){
    this.byMaxPriceAndTags(listType, -1, tags);
  },
  
  byMaxPriceAndTags: function(listType, price, tags){
    var tags = _(tags.split("/")).map(function(tag){
      return parseInt(tag);
    });
    var self = this;
    this.collection = this._collection;
    _(tags).each(function(tag){
      self.collection = self.collection.filteredByTag(tag)
    });
    if (price && price != -1){
      this.collection = this.collection.filteredByPrice(parseInt(price));
    }
    this.listType = listType;
    this.price = price;
    this.tags = tags;
    this._list();
  },
  
  byReference: function(listType, reference){
    this.price = null;
    this.tags = null;
    this.collection = this._collection.filteredByRef(reference);
    this._list();
  },
  
  _list: function(){
    this.collectionView.collection = this.collection;

    this.collectionView.page = 0;
    this.collectionView.perPage = this.collection.perPage;
    
    this.filterView.price = this.price;
    this.filterView.tags = this.tags;
    this.filterView.listType = this.listType;
    
    this.filterView.render();
    
    if(this.listType == 'list'){
      this.filterView.listType = this.listType;
      this.collectionView.displayList();
    }else{
      this.filterView.listType = 'images';
      this.collectionView.displayImages();
    }
    
    this.moreView.collectionView = this.collectionView;
    this.moreView.render();
  }
})

