Order = function(restaurant, doc) {
  if(typeof(restaurant) != 'object') throw("Order must be initialised with restaurant");
  
  this.restaurant = restaurant;

  this.data = {};
  this.data.restaurant_id = restaurant.data._id;
  this.data.restaurant_url = restaurant.data.url_name;
  this.data.restaurant_sql_id = restaurant.data.sql_id;
  this.data.user_sql_id = null;
  this.data.restaurant = restaurant.data.title;
  
  if(this.restaurant.data.accepts_cash && this.restaurant.data.accepts_card) {
    this.data.payment_type = 'card';    
  } else if(this.restaurant.data.accepts_cash && !this.restaurant.data.accepts_card) {
    this.data.payment_type = 'cash';
  } else if(!this.restaurant.data.accepts_cash && this.restaurant.data.accepts_card) {
    this.data.payment_type = 'card';
  }
  
  this.data.delivery_price = restaurant.data.delivery_charge || 0;
  
  this.order_items = [];
  this.new_items = [];
  this.order_added = [];
  
  this.errors = [];
  
  for (var key in doc) {
    this.data[key] = doc[key];    
  }
  
  // Match order item data with restaurant items
  if(this.data.order_items){
    var restaurant_dishes = restaurant.dishes();
    for (var i=0; i < this.data.order_items.length; i++) {
      var doc_item = this.data.order_items[i];
      var oi = new OrderItem(this, doc_item);
      var dish = _.detect(restaurant_dishes, function(d){ return d.data.title == doc_item.title })
      if(dish){
        oi.data.price = dish.data.price;
        oi.data.dish_path = dish.path();
        oi.data.option_refs = [];
        
        _.each(oi.options, function(order_item_option){
          _.each(dish.optionGroups, function(og) {
            if(og.data.title == order_item_option.data.group) {
              _.each(og.options, function(o) {
                var price = (og.data.price || 0) + (o.data.price || 0);
                if(o.data.title == order_item_option.data.title && price == order_item_option.data.price) {
                  oi.data.option_refs.push(o.path())
                }
              })              
            }
          });
        })
        
        this.order_items.push(oi);
      }
    }    
  }

};

