
if(typeof Product=='undefined') {
    var Product = {};
}

function getEle(id) {
	return document.getElementById(id);
}

var Class = {
  create: function() {
    // var parent = null, properties = $A(arguments);
    //  if (Object.isFunction(properties[0]))
    //    parent = properties.shift();
 
    function klass() {
      this.initialize.apply(this, arguments);
    }

    // Object.extend(klass, Class.Methods);
    // klass.superclass = parent;
    // klass.subclasses = [];

    // if (parent) {
    //   var subclass = function() { };
    //   subclass.prototype = parent.prototype;
    //   klass.prototype = new subclass;
    //   parent.subclasses.push(klass);
    // }

    // for (var i = 0; i < properties.length; i++)
    //   klass.addMethods(properties[i]);

    if (!klass.prototype.initialize)
      klass.prototype.initialize = function() {};//Prototype.emptyFunction;

    klass.prototype.constructor = klass;

    return klass;
  }
};

String.prototype.startsWith = function(str){
    return (this.indexOf(str) === 0);
}

var Template = Class.create();
Template.prototype =  {
  initialize: function(template, pattern) {
    this.template = template.toString();
    this.pattern = pattern || Template.Pattern;
  },

	gsub: function(pattern, replacement) {
	    var result = '', source = this.template, match;
	    // arguments.callee.prepareReplacement(replacement);
	    while (source.length > 0) {
	      if (match = source.match(pattern)) {
	        result += source.slice(0, match.index);
	        result += replacement(match)
	        source  = source.slice(match.index + match[0].length);
	      } else {
	        result += source, source = '';
	      }
	    }
	    return result;
	  },

  evaluate: function(object) {
    if (typeof object.toTemplateReplacements == 'function')//Object.isFunction(object.toTemplateReplacements))
      object = object.toTemplateReplacements();
	
    return this.gsub(this.pattern, function(match) {
      if (object == null) return '';

      var before = match[1] || '';
      if (before == '\\') return match[2];

      var ctx = object, expr = match[3];
      var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
      match = pattern.exec(expr);
      if (match == null) return before;

      while (match != null) {
        var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1];
        ctx = ctx[comp];
        if (null == ctx || '' == match[3]) break;
        expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);
        match = pattern.exec(expr);
      }

      return before + ctx;//String.interpret(ctx);
    });
  }
};
Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;

function formatCurrency(price, format, showPlus){
    precision = isNaN(format.precision = Math.abs(format.precision)) ? 2 : format.precision;
    requiredPrecision = isNaN(format.requiredPrecision = Math.abs(format.requiredPrecision)) ? 2 : format.requiredPrecision;

    //precision = (precision > requiredPrecision) ? precision : requiredPrecision;
    //for now we don't need this difference so precision is requiredPrecision
    precision = requiredPrecision;

    integerRequired = isNaN(format.integerRequired = Math.abs(format.integerRequired)) ? 1 : format.integerRequired;

    decimalSymbol = format.decimalSymbol == undefined ? "," : format.decimalSymbol;
    groupSymbol = format.groupSymbol == undefined ? "." : format.groupSymbol;
    groupLength = format.groupLength == undefined ? 3 : format.groupLength;

    if (showPlus == undefined || showPlus == true) {
        s = price < 0 ? "-" : ( showPlus ? "+" : "");
    } else if (showPlus == false) {
        s = '';
    }

    i = parseInt(price = Math.abs(+price || 0).toFixed(precision)) + "";
    pad = (i.length < integerRequired) ? (integerRequired - i.length) : 0;
    while (pad) { i = '0' + i; pad--; }

    j = (j = i.length) > groupLength ? j % groupLength : 0;
    re = new RegExp("(\\d{" + groupLength + "})(?=\\d)", "g");

    /**
     * replace(/-/, 0) is only for fixing Safari bug which appears
     * when Math.abs(0).toFixed() executed on "0" number.
     * Result is "0.-0" :(
     */
    r = (j ? i.substr(0, j) + groupSymbol : "") + i.substr(j).replace(re, "$1" + groupSymbol) + (precision ? decimalSymbol + Math.abs(price - i).toFixed(precision).replace(/-/, 0).slice(2) : "")

    if (format.pattern.indexOf('{sign}') == -1) {
        pattern = s + format.pattern;
    } else {
        pattern = format.pattern.replace('{sign}', s);
    }

    return pattern.replace('%s', r).replace(/^\s\s*/, '').replace(/\s\s*$/, '');
};


/**************************** CONFIGURABLE PRODUCT **************************/
Product.Config = Class.create();
Product.Config.prototype = {
    initialize: function(config){
		var self = this;
        this.config     = config;
        this.taxConfig  = this.config.taxConfig;
        this.settingsQ   = $('.super-attribute-select'); //$$('.super-attribute-select');
		this.settings = this.settingsQ.get();
        this.state      = {};//new Hash();
        this.priceTemplate = new Template(this.config.template);
        this.prices     = config.prices;

        this.settingsQ.each(function(i){
			$(this).change(function(eve) {
				self.configure(eve);
			});
            // Event.observe(element, 'change', this.configure.bind(this))
        });

        // fill state
        this.settingsQ.each(function(i){
            var attributeId = this.id.replace(/[a-z]*/, '');
            if(attributeId && self.config.attributes[attributeId]) {
                this.config = self.config.attributes[attributeId];
                this.attributeId = attributeId;
                self.state[attributeId] = false;
            }
        });

        // Init settings dropdown
        var childSettings = [];
        for(var i=this.settings.length-1;i>=0;i--){
            var prevSetting = this.settings[i-1] ? this.settings[i-1] : false;
            var nextSetting = this.settings[i+1] ? this.settings[i+1] : false;
            if(i==0){
                this.fillSelect(this.settings[i])
            }
            else {
                this.settings[i].disabled=true;
            }
            // $(this.settings[i]).childSettings = childSettings.clone();
            $(this.settings[i]).childSettings = $.extend([], childSettings);
            $(this.settings[i]).prevSetting   = prevSetting;
            $(this.settings[i]).nextSetting   = nextSetting;
            childSettings.push(this.settings[i]);
        }

        // try retireve options from url
        var separatorIndex = window.location.href.indexOf('#');
        if (separatorIndex!=-1) {
            var paramsStr = window.location.href.substr(separatorIndex+1);
            this.values = paramsStr.toQueryParams();
            this.settingsQ.each(function(i){
                var attributeId = this.attributeId;
                this.value = self.values[attributeId];
                self.configureElement(this);
            }.bind(this));
        }
    },

    configure: function(eve){
        // var element = Event.element(event);
        this.configureElement(eve.currentTarget);
    },

    configureElement : function(element) {
        this.reloadOptionLabels(element);
        if(element.value){
            this.state[element.config.id] = element.value;
            if(element.nextSetting){
                element.nextSetting.disabled = false;
                this.fillSelect(element.nextSetting);
                this.resetChildren(element.nextSetting);
            }
        }
        else {
            this.resetChildren(element);
        }
        this.reloadPrice();
//      Calculator.updatePrice();
    },

    reloadOptionLabels: function(element){
        var selectedPrice;
        if(element.options[element.selectedIndex].config){
            selectedPrice = parseFloat(element.options[element.selectedIndex].config.price)
        }
        else{
            selectedPrice = 0;
        }
        for(var i=0;i<element.options.length;i++){
            if(element.options[i].config){
                element.options[i].text = this.getOptionLabel(element.options[i].config, element.options[i].config.price-selectedPrice);
            }
        }
    },

    resetChildren : function(element){
        if(element.childSettings) {
            for(var i=0;i<element.childSettings.length;i++){
                element.childSettings[i].selectedIndex = 0;
                element.childSettings[i].disabled = true;
                if(element.config){
                    this.state[element.config.id] = false;
                }
            }
        }
    },

    fillSelect: function(element){
        var attributeId = element.id.replace(/[a-z]*/, '');
        var options = this.getAttributeOptions(attributeId);
        this.clearSelect(element);
        element.options[0] = new Option(this.config.chooseText, '');
		
        var prevConfig = false;
        if(element.prevSetting){
            prevConfig = element.prevSetting.options[element.prevSetting.selectedIndex];
        }

        if(options) {
            var index = 1;
            for(var i=0;i<options.length;i++){
                var allowedProducts = [];
                if(prevConfig) {
                    for(var j=0;j<options[i].products.length;j++){
                        if(prevConfig.config.allowedProducts
                            && prevConfig.config.allowedProducts.indexOf(options[i].products[j])>-1){
                            allowedProducts.push(options[i].products[j]);
                        }
                    }
                } else {
                    // allowedProducts = options[i].products.clone();
                    allowedProducts = $.extend([], options[i].products);
                }
                if(allowedProducts.length>0){
                    options[i].allowedProducts = allowedProducts;
                    element.options[index] = new Option(this.getOptionLabel(options[i], options[i].price), options[i].id);
                    element.options[index].config = options[i];
                    index++;
                }
            }
        }
    },

    getOptionLabel: function(option, price){
        var price = parseFloat(price);
        if (this.taxConfig.includeTax) {
            var tax = price / (100 + this.taxConfig.defaultTax) * this.taxConfig.defaultTax;
            var excl = price - tax;
            var incl = excl*(1+(this.taxConfig.currentTax/100));
        } else {
            var tax = price * (this.taxConfig.currentTax / 100);
            var excl = price;
            var incl = excl + tax;
        }

        if (this.taxConfig.showIncludeTax || this.taxConfig.showBothPrices) {
            price = incl;
        } else {
            price = excl;
        }

        var str = option.label;
        if(price){
            if (this.taxConfig.showBothPrices) {
                str+= ' ' + this.formatPrice(excl, true) + ' (' + this.formatPrice(price, true) + ' ' + this.taxConfig.inclTaxTitle + ')';
            } else {
                str+= ' ' + this.formatPrice(price, true);
            }
        }
        return str;
    },

    formatPrice: function(price, showSign){
        var str = '';
        price = parseFloat(price);
        if(showSign){
            if(price<0){
                str+= '-';
                price = -price;
            }
            else{
                str+= '+';
            }
        }

        var roundedPrice = (Math.round(price*100)/100).toString();

        if (this.prices && this.prices[roundedPrice]) {
            str+= this.prices[roundedPrice];
        }
        else {
            str+= this.priceTemplate.evaluate({price:price.toFixed(2)});
        }
        return str;
    },

    clearSelect: function(element){
        for(var i=element.options.length-1;i>=0;i--){
            element.remove(i);
        }
    },

    getAttributeOptions: function(attributeId){
        if(this.config.attributes[attributeId]){
            return this.config.attributes[attributeId].options;
        }
    },

    reloadPrice: function(){
        var price = 0;
        for(var i=this.settings.length-1;i>=0;i--){
            var selected = this.settings[i].options[this.settings[i].selectedIndex];
            if(selected.config){
                price += parseFloat(selected.config.price);
            }
        }

        optionsPrice.changePrice('config', price);
        optionsPrice.reload();

        return price;

        if($('product-price-'+this.config.productId)){
            $('product-price-'+this.config.productId).innerHTML = price;
        }
        this.reloadOldPrice();
    },

    reloadOldPrice: function(){
        if ($('old-price-'+this.config.productId)) {

            var price = parseFloat(this.config.oldPrice);
            for(var i=this.settings.length-1;i>=0;i--){
                var selected = this.settings[i].options[this.settings[i].selectedIndex];
                if(selected.config){
                    price+= parseFloat(selected.config.price);
                }
            }
            if (price < 0)
                price = 0;
            price = this.formatPrice(price);

            if($('old-price-'+this.config.productId)){
                $('old-price-'+this.config.productId).innerHTML = price;
            }

        }
    }
}