Order.prototype = {
  
  fields: [
    { name: 'customer_name',         sel: 'input[name=customer_name]',  regex: /\S+ \S+/i, err: 'Please type your full name' },
    { name: 'phone',                 sel: 'input[name=phone]',          regex: /([0-9] *){9}/, err: 'Must be 9 or more digits' },
    // { name: 'email',                 sel: 'input[name=email]',          regex: /^([a-z0-9_.-])+@(([a-zA-Z0-9-])+.)+([a-zA-Z0-9]{2,4})+$/i, err: 'Type a valid email address' },
    { name: 'method',                sel: 'input:radio[name=method]:checked' },
    { name: 'address_1',             sel: 'input[name=address_1]',      regex: /[a-z]+/i, err: 'Please type your address', cond: function(self) { return self.for_delivery() }  },
    { name: 'address_2',             sel: 'input[name=address_2]' },
    { name: 'town',                  sel: 'input[name=town]',           regex: /[a-z]+/i, err: 'Please type your town', cond: function(self) { return self.for_delivery() } },
    { name: 'postcode',              sel: 'input[name=postcode]',       regex: /^[a-z]+[0-9]+/i, err: 'Please type your postcode', cond: function(self) { return self.for_delivery() }   },
    { name: 'delivery_instructions', sel: 'textarea[name=delivery_instructions]' },
    { name: 'previous_card_order',   sel: 'select[name=previous_card_order]' },
    { name: 'billing_delivery_same', sel: 'input:checkbox[name=billing_delivery_same]' },
    { name: 'bill_address_1',        sel: 'input[name=bill_address_1]' },
    { name: 'bill_town',             sel: 'input[name=bill_town]' },
    { name: 'bill_postcode',         sel: 'input[name=bill_postcode]' },
    { name: 'coupon_code',           sel: 'input[name=coupon_code]' },
    { name: 'special_instructions',  sel: 'textarea[name=special_instructions]' }
  ],
  
  fetch_attributes: function() {
    for (field in this.fields) {
      if(!this.fields[field].no_save) {
        var val = $('#confirmation_inner_' + this.restaurant.data._id + ' ' + this.fields[field].sel).val();
        if(val && val != '') this.data[this.fields[field].name] = val;        
      }
    }
    if(this.for_delivery()) {
      this.data.requested_time = $('#confirmation_inner_' + this.restaurant.data._id + ' select[name=requested_deliv_time]').val();
    } else {
      this.data.requested_time = $('#confirmation_inner_' + this.restaurant.data._id + ' select[name=requested_colec_time]').val();      
    }
    if($('#confirmation_inner_' + this.restaurant.data._id + ' input:checkbox[name=billing_delivery_same]').is(':checked')) {
      this.data.bill_address_1 = this.data.address_1;
      this.data.bill_town = this.data.town;
      this.data.bill_postcode = this.data.postcode;
    }
    this.fetch_order_items();
  },
  
  fetch_order_items: function() {
    
    this.data.order_items = _.map(this.order_items, function(item){
      var i = {
        title: item.data.title,
        quantity: item.data.quantity,
        price: item.price(),
        item_price: item.data.price,
        sms_title: item.data.sms_title
      }

      var opts = []
      _.each(item.options, function(option) {
        var title = option.data.title;
        if(option.data.options) {
          _.each(option.data.options, function(opt){
            opts.push({group: option.data.group, title: opt.title, price: opt.price});              
          });
        } else {
          opts.push({group: option.data.group, title: option.data.title, price: option.data.price});            
        }
      });
      
      if(opts.length != 0) i.options = opts;
      
      return i;
    })

    this.data.sub_total = this.sub_total().toFixed(2);
    this.data.card_fee = this.card_fee().toFixed(2);
    this.data.delivery_price = this.delivery().toFixed(2);
    this.data.restaurant_discount = this.calculate_restaurant_discount().toFixed(2);
    this.data.commissionable_total = this.commissionable_total().toFixed(2);
    this.data.total = this.total().toFixed(2);    
  },
  
  validate: function() {
    var valid = true;
    this.errors = {};
    if(this.data.phone && this.data.phone.match(/^07/) && this.data.phone.length < 11) {
      var field = $('#confirmation_inner_' + this.restaurant.data._id + ' input[name=phone]');
      valid = false;
      this.add_error_to_field(field, "Must have 11 digits", 'phone')
    }
    for (field_idx in this.fields) {
      var field = $('#confirmation_inner_' + this.restaurant.data._id + ' ' + this.fields[field_idx].sel);

      if(!this.errors[this.fields[field_idx].name] && this.fields[field_idx].regex) {
        var validate_field = this.fields[field_idx].regex;
        if(validate_field && this.fields[field_idx].cond && !this.fields[field_idx].cond(this)) {
          validate_field = false;
        }
        var field_value = this.data[this.fields[field_idx].name];
        if(validate_field && (!field_value || !field_value.match(this.fields[field_idx].regex))) {
          valid = false;
          this.add_error_to_field(field, this.fields[field_idx].err, this.fields[field_idx].name)
        } else {
          field.parent().removeClass('err').addClass('ok');
          if(field.next().length != 0) {
            field.next().slideUp(300, function(){ $(this).remove() })
          }
        }
      }
    }
    return valid;
  },
  
  add_error_to_field: function(field, err, field_name) {
    this.errors[field_name] = err;
    field.parent().removeClass('ok').addClass('err');
    if(field.next().length == 0) {
      field.parent().append(Jaml.render('under_err', err));
      field.next().slideDown();
    }
  },
  
  valid: function() {
    this.fetch_attributes();
    return this.validate();
  },
  
  /**
   *  Adds an item to the order.
   *  Alteration: add|remove
   *  Returns: ['added|updated|removed', dish_ref, order_ref, quantity]
   */ 
  alter_item: function(alteration, item_ref) {
    
    var path = item_ref.split("_");
    
    if(alteration == 'remove') {
      if(path[0] != 'order') {
        var item = _.detect(this.order_items.reverse(), function(i){
          return i.data.dish_path == item_ref;
        });
        this.order_items.reverse();
      } else {
        var item = this.order_items[parseInt(path[path.length -1])];
      }
      if(!item) return false;
      
      item.data.quantity -= 1;
      if(item.data.quantity == 0) {
        var rem = ['removed', item.data.dish_path, item.path(), item.amalgamated_quantity()];
        this.order_items.splice(item.idx(), 1);
        return rem;
      } else {
        return ['updated', item.data.dish_path, item.path(), item.amalgamated_quantity()];
      }
    } else if(alteration == 'add') {
      if(path[0] == 'order') {
        var item = this.order_items[parseInt(path[path.length -1])];
        item.data.quantity += 1;
        return ['updated', item.data.dish_path, item.path(), item.amalgamated_quantity()];
      }

      var dish = this.restaurant.menu_sections[parseInt(path[1])].dishes[parseInt(path[2])];
      
      var new_item = new OrderItem(this, {
        title: dish.data.title,
        sms_title: dish.data.sms_title,
        dish_path: dish.path(),
        quantity: 1,
        price: dish.data.price,
        options: [],
        option_refs: []
      });

      _.each(dish.visible_groups(), function(group) {
        var group_options = _.intersect(dish.selected_options(), group.options);
        if(group_options.length >= 0){
          _.each(group_options, function(o){
            new_item.data.option_refs.push(o.path());
          }); 
        }
        if(group_options.length == 1){
          var item_option = new OrderItemOption(new_item, {
            group: group.data.title,
            price: group_options[0].price(),
            title: group_options[0].data.title
          });
          new_item.options.push(item_option);
        } else if(group_options.length > 1){
          var item_option = new OrderItemOption(new_item, {
            group: group.data.title,
            price: (group.data.price || 0),
            options: _.map(group_options, function(opt){
              return {title: opt.data.title, price: opt.price()}
            })
          });
          new_item.options.push(item_option);
        }
      });
      
      var existing = new_item.existing();
      if(existing) {
        existing.data.quantity += 1;
        return ['updated', existing.data.dish_path, existing.path(), existing.amalgamated_quantity()];
      } else {
        this.order_items.push(new_item);
        this.new_items.push(new_item.path());
        return ['added', new_item.data.dish_path, new_item.path(), new_item.amalgamated_quantity()];
      }
    }
  },
  
  path: function() {
    return 'order_' + this.restaurant.path();
  },
  
  sub_total: function() {
    return _.reduce(this.order_items, function(memo, item){ return memo + item.price() }, 0)
  },
  
  delivery: function() {

    if(this.restaurant.data.delivery_zones && this.data.distance_to_restaurant) {
      return this.restaurant.delivery_charge(this.data.distance_to_restaurant, this.postcode_header(), this.sub_total())
    } else {
      return (Number(this.data.delivery_price) || 0);
    }
  },
  
  card_fee: function() {
    return 0.5;
  },
  
  discount: function() {
    if(this.data.discount && this.pay_online()) {
      return this.data.discount;
    } else {
      return 0;
    }
  },
  
  restaurant_discount: function() {
    return this.data.restaurant_discount || 0;
  },
  
  total_discount: function() {
    return (Number(this.restaurant_discount()) + Number(this.discount()));
  },
  
  calculate_restaurant_discount: function() {
    var self = this;
    return _.reduce(this.restaurant.offers(), function(m,o) { return (m + o.amount(self.sub_total()))}, 0);    
  },
  
  applicable_offers: function() {
    var self = this;
    return _.select(this.restaurant.offers(), function(m,o) { return o.applicable(self.sub_total())});
  },
  
  total: function() {
    var tot = this.commissionable_total();
    if(this.pay_online()) tot += this.card_fee();
    if(this.discount()) tot -= this.discount();
    return tot;
  },
  
  commissionable_total: function() {
    var tot = this.sub_total();
    tot -= this.restaurant_discount();
    if(this.for_delivery()) tot += this.delivery();
    return tot;    
  },

  commission: function() {
    var tot = this.commissionable_total();
    tot = tot * this.restaurant.data.commission / 100;
    return tot;    
  },

  commission_and_vat: function() {
	 return Number(Number(this.commission().toFixed(2)) * 1.2).toFixed(2);
  },
  
  pay_online: function() {
    return (this.data.payment_type != 'cash')
  },
  
  asap: function() {
    return this.data.requested_time && this.data.requested_time.match(/asap/i)
  },
  
  for_delivery: function() {
    return (this.data.method != 'collect')
  },
  
  first_name: function(){
    return this.data.customer_name.split(" ")[0]
  },
  
  last_name: function(){
    return this.data.customer_name.split(" ")[1]    
  },
  
  delivery_address: function(){
    return {
      address_1: this.data.address_1,
      address_2: this.data.address_2,
      town: this.data.town,
      postcode: this.data.postcode,
      country: 'GB'
    }
  },
  
  billing_address: function(){
    return {
      address_1: this.data.bill_address_1,
      town: this.data.bill_town,
      postcode: this.data.bill_postcode,
      country: 'GB'
    }
  },
  
  postcode_header: function() {
    var pc = this.data.postcode.toUpperCase().replace(/[^0-9A-Z]/g, '');
    var postcode_header = pc.length > 4 ? pc.substr(0,pc.length-3) : pc;
    return postcode_header.replace(/[A-Z]$/, '')
  },
  
  
  /**
   * Go through mandatory options - 
   */
  clone: function() {
    var clone = new Order(this.restaurant);
    _.each(this.data.order_items, function(oi) {
      var dish = _.detect(this.restaurant.dishes(), function(d) { return d.data.title == oi.title});
      if(dish) {
        var new_item = new OrderItem(clone, {
          title: dish.data.title,
          sms_title: dish.data.sms_title,
          dish_path: dish.path(),
          quantity: oi.quantity,
          price: dish.data.price,
          options: [],
          option_refs: []
        });
        
        if(oi.options) {
          for(var i=0; i< oi.options.length; i++) {
            var option_group = _.detect(dish.visible_groups(), function(og) {return og.data.title == oi.options[i].group});
            if(option_group) {
              var dish_option = _.detect(option_group.options, function(o) { return o.data.title == oi.options[i].title});
              if(dish_option) {
                dish_option.select();
              }
            }
          }
          
          _.each(dish.visible_groups(), function(group) {
            var group_options = _.intersect(dish.selected_options(), group.options);
            if(group_options.length >= 0){
              _.each(group_options, function(o){
                new_item.data.option_refs.push(o.path());
              }); 
            }
            if(group_options.length == 1){
              var item_option = new OrderItemOption(new_item, {
                group: group.data.title,
                price: group_options[0].price(),
                title: group_options[0].data.title
              });
              new_item.options.push(item_option);
            } else if(group_options.length > 1){
              var item_option = new OrderItemOption(new_item, {
                group: group.data.title,
                price: (group.data.price || 0),
                options: _.map(group_options, function(opt){
                  return {title: opt.data.title, price: opt.price()}
                })
              });
              new_item.options.push(item_option);
            }
          });
          
        }        
        clone.order_items.push(new_item)
      }
    }, this);
    clone.fetch_order_items();
    clone.data.special_instructions = this.data.special_instructions;
    clone.data.payment_type = this.data.payment_type;
    clone.data.method = this.data.method;
    
    return clone.data;
  }
  
};

OrderItem = function(order, data) {
  this.order = order;
  this.data = { quantity: 1 };
  this.options = [];

  for (var key in data) {
    this.data[key] = data[key];
  }
  
  if(this.data.options){
    for (var i=0; i < this.data.options.length; i++) {
      this.options.push(new OrderItemOption(this, this.data.options[i]));
    }    
  }

}

OrderItem.prototype = {
  price: function() {
    return this.individual_price() * this.data.quantity;
  },
  individual_price: function() {
    var price = (this.data.price || 0);
    _.each(this.options, function(o){
      price += o.price();
    });
    return price;
  },
  path: function() {
    return this.order.path() + "_" + this.idx();
  },
  idx: function() {
    return _.indexOf(this.order.order_items, this);      
  },
  amalgamated_quantity: function() {
    return _.reduce(_.select(this.order.order_items, function(i){
      return i.data.dish_path == this.data.dish_path
    }, this), function(memo, i){ return memo + i.data.quantity}, 0)
  },
  existing: function() {
    return _.detect(this.order.order_items, function(oi){
      var path = (oi.data.dish_path == this.data.dish_path);
      var items = oi.data.option_refs ? (oi.data.option_refs.join(" ") == this.data.option_refs.join(" ")) : [];
      return (path && items);
    }, this);
  }
}

OrderItemOption = function(order_item, data) {
  this.order_item = order_item;
  this.data = {};
  
  for (var key in data) {
    this.data[key] = data[key];
  }
}

OrderItemOption.prototype = {
  price: function() {
    var price = 0;
    if(this.data.options) {
      _.each(this.data.options, function(o){ 
        price = price + o.price;
      });
    } else {
      price = (this.data.price || 0)
    }
    return price;
  }
}