/**************************** SUPER PRODUCTS ********************************/
// 
// Product.Super = {};
// Product.Super.Configurable = Class.create();
// 
// Product.Super.Configurable.prototype = {
//     initialize: function(container, observeCss, updateUrl, updatePriceUrl, priceContainerId) {
//         this.container = $(container);
//         this.observeCss = observeCss;
//         this.updateUrl = updateUrl;
//         this.updatePriceUrl = updatePriceUrl;
//         this.priceContainerId = priceContainerId;
//         this.registerObservers();
//     },
//     registerObservers: function() {
//         var elements = this.container.getElementsByClassName(this.observeCss);
//         elements.each(function(element){
//             Event.observe(element, 'change', this.update.bindAsEventListener(this));
//         }.bind(this));
//         return this;
//     },
//     update: function(event) {
//         var elements = this.container.getElementsByClassName(this.observeCss);
//         var parameters = Form.serializeElements(elements, true);
// 
//         new Ajax.Updater(this.container, this.updateUrl + '?ajax=1', {
//                 parameters:parameters,
//                 onComplete:this.registerObservers.bind(this)
//         });
//         var priceContainer = $(this.priceContainerId);
//         if(priceContainer) {
//             new Ajax.Updater(priceContainer, this.updatePriceUrl + '?ajax=1', {
//                 parameters:parameters
//             });
//         }
//     }
// }

/**************************** PRICE RELOADER ********************************/
Product.OptionsPrice = Class.create();
Product.OptionsPrice.prototype = {
    initialize: function(config) {
        this.productId          = config.productId;
        this.priceFormat        = config.priceFormat;
        this.includeTax         = config.includeTax;
        this.defaultTax         = config.defaultTax;
        this.currentTax         = config.currentTax;
        this.productPrice       = config.productPrice;
        this.showIncludeTax     = config.showIncludeTax;
        this.showBothPrices     = config.showBothPrices;
        this.productPrice       = config.productPrice;
        this.productOldPrice    = config.productOldPrice;
        this.skipCalculate      = config.skipCalculate;
        this.duplicateIdSuffix  = config.idSuffix;

        this.oldPlusDisposition = config.oldPlusDisposition;
        this.plusDisposition    = config.plusDisposition;

        this.oldMinusDisposition = config.oldMinusDisposition;
        this.minusDisposition    = config.minusDisposition;

        this.optionPrices = {};
        this.containers = {};

        this.displayZeroPrice   = true;

        this.initPrices();
    },

    setDuplicateIdSuffix: function(idSuffix) {
        this.duplicateIdSuffix = idSuffix;
    },

    initPrices: function() {
        this.containers[0] = 'product-price-' + this.productId;
        this.containers[1] = 'bundle-price-' + this.productId;
        this.containers[2] = 'price-including-tax-' + this.productId;
        this.containers[3] = 'price-excluding-tax-' + this.productId;
        this.containers[4] = 'old-price-' + this.productId;
    },

    changePrice: function(key, price) {
        this.optionPrices[key] = parseFloat(price);
    },

    getOptionPrices: function() {
        var result = 0;
        var nonTaxable = 0;
        // $H(this.optionPrices).each(function(pair) {
		for (var key in this.optionPrices) {
            if (key == 'nontaxable') {
                nonTaxable = this.optionPrices[key];
            } else {
                result += this.optionPrices[key];
            }
        }
        var r = new Array(result, nonTaxable);
        return r;
    },

    reload: function() {
        var price;
        var formattedPrice;
        var optionPrices = this.getOptionPrices();
        var nonTaxable = optionPrices[1];
        optionPrices = optionPrices[0];
        // $H(this.containers).each(function(pair) {
		for (var key in this.containers) {
			var value = this.containers[key];
            var _productPrice;
            var _plusDisposition;
            var _minusDisposition;
            if (getEle(value)) {
                if (value == 'old-price-'+this.productId && this.productOldPrice != this.productPrice) {
                    _productPrice = this.productOldPrice;
                    _plusDisposition = this.oldPlusDisposition;
                    _minusDisposition = this.oldMinusDisposition;
                } else {
                    _productPrice = this.productPrice;
                    _plusDisposition = this.plusDisposition;
                    _minusDisposition = this.minusDisposition;
                }

                var price = optionPrices+parseFloat(_productPrice)
                if (this.includeTax == 'true') {
                    // tax = tax included into product price by admin
                    var tax = price / (100 + this.defaultTax) * this.defaultTax;
                    var excl = price - tax;
                    var incl = excl*(1+(this.currentTax/100));
                } else {
                    var tax = price * (this.currentTax / 100);
                    var excl = price;
                    var incl = excl + tax;
                }

                excl += parseFloat(_plusDisposition);
                incl += parseFloat(_plusDisposition);
                excl -= parseFloat(_minusDisposition);
                incl -= parseFloat(_minusDisposition);

                //adding nontaxlable part of options
                excl += parseFloat(nonTaxable);
                incl += parseFloat(nonTaxable);

                if (value == 'price-including-tax-'+this.productId) {
                    price = incl;
                } else if (value == 'old-price-'+this.productId) {
                    if (this.showIncludeTax || this.showBothPrices) {
                        price = incl;
                    } else {
                        price = excl;
                    }
                } else {
                    if (this.showIncludeTax) {
                        price = incl;
                    } else {
                        if (!this.skipCalculate || _productPrice == 0) {
                            price = excl;
                        } else {
                            price = optionPrices+parseFloat(_productPrice);
                        }
                    }
                }

                if (price < 0) price = 0;

                if (price > 0 || this.displayZeroPrice) {
                    formattedPrice = this.formatPrice(price);
                } else {
                    formattedPrice = '';
                }

				var priceEle = $(getEle(value)).find('.price').get(0);
				
                if (priceEle) {//getEle(value).select('.price')[0]) {
                    priceEle.innerHTML = formattedPrice;
					dupEle = $('#'+value+this.duplicateIdSuffix).find('.price').get(0);
                    if (dupEle) {
                        dupEle.innerHTML = formattedPrice;
                    }
                } else {
                    getEle(value).innerHTML = formattedPrice;
                    if (getEle(value+this.duplicateIdSuffix)) {
                        getEle(value+this.duplicateIdSuffix).innerHTML = formattedPrice;
                    }
                }
            };
        }
    },
    formatPrice: function(price) {
        return formatCurrency(price, this.priceFormat);
    }
}

