/******************************************************************************
* gshpPriceManager.js
*******************************************************************************
Gestionnaire de prix (et son complement)
*******************************************************************************
Les formulaires utilises pour l'ajout au panier ont pour valeur d'id :
- addReferenceToBasketFormId			Ajout d'une reference d'un product
- addReferencesToBasketFormId			Ajout de 1  x references d'un product
- addPackToBasketFormId					Ajout d'un pack

Les fonctions de complement du "price manager complement" sont :
- onChangeDimension						Parametres : manager, select, product, dimensions
- onMouseOverQuantityGridInput			Parametres : manager, product, reference
- onMouseOutQuantityGridInput			Parametres : manager, product, reference
- onFocusQuantityGridInput				Parametres : manager, product, reference
- onBlurQuantityGridInput				Parametres : manager, product, reference
- onChangeQuantityGridInput				Parametres : manager, product, reference
- onClickPackItem 						Parametres : manager, checkbox, product
- onCustomizePackItem					Parametres : manager, product						Return : boolean (Flag of customization update)
- onChangeCurrentProductCustomization	Parametres : manager, product
- onChangePackItemCustomization			Parametres : manager, product
- computePrice							Parameters : manager, product, reference, computedPrice
- showReference							Parametres : manager, product, reference
- showGridReferenceData					Parametres : manager, product, reference
- hideGridReferenceData					Parametres : manager, product
- showProductReferences					Parametres : manager, product

Les fonctions de remplacement du "price manager complement" sont :
- overridenFormatPrice					Parametres : manager, product, reference, price, priceType, showPriceType, showCounterValue
- overridenFormatDiscountedPrice		Parametres : manager, product, reference, price, discountedPrice, priceType, showPriceType, showCounterValue
- overridenShowGridReferenceData		Parametres : manager, product, reference
- overridenHideGridReferenceData		Parametres : manager, product

*******************************************************************************
*                                                                             *
* Copyright 2008									                          *
*                                                                             *
******************************************************************************/

//
// ------------------------------------- Global functions
//
function gshpOnClickPackPlusMinus(evt)
{
	evt || (evt = window.event);
	var element = (document.all != null) ? window.event.srcElement : evt.currentTarget;
	if (element != null ) {
		var idData = element.id.split("_");
		if (idData.length >= 3) {
			var productOid	= idData[2];
			var img			= document.getElementById("gshpPackImg_plusMinus_" + productOid);
			var div			= document.getElementById("gshpPackDiv_dimensions_" + productOid);
			if ((img != null) && (div != null)) {
				var srcImg = img.src;
				if (img.src.indexOf("dynlib_plus.gif") != -1) {
					img.src = GshpPriceManager.prototype.MINUS_ICON
					div.style.display = "block";
				}
				else {
					img.src = GshpPriceManager.prototype.PLUS_ICON;
					div.style.display = "none";
				}
				return false;
			}
		}
	}
	return true;
}

function gshpCheckNumericKeyPressed(evt)
{
	var keyCode;
	if (window.event)	keyCode = window.event.keyCode;
	else
	if (evt)			keyCode = evt.which;

	// Numeric keys
	if ((keyCode >= 48) && (keyCode <= 57))
		return true;

	// Hack for Firefox (tab, arrows, backspace, ...)
	if ((keyCode == 0) || (keyCode == 8))
		return true;

	return false;
}

function gshpRefreshGridReferenceData()
{
	var currentProduct = objGshpPriceManager.currentProduct;
	if ((currentProduct != null) && (currentProduct.referenceWithMouseOver == null)) {
		// Refresh of timer
		var now = new Date().getTime();
		var delta = objGshpPriceManager.refreshGridReferenceDataTimeout - (now - objGshpPriceManager.refreshGridReferenceDataLastDate)
		if (delta > 0) {
			setTimeout("gshpRefreshGridReferenceData()", delta);
		}
		else {
			// Hiding or update of reference data according to exsitence of current reference
			var currentReference = currentProduct.currentReference;
			if (currentReference == null) {
				objGshpPriceManager.hideGridReferenceData(currentProduct);
			}
			else {
				objGshpPriceManager.showGridReferenceData(currentProduct, currentReference);
			}
		}
	}
}

//
// ------------------------------------- class GshpPriceManager
//
function GshpPriceManager()
{
	// Global init
	this._isInit = false;
	this._oComplement = null;

	this._basketType = "B2C";
	this._priceSystemType = "B2C";
	this._priceSystemCombination = "basePrice";

	this._vatCalculation = "vatPrice";
	this._defaultVatRate = 19.6;

	this._showPrices = true;
	this._hideDashedBasePrices = false;
	this._currency = "€";
	this._vatDisplayMode = "vat";
	this._showPriceType = true;

	this._showCounterValue = false;
	this._counterValueCurrency = "FF";
	this._counterValueRate = 6.55957;

	this._activateStockRules = false;
	this._showWarningStockMsg_AllHiddenRef = false;
	this._warningStockMsgLabel_AllHiddenRef = "";
	this._stockRules = new Object();

	this._hasPersistentBasketManagementPage = false;
	this._nbCommandType = 0;
	this._nbValidCommandType = 0;

	// Map to find product and reference (key is oid _productUse)
	this._productMap = new Object();
	this._referenceMap = new Object();

	// Map of modes
	this._modeMap = new Object();

	// Map of requested quantities
	this._requestedReferenceQuantityMap = null;

	// Initializing and current objects
	this._initPack = null;
	this._initProduct = null;
	this.currentPack = null;
	this.currentProduct = null;
	this.currentBasket = null;

	// Id and data of used forms to add to basket
	this.addReferenceToBasketFormId = "basketReferenceForm";
	this.addReferencesToBasketFormId = "basketReferencesForm";
	this.addPackToBasketFormId = "basketPackForm";
	this.addToBasketForms = new Object();

	// Roll-over on grid inputs
	this.refreshGridReferenceDataTimeout = 1000;
	this.refreshGridReferenceDataLastDate = 0;
}

//	=================== CONSTANTS
//
GshpPriceManager.prototype.CURRENTPRODUCT_MODE	= "currentProduct";
GshpPriceManager.prototype.PACK_MODE			= "pack";

GshpPriceManager.prototype.PLUS_ICON 			= "./iso_icons/dynlib_plus.gif";
GshpPriceManager.prototype.MINUS_ICON			= "./iso_icons/dynlib_minus.gif";
GshpPriceManager.prototype.EMPTY_ICON			= "./iso_icons/empty.gif";

//	-------------------------------------------------------------------------
//	Recovery of mode or product use
//	-------------------------------------------------------------------------
GshpPriceManager.prototype.getMode = function(sProductUse)
{
	for (var sMode in this._modeMap) {
		if (this._modeMap[sMode].productUse == sProductUse)
			return sMode;
	}
	return "";
}

GshpPriceManager.prototype.getProductUse = function(sMode)
{
	return this._modeMap[sMode].productUse;
}

GshpPriceManager.prototype.getDimensionsRender = function(sMode)
{
	return this._modeMap[sMode].dimensionsRender;
}

//	-------------------------------------------------------------------------
//	Global init
//	-------------------------------------------------------------------------
GshpPriceManager.prototype.isInit = function()
{
	return this._isInit;
}

GshpPriceManager.prototype.setInit = function(init)
{
	this._isInit = init;
}

GshpPriceManager.prototype.setAddReferenceToBasketFormId = function(addReferenceToBasketFormId)
{
	if (addReferenceToBasketFormId != "")
		this.addReferenceToBasketFormId = addReferenceToBasketFormId;
}

GshpPriceManager.prototype.setAddReferencesToBasketFormId = function(addReferencesToBasketFormId)
{
	if (addReferencesToBasketFormId != "")
		this.addReferencesToBasketFormId = addReferencesToBasketFormId;
}

GshpPriceManager.prototype.setAddPackToBasketFormId = function(addPackToBasketFormId)
{
	if (addPackToBasketFormId != "")
		this.addPackToBasketFormId = addPackToBasketFormId;
}

GshpPriceManager.prototype.setAddToBasketFormAction = function(addToBasketFormId, action)
{
	if ((addToBasketFormId != "") && (typeof(action) == "string")) {
		var addToBasketForm = this.addToBasketForms[addToBasketFormId];
		if (addToBasketForm == null) 
			this.addToBasketForms[addToBasketFormId] = addToBasketForm = new Object();
		addToBasketForm.action = action;
	}
}

GshpPriceManager.prototype.setAddToBasketFormTarget = function(addToBasketFormId, target)
{
	if ((addToBasketFormId != "") && (typeof(target) == "string")) {
		var addToBasketForm = this.addToBasketForms[addToBasketFormId];
		if (addToBasketForm == null) 
			this.addToBasketForms[addToBasketFormId] = addToBasketForm = new Object();
		addToBasketForm.target = target;
	}
}

GshpPriceManager.prototype.setBasketType = function(basketType)
{
	this._basketType = basketType;
}

GshpPriceManager.prototype.setPriceSystem = function(priceSystemType, priceSystemCombination)
{
	this._priceSystemType = priceSystemType;
	this._priceSystemCombination = priceSystemCombination;
}

GshpPriceManager.prototype.setVatParameters = function(vatCalculation, defaultVatRate)
{
	this._vatCalculation = vatCalculation;
	this._defaultVatRate = defaultVatRate;
}

GshpPriceManager.prototype.setPriceParameters = function(showPrices, hideDashedBasePrices, currency, vatDisplayMode, showPriceType)
{
	this._showPrices = showPrices;
	this._hideDashedBasePrices = hideDashedBasePrices;
	this._currency = currency;
	this._vatDisplayMode = vatDisplayMode;
	this._showPriceType = showPriceType;

	var priceRow = document.getElementById("gshpReferencePriceRow");
	if (priceRow != null) {
		if (showPrices) {
			priceRow.style.display = document.all ? "block":"table-row";
		} else {
			priceRow.style.display = "none";
		}
	}
}

GshpPriceManager.prototype.setCounterValueParameters = function(showCounterValue, counterValueCurrency, counterValueRate)
{
	this._showCounterValue = showCounterValue;
	this._counterValueCurrency = counterValueCurrency;
	this._counterValueRate = counterValueRate;
}

GshpPriceManager.prototype.setStockRules = function(showWarningStockMsg_AllHiddenRef, warningStockMsgLabel_AllHiddenRef,
													actionOnRef_AS_NC, showWarningStockMsg_AS_NC, warningStockMsgLabel_AS_NC,
													actionOnRef_GS_R, showWarningStockMsg_GS_R, warningStockMsgLabel_GS_R,
													actionOnRef_GS_NR, showWarningStockMsg_GS_NR, warningStockMsgLabel_GS_NR,
													actionOnRef_WS_R, showWarningStockMsg_WS_R, warningStockMsgLabel_WS_R,
													actionOnRef_WS_NR, showWarningStockMsg_WS_NR, warningStockMsgLabel_WS_NR,
													actionOnRef_CS_R, showWarningStockMsg_CS_R, warningStockMsgLabel_CS_R,
													actionOnRef_CS_NR, showWarningStockMsg_CS_NR, warningStockMsgLabel_CS_NR )
{
	this._activateStockRules = true;

	// All hidden
	this._showWarningStockMsg_AllHiddenRef 	= showWarningStockMsg_AllHiddenRef;
	this._warningStockMsgLabel_AllHiddenRef	= warningStockMsgLabel_AllHiddenRef;

	// Used codes by rules :
	// - AS (Any stock), GS (Good stock), WS (Warning stock) and CS (Critical stock)
	// - NC (Not commandable)
	// - R (reorderable) and NR (Not reorderable)
	this._stockRules = new Object();
	this._stockRules["AS_NC"]	= new GshpStockRule("AS_NC", actionOnRef_AS_NC, showWarningStockMsg_GS_R, warningStockMsgLabel_AS_NC);
	this._stockRules["GS_R"]	= new GshpStockRule("GS_R", actionOnRef_GS_R, showWarningStockMsg_GS_R, warningStockMsgLabel_GS_R);
	this._stockRules["GS_NR"]	= new GshpStockRule("GS_NR", actionOnRef_GS_NR, showWarningStockMsg_GS_NR, warningStockMsgLabel_GS_NR);
	this._stockRules["WS_R"]	= new GshpStockRule("WS_R", actionOnRef_WS_R, showWarningStockMsg_WS_R, warningStockMsgLabel_WS_R);
	this._stockRules["WS_NR"]	= new GshpStockRule("WS_NR", actionOnRef_WS_NR, showWarningStockMsg_WS_NR, warningStockMsgLabel_WS_NR);
	this._stockRules["CS_R"]	= new GshpStockRule("CS_R", actionOnRef_CS_R, showWarningStockMsg_CS_R, warningStockMsgLabel_CS_R);
	this._stockRules["CS_NR"]	= new GshpStockRule("CS_NR", actionOnRef_CS_NR, showWarningStockMsg_CS_NR, warningStockMsgLabel_CS_NR);
}

GshpPriceManager.prototype.setCommandTypes = function(hasPersistentBasketManagementPage, nb, nbValid)
{
	this._hasPersistentBasketManagementPage = hasPersistentBasketManagementPage;
	this._nbCommandType = nb;
	this._nbValidCommandType = nbValid;
}

GshpPriceManager.prototype.setRequestedReferences = function(requestedReferencesDescr)
{
	if (requestedReferencesDescr != "") {
		this._requestedReferenceQuantityMap = new Object();
		var descriptionList = requestedReferencesDescr.split("|");
		for (var ind1=0; ind1<descriptionList.length; ind1++) {
			var description = descriptionList[ind1];
			var refOid = refQuantity = null;
			var attrList = description.split("#");
			for (var ind2=0; ind2<attrList.length; ind2++) {
				var attr = attrList[ind2];
				var pos = attr.indexOf("=");
				if (pos != -1) {
					var attrName = attr.substr(0, pos);
					var attrValue = attr.substr(pos+1);
					if (attrName == "basketReference")		refOid = attrValue;
					else
					if (attrName == "basketQuantity")		refQuantity = parseInt(attrValue, 10);
				}
			}
			
			if ((refOid != null) && (refQuantity != null))
				this._requestedReferenceQuantityMap[refOid] = refQuantity;
		}
	}
}

GshpPriceManager.prototype.initCurrentProductMode = function(productUse, dimensionsRender)
{
	var mode 			= GshpPriceManager.prototype.CURRENTPRODUCT_MODE;
	this._modeMap[mode]	= new GshpMode(mode, productUse, dimensionsRender);
}

GshpPriceManager.prototype.initPackMode = function(productUse, dimensionsRender)
{
	var mode 			= GshpPriceManager.prototype.PACK_MODE;
	this._modeMap[mode] = new GshpMode(mode, productUse, dimensionsRender);
}

//	-------------------------------------------------------------------------
//	Basket init
//	-------------------------------------------------------------------------
GshpPriceManager.prototype.setBasket = function(oid, typeOid, label)
{
	this.currentBasket = new GshpBasket(oid, typeOid, label);
}

//	-------------------------------------------------------------------------
//	Pack init
//	-------------------------------------------------------------------------
GshpPriceManager.prototype.startInitPack = function(oid)
{
	this._initPack = new GshpPack(oid);

	// Current pack
	this.currentPack = this._initPack;
}

GshpPriceManager.prototype.setPackLabel = function(label)
{
	if (this._initPack == null)	return;

	this._initPack.label = label;
}

GshpPriceManager.prototype.setPackPromoModel = function(promoOid, promoDescription)
{
	if (this._initPack == null)	return;

	this._initPack.setPromoModel(promoOid, promoDescription);
}

//	-------------------------------------------------------------------------
//	Product init
//	-------------------------------------------------------------------------
GshpPriceManager.prototype.startInitProduct = function(productUse, oid)
{
	var productMode = this.getMode(productUse);
	this._initProduct = new GshpProduct(productMode, productUse, oid);

	// Map to find product from input id
	this._productMap[oid + "_" + productUse] = this._initProduct;

	// Current product
	if (productMode == GshpPriceManager.prototype.CURRENTPRODUCT_MODE)
		this.currentProduct = this._initProduct;
	else
	if ((productMode == GshpPriceManager.prototype.PACK_MODE) && (this._initPack != null))
		this._initPack.addProduct(this._initProduct);
}

GshpPriceManager.prototype.setProductLabel = function(label)
{
	if (this._initProduct == null) return;

	this._initProduct.label = label;
}

GshpPriceManager.prototype.setIsCurrentProduct = function(isCurrentProduct)
{
	if (this._initProduct == null) return;

	this._initProduct.isCurrentProduct = isCurrentProduct;
}

GshpPriceManager.prototype.setOpenDimension = function(useOpenDimension, openDimensionLabel)
{
	if (this._initProduct == null) return;

	this._initProduct.useOpenDimension	= useOpenDimension;
	this._initProduct.openDimensionLabel= openDimensionLabel;
}

GshpPriceManager.prototype.setOpenCategories = function(openCategory1, openCategory2, openCategory3, openCategory4, openCategory5)
{
	if (this._initProduct == null) return;

	this._initProduct.openCategories[0] = openCategory1;
	this._initProduct.openCategories[1] = openCategory2;
	this._initProduct.openCategories[2] = openCategory3;
	this._initProduct.openCategories[3] = openCategory4;
	this._initProduct.openCategories[4] = openCategory5;
}

GshpPriceManager.prototype.setFlashSale = function(oid, label, startDate, endDate, price, priceType)
{
	if (this._initProduct == null) return;

	var flashSale = new GshpFlashSale(oid, label, startDate, endDate, price, priceType);
	this._initProduct.setFlashSale(flashSale);
}

GshpPriceManager.prototype.addPrices = function(list)
{
	if (this._initProduct == null) return;

	for (var i=0; i<list.length; i++) {
		var record = list[i].split("|");
		var reference = this._initProduct.addReference(record);

		// Map to find reference from input id
		if (reference != null)
			this._referenceMap[reference.oid + "_" + this._initProduct.use] = reference;
	}
}

GshpPriceManager.prototype.addDimensionModel = function(rank, isOpen, label, list)
{
	if (this._initProduct == null) return;

	var dimensionModel = new GshpDimensionModel(rank, isOpen, label);
	this._initProduct.dimensionModels[rank-1] = dimensionModel;

	if (list != null) {
		for (var i=0; i<list.length; i++) {
			var record = list[i].split("|");
			dimensionModel.addValue(record);
		}
	}
}

//	-------------------------------------------------------------------------
//	Rounded calculation of price, vat price or vat rate
//	-------------------------------------------------------------------------
GshpPriceManager.prototype.calculatePrice = function(vatPrice, vatRate)
{
	return this.roundPrice(vatPrice / (1 + 0.01 * vatRate));
}
GshpPriceManager.prototype.calculateVatPrice = function(price, vatRate)
{
	return this.roundPrice(price * (1 + 0.01 * vatRate));
}
GshpPriceManager.prototype.calculateVatRate = function(price, vatPrice)
{
	return this.roundRate(100 * ((vatPrice / price) - 1));
}

//	-------------------------------------------------------------------------
//	Rounding of price or rate
//	-------------------------------------------------------------------------
GshpPriceManager.prototype.roundPrice = function(price)
{
	return (Math.round(price * 100) / 100);
}
GshpPriceManager.prototype.roundRate = function(rate)
{
	return (Math.round(rate * 10) / 10);
}

//	-------------------------------------------------------------------------
//	Computing/Validating/Formating of price
//	-------------------------------------------------------------------------
GshpPriceManager.prototype.computePrice = function(product, reference)
{
	// Recovery of computed price from reference
	if (reference.hasComputedPrice() == true)
		return reference.computedPrice;

	// Creation and init of computed price
	var basePrice = reference.basePrice;
	if (isNaN(basePrice)) basePrice = 0;
	var baseVatPrice = reference.baseVatPrice;
	if (isNaN(baseVatPrice)) baseVatPrice = 0;

	var vatRate = reference.vatRate;
	if (isNaN(vatRate) || (vatRate == 0)) vatRate = this._defaultVatRate;

	var discountedPrice = reference.discountedPrice;
	if (isNaN(discountedPrice)) discountedPrice = 0;
	var discountedVatPrice = reference.discountedVatPrice;
	if (isNaN(discountedVatPrice)) discountedVatPrice = 0;

	var clientDiscountPercentage = reference.clientDiscountPercentage;
	if (isNaN(clientDiscountPercentage)) clientDiscountPercentage = 0;
	var applyClientDiscountPercentageOnDiscountedPrice = reference.applyClientDiscountPercentageOnDiscountedPrice;

	// Base prices
	var oPrice = this.validatePrice(basePrice, baseVatPrice, vatRate, true);
	basePrice 	= oPrice.price;
	baseVatPrice= oPrice.vatPrice;
	vatRate		= oPrice.vatRate;

	// Init of computed price
	var computedPrice = new GshpComputedPrice();
	computedPrice.setVat(vatRate)
	computedPrice.setBasePrice(basePrice, baseVatPrice);
	computedPrice.setDiscountedPrice(basePrice, baseVatPrice, 0.0);
	reference.setComputedPrice(computedPrice);

	// Discounted prices
	// -Flash sale
	var flashSale = product.flashSale;
	if ((flashSale != null) && (flashSale.isValid() == true)) {
		if (flashSale.priceType == 'price')	{
			discountedPrice		= flashSale.price;
			discountedVatPrice	= this.calculateVatPrice(flashSale.price, vatRate);
		}
		else {
			discountedPrice		= this.calculatePrice(flashSale.price, vatRate);
			discountedVatPrice	= flashSale.price;
		}

		computedPrice.setDiscountedPrice(discountedPrice, discountedVatPrice, 0.0);
		computedPrice.setValidityDates(product.flashSale.startDate, product.flashSale.endDate);
	}
	else
	// - B to B : Custom price
	if ((this._priceSystemType == 'B2B') && (this._basketType != "B2C")) {
		discountedPrice		= reference.customPriceB2B;
		discountedVatPrice	= this.calculateVatPrice(discountedPrice, vatRate);

		computedPrice.setDiscountedPrice(discountedPrice, discountedVatPrice, 0.0);
		computedPrice.setCustomPriceB2B(reference.customRateB2B, reference.discountB2B, discountedPrice);
	}
	else
	// - B to C : Base/Special prices with client discount
	{
		var discountedIsBasePrices = false;
		if ((discountedPrice == 0) && (discountedVatPrice == 0)) {
			discountedIsBasePrices = true;
			discountedPrice = basePrice;
			discountedVatPrice = baseVatPrice;
		}
		if ((clientDiscountPercentage > 0) && (discountedIsBasePrices == false) && (applyClientDiscountPercentageOnDiscountedPrice == false)) 
			clientDiscountPercentage = 0.0;
		if (discountedIsBasePrices == false) {
			var oPrice = this.validatePrice(discountedPrice, discountedVatPrice, vatRate, false);
			discountedPrice 	= oPrice.price;
			discountedVatPrice	= oPrice.vatPrice;
		}

		computedPrice.setDiscountedPrice(discountedPrice, discountedVatPrice, clientDiscountPercentage);
	}

	// Add-on by manager complement
	if ((this._oComplement != null) && (typeof(this._oComplement.computePrice) == "function"))
		this._oComplement.computePrice(this, product, reference, computedPrice);

	return computedPrice;
}

GshpPriceManager.prototype.validatePrice = function(price, vatPrice, vatRate, canModifyVatRate)
{
	var oPrice = new Object();
	oPrice.price	= price;
	oPrice.vatPrice	= vatPrice;
	oPrice.vatRate	= vatRate;

	if (this._vatCalculation == "price") {
		if (canModifyVatRate)	oPrice.vatRate = this.roundRate(vatRate);
		oPrice.vatPrice = this.roundPrice(vatPrice);
		oPrice.price	= this.calculatePrice(oPrice.vatPrice, oPrice.vatRate);
	}
	else
	if (this._vatCalculation == "vatPrice") {
		if (canModifyVatRate)	oPrice.vatRate = this.roundRate(vatRate);
		oPrice.price = this.roundPrice(price);
		oPrice.vatPrice = this.calculateVatPrice(oPrice.price, oPrice.vatRate);
	}
	else
	if ((this._vatCalculation == "vat") && (price != 0) && (canModifyVatRate == true)) {
		oPrice.price	= this.roundPrice(price);
		oPrice.vatPrice = this.roundPrice(vatPrice);
		oPrice.vatRate	= this.calculateVatRate(oPrice.price, oPrice.vatPrice);
	}
	return oPrice;
}

GshpPriceManager.prototype.formatProductPrice = function(product, reference)
{
	if (reference == null) return "No available reference";

	// Recovery of computed price
	var oPrice 		= this.computePrice(product, reference);
	var basePrice 	= oPrice.basePrice;
	var baseVatPrice= oPrice.baseVatPrice;
	var vatRate 	= oPrice.vatRate;
	var price 		= oPrice.price;
	var vatPrice 	= oPrice.vatPrice;
	var clientDiscountPercentage = oPrice.clientDiscountPercentage;

	// Client percentage discount
	if (clientDiscountPercentage > 0) {
		price 	= this.roundPrice(price - (price * clientDiscountPercentage / 100.0));
		vatPrice= this.calculateVatPrice(price, vatRate);
	}

	// Display of prices
	var vatDisplayMode	= this._vatDisplayMode;
	var showPriceType	= this._showPriceType;
	var showCounterValue= (product.mode == GshpPriceManager.prototype.PACK_MODE) ? false : this._showCounterValue;
	if (price != basePrice) {
		return this.formatDiscountedPriceAccordingToVatDisplayMode(product, reference, basePrice, baseVatPrice, price, vatPrice, vatDisplayMode, showPriceType, showCounterValue);
	} else {
		return this.formatPriceAccordingToVatDisplayMode(product, reference, basePrice, baseVatPrice, vatDisplayMode, showPriceType, showCounterValue);
	}
}

GshpPriceManager.prototype.formatPriceAccordingToVatDisplayMode = function(product, reference, price, vatPrice, vatDisplayMode, showPriceType, showCounterValue)
{
	switch (vatDisplayMode) {
		case "vatFree":
			return this.formatPrice(product, reference, price, " HT", showPriceType, showCounterValue);
		case "vat":
			return this.formatPrice(product, reference, vatPrice, " TTC", showPriceType, showCounterValue);
		default:
			return this.formatPrice(product, reference, price, " HT", showPriceType, showCounterValue) + "<span class='gshpSeparatorPrices'> - </span>" + this.formatPrice(product, reference, vatPrice, " TTC", showPriceType, showCounterValue);
	}
}

GshpPriceManager.prototype.formatDiscountedPriceAccordingToVatDisplayMode = function(product, reference, basePrice, baseVatPrice, price, vatPrice, vatDisplayMode, showPriceType, showCounterValue)
{
	switch (vatDisplayMode) {
		case "vatFree":
			return this.formatDiscountedPrice(product, reference, basePrice, price, " HT", showPriceType, showCounterValue);
		case "vat":
			return this.formatDiscountedPrice(product, reference, baseVatPrice, vatPrice, " TTC", showPriceType, showCounterValue);
		default:
			return this.formatDiscountedPrice(product, reference, basePrice, price, " HT", showPriceType, showCounterValue) + "<span class='gshpSeparatorPrices'> - </span>" + this.formatDiscountedPrice(product, reference, baseVatPrice, vatPrice, " TTC", showPriceType, showCounterValue);
	}
}

GshpPriceManager.prototype.formatPrice = function(product, reference, price, priceType, showPriceType, showCounterValue)
{
	// Override by manager complement
	if ((this._oComplement != null) && (typeof(this._oComplement.overridenFormatPrice) == "function"))
		return this._oComplement.overridenFormatPrice(this, product, reference, price, priceType, showPriceType, showCounterValue);

	// Default treatment
	if (priceType == null) priceType = "";

	var str = this.formatPriceValue(price, this._currency);
	if (showPriceType == true) str += priceType;
	if (showCounterValue  == true) {
		var counterPrice = price * this._counterValueRate;
		str += " <span class='gshpCounterValue'>(" + this.formatPriceValue(counterPrice, this._counterValueCurrency);
		if (showPriceType == true) str += priceType;
		str += ")</span>";
	}
	return str;
}

GshpPriceManager.prototype.formatDiscountedPrice = function(product, reference, price, discountedPrice, priceType, showPriceType, showCounterValue)
{
	// Override by manager complement
	if ((this._oComplement != null) && (typeof(this._oComplement.overridenFormatDiscountedPrice) == "function"))
		return this._oComplement.overridenFormatDiscountedPrice(this, product, reference, price, discountedPrice, priceType, showPriceType, showCounterValue);

	// Default treatment
	if (priceType == null) priceType = "";

	var str = "<span class='gshpDiscountedPriceContainer'>";
	if (this._hideDashedBasePrices == false) {
		str += "<span class='gshpDashedPrice'>";
		str += this.formatPriceValue(price, this._currency);
		if (showPriceType == true) str += priceType;
		str += "</span>";

		str += "<span class='gshpSeparatorDashedDiscountedPrices'>&#160;</span>";
	}

	str += "<span class='gshpDiscountedPrice'>";
	str += this.formatPriceValue(discountedPrice, this._currency);
	if (showPriceType == true) str += priceType;
	if (showCounterValue == true) {
		var counterPrice = discountedPrice * this._counterValueRate;
		str += " <span class='gshpCounterValue'>(" + this.formatPriceValue(counterPrice, this._counterValueCurrency);
		if (showPriceType == true) str += priceType;
		str += ")</span>";
	}
	str += "</span>";
	str += "</span>";
	return str;
}

GshpPriceManager.prototype.formatPriceValue = function(money, unit)
{
	return gshpFormatPriceValue(money, unit);
}

//	-------------------------------------------------------------------------
//	Display of prices
//	-------------------------------------------------------------------------
GshpPriceManager.prototype.showCurrentProductPrices = function()
{
	if (this.isInit() == false) return;
	if (this.currentProduct == null) return;

	// Update of 'add to basket' link title adding current persistent basket label
	if ((this._basketType == 'B2B') && (this._hasPersistentBasketManagementPage == true))
		this._updateAddToBasketLinkTitle("addToBasket");

	// Analysis and display of product and its references
	this._studyReferences(this.currentProduct);
	this.showProductReferences(this.currentProduct);
}

GshpPriceManager.prototype.showPackPrices = function()
{
	if (this.isInit() == false) return;
	if (this.currentPack == null) return;

	// Analysis of pack items
	var managePlusMinus = false;
	var productList = this.currentPack.productList;
	for (var ind=0; ind<productList.length; ind++) {
		var product = productList[ind];

		// Analysis
		this._studyReferences(product);

		// Recovery of existence flag of current product in pack
		if (product.isCurrentProduct == true)
			this.currentPack.hasCurrentProduct = true;

		// Recovery of maximun count of commandable reference to know if you manage plus/minus link
		if ((product.nbReference - product.nbNotCommandableReference) > 1)
			this.currentPack.managePlusMinus = true;
	}

	// Display
	for (var ind=0; ind<productList.length; ind++) {
		var product = productList[ind];
		this.showProductReferences(product);
	}

	// Update of prices
	this._updatePackPrice();
}

//	-------------------------------------------------------------------------
//	Management of events
//	-------------------------------------------------------------------------
GshpPriceManager.prototype.onChangeDimension = function(select)
{
	var idData = select.id.split("_");
	if (idData.length < 4) return;
	var productKey 	= idData[1] + "_" + idData[2];	// oid  and use
	var n 			= parseInt(idData[3], 10) -1;
	var product 	= this._productMap[productKey];
	if (product == null) return;

	var dimensions = new Array();
	for (var i=0; i<=n; i++) {
		var dimensionCodes = product.dimensionCodes[i];
		if (dimensionCodes == null) continue;
		var referenceDimensionSelect = document.getElementById("gshpReferenceDimensionSelect_" + product.oid + "_" + product.use + "_" + (i+1));
		dimensions[i] = referenceDimensionSelect.value;
	}
	for (var i=n+1; i<5; i++) {
		var dimensionCodes = product.dimensionCodes[i];
		if (dimensionCodes == null) continue;
		this._fillOptions(product, i, dimensions);
		return;
	}
	this._selectReference(product, dimensions);

	// Update of pack price (with discount percentage for each pack item)
	if (product.isSelectedPackItem() == true)
		this._updatePackPrice();

	// Add-on by manager complement
	if ((this._oComplement != null) && (typeof(this._oComplement.onChangeDimension) == "function"))
		this._oComplement.onChangeDimension(this, select, product, dimensions);
}

GshpPriceManager.prototype.onMouseOverQuantityGridInput = function(productOid, referenceOid, productUse)
{
	var key = productOid + "_" + productUse;
	var product = this._productMap[key];
	var reference = product.references[referenceOid];
	if ((product == null) || (reference == null)) return;

	// Display of reference data
	product.setReferenceWithMouseOver(reference);
	this.showGridReferenceData(product, reference);

	// Add-on by manager complement
	if ((this._oComplement != null) && (typeof(this._oComplement.onMouseOverQuantityGridInput) == "function"))
		this._oComplement.onMouseOverQuantityGridInput(this, product, reference);
}

GshpPriceManager.prototype.onMouseOutQuantityGridInput = function(productOid, referenceOid, productUse)
{
	var key = productOid + "_" + productUse;
	var product = this._productMap[key];
	var reference = product.references[referenceOid];
	if ((product == null) || (reference == null)) return;

	// Refresh of timer to hide reference data
	product.setReferenceWithMouseOver(null);
	this.refreshGridReferenceDataLastDate = new Date().getTime();
	setTimeout("gshpRefreshGridReferenceData()", this.refreshGridReferenceDataTimeout);

	// Add-on by manager complement
	if ((this._oComplement != null) && (typeof(this._oComplement.onMouseOutQuantityGridInput) == "function"))
		this._oComplement.onMouseOutQuantityGridInput(this, product, reference);
}

GshpPriceManager.prototype.onFocusQuantityGridInput = function(productOid, referenceOid, productUse)
{
	var key = productOid + "_" + productUse;
	var product = this._productMap[key];
	var reference = product.references[referenceOid];
	if ((product == null) || (reference == null)) return;

	// Display of reference date
	product.setCurrentReference(reference);
	this.showGridReferenceData(product, reference);

	// Add-on by manager complement
	if ((this._oComplement != null) && (typeof(this._oComplement.onFocusQuantityGridInput) == "function"))
		this._oComplement.onFocusQuantityGridInput(this, product, reference);
}

GshpPriceManager.prototype.onBlurQuantityGridInput = function(productOid, referenceOid, productUse)
{
	var key = productOid + "_" + productUse;
	var product = this._productMap[key];
	var reference = product.references[referenceOid];
	if ((product == null) || (reference == null)) return;

	// Hiding of reference data
	product.setCurrentReference(null);
	this.hideGridReferenceData(product);

	// Add-on by manager complement
	if ((this._oComplement != null) && (typeof(this._oComplement.onBlurQuantityGridInput) == "function"))
		this._oComplement.onBlurQuantityGridInput(this, product, reference);
}

GshpPriceManager.prototype.onChangeQuantityGridInput = function(productOid, referenceOid, productUse)
{
	var key = productOid + "_" + productUse;
	var product = this._productMap[key];
	var reference = product.references[referenceOid];
	if ((product == null) || (reference == null)) return;
	
	// Management of "By How Much"
	if (reference.byHowMuch > 1) {
		var quantityInput = document.getElementById(reference.quantityGridInputId);
		if (quantityInput != null) {
			var quantity = parseInt(quantityInput.value, 10);
			if (isNaN(quantity) || (quantity < 0)) quantity = 0;
			if (quantity != 0) {
				var multiple1 = (quantity/reference.byHowMuch);
				var multiple2 = Math.ceil(multiple1);
				if (multiple2 != multiple1)
					quantityInput.value = multiple2 * reference.byHowMuch;
			}
		}	
	}

	// Display of total quantity and amounts
	this._showGridTotalQuantityAndAmounts(product);

	// Add-on by manager complement
	if ((this._oComplement != null) && (typeof(this._oComplement.onChangeQuantityGridInput) == "function"))
		this._oComplement.onChangeQuantityGridInput(this, product, reference);
}

GshpPriceManager.prototype.onClickPackItem = function(checkbox)
{
	var idData = checkbox.id.split("_");
	if (idData.length < 3) return;
	var productKey	= idData[2] + "_" + this.getProductUse(GshpPriceManager.prototype.PACK_MODE);	// oid  and pack use
	var product 	= this._productMap[productKey];
	if (product == null) return;

	// Update of product flag
	product.isCheckedPackItem = checkbox.checked;

	// Update of pack price (with discount percentage for each pack item)
	this._updatePackPrice();

	// Add-on by manager complement
	if ((this._oComplement != null) && (typeof(this._oComplement.onClickPackItem) == "function"))
		this._oComplement.onClickPackItem(this, checkbox, product);
}

GshpPriceManager.prototype.onCustomizePackItem = function(link)
{
	var idData = link.id.split("_");
	if (idData.length < 3) return;
	var productOid	= idData[2];
	var productKey	= productOid + "_" + this.getProductUse(GshpPriceManager.prototype.PACK_MODE);	// oid  and pack use
	var product 	= this._productMap[productKey];
	if (product == null) return;

	// Add-on by manager complement
	if ((this._oComplement != null) && (typeof(this._oComplement.onCustomizePackItem) == "function")) {
		var onChange = this._oComplement.onCustomizePackItem(this, product);
		if (onChange == true)
			this.onChangePackItemCustomization(product.oid);
	}
}

GshpPriceManager.prototype.onChangeCurrentProductCustomization = function()
{
	if (this.currentProduct == null) return;

	// Add-on by manager complement
	if ((this._oComplement != null) && (typeof(this._oComplement.onChangeCurrentProductCustomization) == "function"))
		this._oComplement.onChangeCurrentProductCustomization(this, this.currentProduct);
}

GshpPriceManager.prototype.onChangePackItemCustomization = function(productOid)
{
	var productKey	= productOid + "_" + this.getProductUse(GshpPriceManager.prototype.PACK_MODE);	// oid  and pack use
	var product 	= this._productMap[productKey];
	if (product == null) return;

	// Add-on by manager complement
	if ((this._oComplement != null) && (typeof(this._oComplement.onChangePackItemCustomization) == "function"))
		this._oComplement.onChangePackItemCustomization(this, product);
}

//	-------------------------------------------------------------------------
//	Display of reference data (prices, code, warning message, add button, ...)
//	-------------------------------------------------------------------------
GshpPriceManager.prototype.showReference = function(product, reference)
{
	if ((product == null) || (reference == null)) return;

	// Reference data
	this._showReferenceData(product, reference);

	// Button to add reference into basket
	if ((this._activateStockRules == true) && (reference.stockRule != null)) {
		if (product.mode == GshpPriceManager.prototype.CURRENTPRODUCT_MODE) {
			this._showDocumentElements(reference.canCommand(), new Array("addToBasket","gshpCreatePersistentBasket"));
		}
	}

	// Add-on by manager complement
	if ((this._oComplement != null) && (typeof(this._oComplement.showReference) == "function"))
		this._oComplement.showReference(this, product, reference);
}

GshpPriceManager.prototype._showReferenceData = function(product, reference)
{
	// Data (price, stock and codes)
	if (product.mode == GshpPriceManager.prototype.CURRENTPRODUCT_MODE) {
		// Price
		var refPriceValueSpan = document.getElementById("gshpReferencePriceValue");
		if (refPriceValueSpan != null) refPriceValueSpan.innerHTML = this.formatProductPrice(product, reference);

		// Ecotax
		var refEcoTaxSpan = document.getElementById("gshpReferenceEcoTax");
		if (refEcoTaxSpan != null) refEcoTaxSpan.style.display = (reference.ecoTax > 0) ? "inline" : "none";
		var refEcoTaxValueSpan = document.getElementById("gshpReferenceEcoTaxValue");
		if (refEcoTaxValueSpan != null) refEcoTaxValueSpan.innerHTML = this.formatPriceValue(reference.ecoTax, this._currency);

		// Stock
		var refStockSpan = document.getElementById("gshpReferenceStock");
		if (refStockSpan != null) refStockSpan.innerHTML = (reference.stock < 0) ? 0 : reference.stock;

		// Codes
		var refCodeSpan = document.getElementById("gshpReferenceCode");
		if (refCodeSpan != null) refCodeSpan.innerHTML = reference.code;

		var refPublicCodeSpan = document.getElementById("gshpReferencePublicCode");
		if (refPublicCodeSpan != null) refPublicCodeSpan.innerHTML = reference.publicCode;
	}
	else
	if (product.mode == GshpPriceManager.prototype.PACK_MODE) {
		// Price
		var refPriceValueSpan = document.getElementById("gshpPackReferencePriceValue_" + product.oid);
		if (refPriceValueSpan != null) refPriceValueSpan.innerHTML = this.formatProductPrice(product, reference);
	}

	// Stock message
	var stockRule = reference.stockRule;
	if ((this._activateStockRules == true) && (stockRule != null)) {
		// Warning message is necessary only for "current product" mode if :
		// - All references are hidden 			WarningStockMsg_AllHiddenRef
		// - According to stock rule			WarningStockMsg_??
		if (product.mode == GshpPriceManager.prototype.CURRENTPRODUCT_MODE) {
			if (product.allRefAreHidden == true) {
				if (this._showWarningStockMsg_AllHiddenRef == true) {
					var warningStockMsgSpan_AllHiddenRef = document.getElementById("gshpWarningStockMsg_AllHiddenRef");
					if (warningStockMsgSpan_AllHiddenRef != null) {
						warningStockMsgSpan_AllHiddenRef.style.display = "block";
						warningStockMsgSpan_AllHiddenRef.innerHTML = this._warningStockMsgLabel_AllHiddenRef;
					}
				}
			}
			else {
				// AnyStock not commandable, GoodStock, WarningStock and CriticalStock
				var stockRuleTypes = new Array("AS_NC", "GS_R", "GS_NR", "WS_R", "WS_NR", "CS_R", "CS_NR");
				for (var ind=0; ind<stockRuleTypes.length; ind++) {
					var stockRuleType 	= stockRuleTypes[ind];
					var elementId 		= "gshpWarningStockMsg_" + stockRuleType;
					var warningStockMsgSpan = document.getElementById(elementId);
					if (warningStockMsgSpan != null) 	{
						// Element is hidden if it's not the current stock rule or if message is empty
						var displayMsg = ((stockRule.getType() == stockRuleType) && stockRule.haveWarningMsg());
						warningStockMsgSpan.style.display = displayMsg ? "block" : "none";
						warningStockMsgSpan.innerHTML = displayMsg ? stockRule.getWarningMsg() : "";
					}
				}
			}
		}
	}
}

GshpPriceManager.prototype.showGridReferenceData = function(product, reference)
{
	// Override by manager complement
	if ((this._oComplement != null) && (typeof(this._oComplement.overridenShowGridReferenceData) == "function"))
		return this._oComplement.overridenShowGridReferenceData(this, product, reference);

	// Data to show
	this._showReferenceData(product, reference);
	
	// Add-on by manager complement
	if ((this._oComplement != null) && (typeof(this._oComplement.showGridReferenceData) == "function"))
		this._oComplement.showGridReferenceData(this, product, reference);
}

GshpPriceManager.prototype.hideGridReferenceData = function(product)
{
	// Override by manager complement
	if ((this._oComplement != null) && (typeof(this._oComplement.overridenHideGridReferenceData) == "function"))
		return this._oComplement.overridenHideGridReferenceData(this, product);
	
	// Data to hide
	// - misc (price, stock and code)
	if (product.mode == GshpPriceManager.prototype.CURRENTPRODUCT_MODE) {
		// Price
		var refPriceValueSpan = document.getElementById("gshpReferencePriceValue");
		if (refPriceValueSpan != null) refPriceValueSpan.innerHTML = "";

		// Stock
		var refStockSpan = document.getElementById("gshpReferenceStock");
		if (refStockSpan != null) refStockSpan.innerHTML = "";

		// Codes
		var refCodeSpan = document.getElementById("gshpReferenceCode");
		if (refCodeSpan != null) refCodeSpan.innerHTML = "";

		var refPublicCodeSpan = document.getElementById("gshpReferencePublicCode");
		if (refPublicCodeSpan != null) refPublicCodeSpan.innerHTML = "";
	}
	else
	if (product.mode == GshpPriceManager.prototype.PACK_MODE) {
		// Price
		var refPriceValueSpan = document.getElementById("gshpPackReferencePriceValue_" + product.oid);
		if (refPriceValueSpan != null) refPriceValueSpan.innerHTML = "";
	}

	// - stock messages
	if (this._activateStockRules == true) {
		if (product.mode == GshpPriceManager.prototype.CURRENTPRODUCT_MODE) {
			if (product.allRefAreHidden == false) {
				// AnyStock not commandable, GoodStock, WarningStock and CriticalStock
				var stockRuleTypes = new Array("AS_NC", "GS_R", "GS_NR", "WS_R", "WS_NR", "CS_R", "CS_NR");
				for (var ind=0; ind<stockRuleTypes.length; ind++) {
					var stockRuleType 	= stockRuleTypes[ind];
					var elementId 		= "gshpWarningStockMsg_" + stockRuleType;
					var warningStockMsgSpan = document.getElementById(elementId);
					if (warningStockMsgSpan != null) 	{
						// Element is hidden if it's not the current stock rule or if message is empty
						warningStockMsgSpan.style.display = "none";
						warningStockMsgSpan.innerHTML = "";
					}
				}
			}
		}
	}
}

//	-------------------------------------------------------------------------
//	Display of product references (representation of its references using with select, grid, ...)
//	-------------------------------------------------------------------------
GshpPriceManager.prototype.showProductReferences = function(product)
{
	if ((product == null) || (product.studied == false)) return;

	// Pack
	if (product.mode == GshpPriceManager.prototype.PACK_MODE) {
		// Dimensions are not visible for moment
		var packDiv = document.getElementById("gshpPackDiv_dimensions_" + product.oid);
		if (packDiv != null) {
			packDiv.style.display = "none";
		}

		// If all references are not commandable, we can not see product or pack if product is the current product in card
		if (product.allRefAreNotCommandable	== true) {
			if (product.isCurrentProduct == true) {
				if (this.currentPack != null)
					this.currentPack.isHidden = true;

				var divPack = document.getElementById("gshpPackDiv");
				if (divPack != null) {
					divPack.style.display = "none";
				}
			}
			else {
				var packRow = document.getElementById("gshpPackRow_data_" + product.oid);
				if (packRow != null) {
					packRow.style.display = "none";
				}
			}
		}
		// Mamangement of plusMinus div
		else {
			this._buildPackDivPlusMinus(product);
		}
	}

	// Product reference(s)
	var dimensionRender = this.getDimensionsRender(product.mode);
	if ((dimensionRender == "1row") || (dimensionRender == "2rows")) {
		this._showStandardProductPrices(product);
	}
	else
	if ((product.mode == GshpPriceManager.prototype.CURRENTPRODUCT_MODE) && (dimensionRender == "grid")) {
		this._showGridProductPrices(product);
	}
	else {
		alert("Dimension render [" + dimensionRender + "] can't be managed for product [ " + product.label + "] in mode [ " + product.mode + "]!");
	}

	// Add-on by manager complement
	if ((this._oComplement != null) && (typeof(this._oComplement.showProductReferences) == "function"))
		this._oComplement.showProductReferences(this, product);
}

//	-------------------------------------------------------------------------
//	Private functions
//	-------------------------------------------------------------------------
GshpPriceManager.prototype._showDocumentElements = function(bShow, elementIds)
{
	var display = (bShow ? "block" : "none");
	for (var i=0; i<elementIds.length; i++) {
		var element = document.getElementById(elementIds[i]);
		if (element != null)
			element.style.display = display;
	}
}

GshpPriceManager.prototype._updateAddToBasketLinkTitle = function(addToBasketEltId)
{
	var addToBasketElt = document.getElementById(addToBasketEltId);
	if (addToBasketElt != null) {
		// Recovery of current persistent basket label or default label if automatic creation is possible
		var persistentBasketLabel = "";
		if (this.currentBasket && (this.currentBasket.oid != "")) 
			persistentBasketLabel = this.currentBasket.label;
		else
		if ((this._nbCommandType > 0) && (this._nbValidCommandType == 1))
			persistentBasketLabel = objThesaurus.translate("gshpNewPersistentBasketLabel");

		// Recovery of link element
		if (persistentBasketLabel != "") {
			var addToBasketLink = null;
			if (addToBasketElt.tagName.toLowerCase() == "a") 
				addToBasketLink = addToBasketElt;
			else {
				for (var i=0; i<addToBasketElt.childNodes.length; i++) {
					var child = addToBasketElt.childNodes[i];
					if (child.tagName.toLowerCase() == "a") {
						addToBasketLink = child;
						break;
					}
				}
			}
			if (addToBasketLink != null)
				addToBasketLink.title = objThesaurus.translate("gshpAddToNamedBasket", ""+persistentBasketLabel);
		}
	}
}

GshpPriceManager.prototype._showStandardProductPrices = function(product)
{
	// Filling of selects
	var first = true;
	for (var i=0; i<5; i++) {
		var dimensionCodes = product.dimensionCodes[i];
		if (dimensionCodes == null) {
			var referenceDimensionRow = document.getElementById("gshpReferenceDimensionRow_" + product.oid + "_" + product.use + "_" + (i+1));
			if (referenceDimensionRow != null) {
				referenceDimensionRow.style.display = "none";
			}
		}
		if (!first) continue;
		first = false;
		var referenceDimensionSelect = document.getElementById("gshpReferenceDimensionSelect_" + product.oid + "_" + product.use + "_" + (i+1));
		if (referenceDimensionSelect == null) {
			this._selectReference(product, new Array());
			break;
		}
		for (var oid in dimensionCodes) {
			var label = dimensionCodes[oid];
			var option = document.createElement("OPTION");
			option.text = label;
			option.value = oid;
			referenceDimensionSelect.options.add(option);
		}
		referenceDimensionSelect.selectedIndex = 0;
		this.onChangeDimension(referenceDimensionSelect);
	}
}

GshpPriceManager.prototype._showGridProductPrices = function(product)
{
	var tbody = document.getElementById("gshpReferenceDimensionTBody_grid_" + product.oid + "_" + product.use);
	if (tbody == null) return;

	// Recovery of dimension models to manage
	var nbModel = 0;
	var indModelVert = indModelHoriz = -1;
	for (var i=0; i<5; i++) {
		var dimensionCodes = product.dimensionCodes[i];
		if ((dimensionCodes != null) && (product.dimensionModels[i] != null)) {
			nbModel++;
			if (indModelHoriz == -1) indModelHoriz = i;
			else
			if (indModelVert == -1) indModelVert = i;
		}
	}

	// Creation of grid
	if (nbModel > 2)
		alert("This mode doesn't manage more than 2 dimension models!");
	else {
		if (nbModel == 0) {
			// Recovery of reference without dimension
			var dimensions = new Array("", "", "", "", "");
			var reference = product.getReferenceByDimensions(dimensions);
			if ((reference != null) && (reference.isHidden() == false)) {
				// TR
				var tr = document.createElement("tr");
				tr.className = "gshpReferenceDimensionRow_quantities";
				tbody.appendChild(tr);

				// TD (quantity input)
				var td = document.createElement("td");
				td.className = "textAlignCenter verticalAlignMiddle gshpReferenceDimensionCell_quantity";
				td.innerHTML = this._getQuantityGridInputHtml(product, reference);
				tr.appendChild(td);
			}
		}
		else
		if ((nbModel >= 1) && (nbModel <= 2)) {
			// Recovery of all dimension values
			var allDimensionValuesVert	= (indModelVert != -1) ? product.dimensionModels[indModelVert].valueMap : null;
			var allDimensionValuesHoriz	= (indModelHoriz != -1) ? product.dimensionModels[indModelHoriz].valueMap : null;

			// Recovery of used (and not hidden, Cf studyReferences) dimension values
			var usedDimensionValuesVert	= (indModelVert != -1) ? product.dimensionCodes[indModelVert] : null;
			var usedDimensionValuesHoriz= (indModelHoriz != -1) ? product.dimensionCodes[indModelHoriz] : null;

			// Recovery of nb used dimension values
			var nbUsedDimensionValuesVert	= 0;
			var nbUsedDimensionValuesHoriz	= 0;

			// First Line (labels)
			if ((allDimensionValuesVert != null) && (usedDimensionValuesVert != null)) {
				// TR
				var tr = document.createElement("tr");
				tr.className = "gshpReferenceDimensionRow_labels";
				tbody.appendChild(tr);

				// TD (empty)
				var td = document.createElement("td");
				td.className = "gshpReferenceDimensionCell_empty";
				td.innerHTML = "<span></span>";
				tr.appendChild(td);

				for (var oidVert in allDimensionValuesVert) {
					// Test if this dimension value is used by one product reference
					if (usedDimensionValuesVert[oidVert] == null) continue;
					nbUsedDimensionValuesVert++;

					// TD (label of dimension value)
					var td = document.createElement("td");
					td.className = "textAlignCenter verticalAlignMiddle gshpReferenceDimensionCell_dimValueLabel";
					td.innerHTML = "<span>" + allDimensionValuesVert[oidVert] + "</span>";
					tr.appendChild(td);
				}

				// TD (label of total quantity)
				if (nbUsedDimensionValuesVert > 1) {
					var td = document.createElement("td");
					td.className = "textAlignCenter verticalAlignMiddle gshpReferenceDimensionCell_totalQuantityLabel";
					td.innerHTML = "<span></span>";
					tr.appendChild(td);
				}
			}

			// Next Lines (label and quantities)
			if ((allDimensionValuesHoriz != null) && (usedDimensionValuesHoriz != null)) {
				var dimensions = new Array("", "", "", "", "");
				for (var oidHoriz in allDimensionValuesHoriz) {
					// Test if this dimension value is used by one product reference
					if (usedDimensionValuesHoriz[oidHoriz] == null) continue;
					nbUsedDimensionValuesHoriz++;

					// Init of current dimension
					dimensions[indModelHoriz] = oidHoriz;

					// TR
					var tr = document.createElement("tr");
					tr.className = "gshpReferenceDimensionRow_quantities";
					tr.id = 'gshpReferenceDimensionRow_' + product.oid + '_' + product.use + '_1_' + oidHoriz;
					tbody.appendChild(tr);

					// TD (label of dimension value)
					var td = document.createElement("td");
					td.className = "textAlignLeft verticalAlignMiddle gshpReferenceDimensionCell_dimValueLabel";
					var innerHtml = "<span>" + allDimensionValuesHoriz[oidHoriz] + "</span>";
					td.innerHTML = innerHtml;
					tr.appendChild(td);

					if ((allDimensionValuesVert == null) || (usedDimensionValuesVert == null)) {
						// Recovery of reference from current dimensions
						var reference = product.getReferenceByDimensions(dimensions);

						// TD (quantity input)
						var td = document.createElement("td");
						td.className = "textAlignCenter verticalAlignMiddle gshpReferenceDimensionCell_quantity";
						td.innerHTML = this._getQuantityGridInputHtml(product, reference);
						tr.appendChild(td);
					}
					else {
						for (var oidVert in allDimensionValuesVert) {
							// Test if this dimension value is used by one product reference
							if (usedDimensionValuesVert[oidVert] == null) continue;

							// Init of current dimension
							dimensions[indModelVert] = oidVert;

							// Recovery of reference from current dimensions
							var reference = product.getReferenceByDimensions(dimensions);

							// TD (quantity input)
							var td = document.createElement("td");
							td.className = "textAlignCenter verticalAlignMiddle gshpReferenceDimensionCell_quantity";
							td.innerHTML = this._getQuantityGridInputHtml(product, reference);
							tr.appendChild(td);
						}
					}

					// TD (total quantity)
					if (nbUsedDimensionValuesVert > 1) {
						var td = document.createElement("td");
						var spanId = "gshpDimensionQuantityGridSpan_" + product.oid + "_" + oidHoriz + "_" + product.use;
						td.className = "textAlignCenter verticalAlignMiddle gshpReferenceDimensionCell_totalQuantity";
						td.innerHTML = "<span id='" + spanId + "'>0</span>";
						tr.appendChild(td);
						product.addDimensionQuantityGridSpanId(oidHoriz, spanId);
					}
				}
			}

			// Last line (total quantities)
			if (nbUsedDimensionValuesHoriz > 1) {
				// TR
				var tr = document.createElement("tr");
				tr.className = "gshpReferenceDimensionRow_sum";
				tbody.appendChild(tr);

				// TD (label of total quantity)
				var td = document.createElement("td");
				td.className = "textAlignLeft verticalAlignMiddle gshpReferenceDimensionCell_totalQuantityLabel";
				var innerHtml = "<span></span>";
				td.innerHTML = innerHtml;
				tr.appendChild(td);

				if ((allDimensionValuesVert == null) || (usedDimensionValuesVert == null)) {
					// TD (total quantity)
					var td = document.createElement("td");
					var spanId = "gshpDimensionQuantityGridSpan_" + product.oid + "_*_" + product.use;
					td.className = "textAlignCenter verticalAlignMiddle gshpReferenceDimensionCell_totalQuantity";
					td.innerHTML = "<span id='" + spanId + "'>0</span>";
					tr.appendChild(td);
					product.addDimensionQuantityGridSpanId("*", spanId);
				}
				else {
					for (var oidVert in allDimensionValuesVert) {
						// Test if this dimension value is used by one product reference
						if (usedDimensionValuesVert[oidVert] == null) continue;

						// TD (total quantity)
						var td = document.createElement("td");
						var spanId = "gshpDimensionQuantityGridSpan_" + product.oid + "_" + oidVert + "_" + product.use;
						td.className = "textAlignCenter verticalAlignMiddle gshpReferenceDimensionCell_totalQuantity";
						td.innerHTML = "<span id='" + spanId + "'>0</span>";
						tr.appendChild(td);
						product.addDimensionQuantityGridSpanId(oidVert, spanId);
					}
				}

				// TD (empty)
				if (nbUsedDimensionValuesVert > 1) {
					var td = document.createElement("td");
					td.className = "textAlignCenter verticalAlignMiddle gshpReferenceDimensionCell_empty";
					td.innerHTML = "<span></span>";
					tr.appendChild(td);
				}
			}
		}

		// Button to add references into basket
		if ((product.allRefAreNotCommandable == true) && (product.mode == GshpPriceManager.prototype.CURRENTPRODUCT_MODE)) {
			this._showDocumentElements(false, new Array("addToBasket","gshpCreatePersistentBasket"));
		}

		// Display of total quantity and amounts
		this._showGridTotalQuantityAndAmounts(product);

		// Display of message about grid
		var gridMsgSpan = document.getElementById("gshpDimensionsRenderMsg_grid");
		if (gridMsgSpan != null) {
			var displayMsg = (this._requestedReferenceQuantityMap != null);
			var msg = objThesaurus.translate("gshpAddToBasketMsg"+(product.hasUnavailableRequestedReference?"Error":"")+"FromGrid");
			gridMsgSpan.style.display = displayMsg ? "block" : "none";
			gridMsgSpan.innerHTML = displayMsg ? msg : "";
		}
	}
}

GshpPriceManager.prototype._getQuantityGridInputHtml = function(product, reference)
{
	var inputId			= "";
	var attrId 			= "";
	var attrValue 		= "";
	var attrDisabled	= " disabled='disabled'";
	var attrClass 		= " class='gshpQuantityDisabledInput'";
	var attrTitle		= "";
	var attrOnKeyPress	= "";
	var attrOnMouseOver	= "";
	var attrOnMouseOut	= "";
	var attrOnFocus		= "";
	var attrOnBlur		= "";
	var attrOnChange	= "";
	var isUnavailableStock = false;
	if (reference != null) {
		var requestedQuantity = null;
		if (this._requestedReferenceQuantityMap != null)	requestedQuantity = this._requestedReferenceQuantityMap[reference.oid];
		if (requestedQuantity == null)						requestedQuantity = reference.basketQuantity;
		
		inputId	= "gshpReferenceQuantityGridInput_" + reference.oid + "_" + product.use;
		attrId	= " id='" + inputId + "'";
		if ((reference.canCommand() == true) || (reference.basketQuantity > 0)) {
			attrDisabled= "";
			attrClass	= " class='gshpQuantityInput";
			if (requestedQuantity > reference.basketQuantity)	{
				attrClass += " gshpAvailableMaxQuantity";
				isUnavailableStock = true;
			}
			attrClass	+= "'";
			attrValue	= ((reference.basketQuantity > 0) || (isUnavailableStock == true)) ? (" value = '" + reference.basketQuantity + "'") : "";
			var title	= "";
			if (reference.byHowMuch > 1)
				title	+= objThesaurus.translate("gshpToolTipByHowMuch").replace(/%1/g, ""+ reference.byHowMuch);
			if (reference.minimalQuantity > 1) {
				if (title != "") title += (navigator.appName == "Microsoft Internet Explorer") ? "\n" : " - ";
				title += objThesaurus.translate("gshpToolTipMinimalQuantity") + reference.minimalQuantity;
			}
			attrTitle			= " title='" + title.replace(/'/g, "\\\'") + "'";
			attrOnKeyPress		= " onKeyPress='return gshpCheckNumericKeyPressed(event);'";
			var paramsRollOver	= "\"" + product.oid + "\", \"" + reference.oid + "\", \"" + product.use + "\"";
			attrOnMouseOver		= " onMouseOver='objGshpPriceManager.onMouseOverQuantityGridInput("+paramsRollOver+");'";
			attrOnMouseOut		= " onMouseOut='objGshpPriceManager.onMouseOutQuantityGridInput("+paramsRollOver+")'";
			attrOnFocus			= " onFocus='objGshpPriceManager.onFocusQuantityGridInput("+paramsRollOver+")'";
			attrOnBlur			= " onBlur='objGshpPriceManager.onBlurQuantityGridInput("+paramsRollOver+")'";
			attrOnChange		= " onChange='objGshpPriceManager.onChangeQuantityGridInput("+paramsRollOver+")'";
		}
		reference.setQuantityGridInputId(inputId);
	}

	// Update of availibity flag
	if (isUnavailableStock == true)
		product.hasUnavailableRequestedReference = true;
	return "<input type='text'" + attrId + attrValue + attrDisabled + attrClass + attrTitle + attrOnKeyPress + attrOnMouseOver + attrOnMouseOut + attrOnFocus + attrOnBlur + attrOnChange + "/>";
}

GshpPriceManager.prototype._showGridTotalQuantityAndAmounts = function(product)
{
	// Recovery of quantities and amounts according to selected references
	var totalQuantity = totalAmount = totalVatAmount = 0;
	var dimensionTotalQuantities = new Object();
	for (var refOid in product.references) {
		var reference = product.references[refOid];
		if (reference.quantityGridInputId != "") {
			// Recovery of quantity
			var quantity = 0;
			var quantityInput = document.getElementById(reference.quantityGridInputId);
			if (quantityInput != null) {
				quantity = parseInt(quantityInput.value, 10);
				if (isNaN(quantity) || (quantity < 0)) quantity = 0;
			}

			// Updates
			if (quantity > 0) {
				// - of global quantity
				totalQuantity += quantity;

				// - of quantity of dimensions
				if (product.useOpenDimension == true) {
					var openDimension = reference.openDimension;
					var dimTotalQuantity = dimensionTotalQuantities[openDimension];
					if (dimTotalQuantity == null) dimTotalQuantity = 0;
					dimensionTotalQuantities[openDimension] = dimTotalQuantity + quantity;
				}
				else {
					for (var i=0; i<5; i++) {
						var dimOid = reference.dimensionOids[i];
						if (dimOid == "") continue;
						var dimTotalQuantity = dimensionTotalQuantities[dimOid];
						if (dimTotalQuantity == null) dimTotalQuantity = 0;
						dimensionTotalQuantities[dimOid] = dimTotalQuantity + quantity;
					}
				}

				// - of amounts
				var oPrice = this.computePrice(product, reference);
				totalAmount += quantity * oPrice.price;
				totalVatAmount += quantity * oPrice.vatPrice;
			}
		}
	}

	// Update of span
	for (var dimOid in product.dimensionQuantityGridSpanIds) {
		var quantity = (dimOid != "*") ? dimensionTotalQuantities[dimOid] : totalQuantity;
		if (quantity == null) quantity = 0; 

		var spanId = product.dimensionQuantityGridSpanIds[dimOid];
		var span = document.getElementById(spanId);
		if (span != null) 	span.innerHTML = quantity;
	}

	// Update of inputs
	var totalQuantityInput = document.getElementById("gshpBasketTotalGridQuantity");
	if (totalQuantityInput != null) 	totalQuantityInput.value = totalQuantity;

	var totalAmountInput = document.getElementById("gshpBasketTotalGridAmount");
	if (totalAmountInput != null)		totalAmountInput.value = this.formatPriceValue(totalAmount, "");

	var totalVatAmountInput = document.getElementById("gshpBasketTotalGridVatAmount");
	if (totalVatAmountInput != null)	totalVatAmountInput.value = this.formatPriceValue(totalVatAmount, "");
}

GshpPriceManager.prototype._studyReferences = function(product)
{
	// Init of dimensions
	product.studied 		= true;
	product.dimensionCodes	= new Array();
	product.referenceByDim	= new Object();

	var nbReference = 0;
	var nbNotCommandableReference = 0;
	var nbHiddenReference = 0;
	for (var refOid in product.references) {
		nbReference++;
		var reference = product.references[refOid];

		// Management of stock rules
		if (this._activateStockRules == true) {
			// Recovery of stock rule for reference
			var stockRuleKey = this.getStockRuleKey(reference);
			var stockRule = this._stockRules[stockRuleKey];
			if (stockRule == null) {
				alert("Stock rule with key [" + stockRuleKey + "] is null.");
				continue;
			}
			reference.setStockRule(stockRule);

			// Treatment of not commandable references
			if (reference.canCommand() == false) {
				nbNotCommandableReference++;
				if (reference.isHidden() == true) {
					nbHiddenReference++;
					continue;
				}
			}
		}

		// Management of dimensions
		var dimRef = "";
		if (product.useOpenDimension == true) {
			var openDimension = reference.openDimension;
			dimRef = openDimension;
			if (product.dimensionCodes[0] == null) product.dimensionCodes[0] = new Object();
			product.dimensionCodes[0][openDimension] = openDimension;
		}
		else {
			for (var i=0; i<5; i++) {
				var oid = reference.dimensionOids[i];
				dimRef += oid + "|";
				if (oid == "") continue;
				if (product.dimensionCodes[i] == null) product.dimensionCodes[i] = new Object();
				product.dimensionCodes[i][oid] = reference.dimensionLabels[i];
			}
		}
		product.referenceByDim[dimRef] = reference.oid;
	}

	// Recovery of count
	product.nbReference					= nbReference;
	product.nbNotCommandableReference	= nbNotCommandableReference;
	product.nbHiddenReference			= nbHiddenReference;

	// Detection if all references are not commandable or hidden
	product.allRefAreNotCommandable = (nbReference == nbNotCommandableReference);
	product.allRefAreHidden   		= (nbReference == nbHiddenReference);
}

GshpPriceManager.prototype._buildPackDivPlusMinus = function(product)
{
	var div = document.getElementById("gshpPackDiv_plusMinus_" + product.oid);
	if (div != null ) {
		if (this.currentPack.managePlusMinus == true) {
			var img = document.createElement("img");
			img.id = "gshpPackImg_plusMinus_" + product.oid;
			img.align = "absbottom";
			img.style.width = "16px";
			img.style.height = "16px";
			img.border = 0;

			if (product.nbReference - product.nbNotCommandableReference > 1) {
				var a = document.createElement("a");
				a.href = "#";
				a.id = "gshpPackLink_plusMinus_" + product.oid;
				a.onclick = gshpOnClickPackPlusMinus;

				img.src = GshpPriceManager.prototype.PLUS_ICON;
				a.appendChild(img);
				div.appendChild(a);
			}
			else {
				img.src = GshpPriceManager.prototype.EMPTY_ICON;
				div.appendChild(img);
			}
		}
	}
}

GshpPriceManager.prototype._fillOptions = function(product, n, dimensions)
{
	var referenceDimensionSelect = document.getElementById("gshpReferenceDimensionSelect_" + product.oid + "_" + product.use + "_" + (n+1));
	while (referenceDimensionSelect.firstChild) {
		referenceDimensionSelect.removeChild(referenceDimensionSelect.firstChild);
	}
	var values = new Object();
	for (var refOid in product.references) {
		var reference = product.references[refOid];

		var ok = true;
		if (product.useOpenDimension == true) {
			var dimension = dimensions[0];
			if ((dimension != null) && (dimension != reference.openDimension))
				ok = false;
		}
		else {
			for (var i=0; i<5; i++) {
				var dimension = dimensions[i];
				if (dimension == null) continue;
				var oid = reference.dimensionOids[i];
				if (oid != dimension) {
					ok = false;
					break;
				}
			}
		}

		// Reference is hidden
		if (ok == true) {
			if (((product.mode == GshpPriceManager.prototype.CURRENTPRODUCT_MODE) && (reference.isHidden() == true)) ||
				((product.mode == GshpPriceManager.prototype.PACK_MODE) && (reference.canCommand() == false)))
			ok = false;
		}

		if (ok) {
			if (product.useOpenDimension == true) {
				var dimensionOid	= reference.openDimension;
				var dimensionLabel	= reference.openDimension;
			}
			else {
				var dimensionOid	= reference.dimensionOids[n];
				var dimensionLabel	= reference.dimensionLabels[n];
			}
			values[dimensionOid] = dimensionLabel;
		}
	}
	for (var oid in values) {
		var label = values[oid];
		var option = document.createElement("OPTION");
		option.text = label;
		option.value = oid;
		referenceDimensionSelect.options.add(option);
	}
	this.onChangeDimension(referenceDimensionSelect);
}

GshpPriceManager.prototype._selectReference = function(product, dimensions)
{
	var reference = product.getReferenceByDimensions(dimensions);
	if (reference != null) {
		product.setCurrentReference(reference);
		this.showReference(product, reference);
	}
}

GshpPriceManager.prototype._buildReferenceDescription = function(product, reference, customization, quantity)
{
	if ((product == null) || (reference == null)) return "";

	// Recovery of computed price
	var oPrice 			= this.computePrice(product, reference);
	var basePrice 		= oPrice.basePrice;
	var baseVatPrice	= oPrice.baseVatPrice;
	var vatRate 		= oPrice.vatRate;
	var price 			= oPrice.price;
	var vatPrice 		= oPrice.vatPrice;
	var customRateB2B	= oPrice.customRateB2B;
	var discountB2B		= oPrice.discountB2B;
	var clientDiscountPercentage = oPrice.clientDiscountPercentage;

	// Description
	var referenceDescr = "";
	referenceDescr = "basketCode=" + objStringUtils.escape(reference.code, "#|");
	referenceDescr += "#basketLabel=" + objStringUtils.escape(product.label, "#|");
	referenceDescr += "#basketCustomization=" + objStringUtils.escape(customization, "#|");
	referenceDescr += "#basketQuantity=" + quantity;
	referenceDescr += "#basketImportance=" + ((this.currentProduct && (product.oid == this.currentProduct.oid)) ? 0 : 1);
	referenceDescr += "#basketPrice=" + price;
	referenceDescr += "#basketBasePrice=" + basePrice;
	referenceDescr += "#basketVat=" + vatRate;
	referenceDescr += "#basketReference=" + objStringUtils.escape(reference.oid, "#|");
	if (this._basketType == "B2B") {
		referenceDescr += "#basketPriceSystemCombination=" + this._priceSystemCombination;
		referenceDescr += "#basketCustomRate=" + (customRateB2B ? customRateB2B : "");
		referenceDescr += "#basketDiscount=" + (discountB2B ? discountB2B : "");	
	}
	else
	if (this._basketType == "B2C") {
		referenceDescr += "#basketVatPrice=" + vatPrice;
		referenceDescr += "#basketBaseVatPrice=" + baseVatPrice;
		referenceDescr += "#basketClientDiscountPercentage=" + clientDiscountPercentage;	
	}

	return referenceDescr;
}

GshpPriceManager.prototype._buildPackItemDescription = function(product, quantity)
{
	if (product == null) return "";

	var packItemDescr = "";
	var reference = product.currentReference;
	if ((reference != null) && (reference.canCommand() == true)) {
		// Recovery of pack item customization
		var customization = "";
		var customizationInput = document.getElementById("gshpPackItemCustomization_" + product.oid);
		if (customizationInput != null)
			customization = customizationInput.value;

		// Recovery of pack discount percentage
		var packDiscountPercentage	= product.packDiscountPercentage;

		// Description
		packItemDescr = this._buildReferenceDescription(product, reference, customization, quantity);
		if (packItemDescr != "") {
			packItemDescr += "#basketPackDiscountPercentage=" + packDiscountPercentage;
		}
	}
	return packItemDescr;
}

GshpPriceManager.prototype._updatePackPrice = function()
{
	if (this.currentPack == null) return;

	// Pack items
	var productList = this.currentPack.productList;

	// Recovery of count of selected pack item
	var nbSelectedPackItem = 0;
	for (var ind=0; ind<productList.length; ind++) {
		var product = productList[ind];
		if (product.isSelectedPackItem() == true) {
			nbSelectedPackItem++;
		}
	}

	// Calculation of prices according to pack discount percentages
	var percentageList = this.currentPack.getDiscountPercentageList(nbSelectedPackItem);

	// Calculation of totals (prices and discounts)
	var subTotalPrice = subTotalVatPrice = 0.0;
	var totalPrice = totalVatPrice = 0.0;

	var indPackItem = 0;
	for (var ind=0; ind<productList.length; ind++) {
		var product = productList[ind];
		if (product.isSelectedPackItem() == true) {
			var reference = product.currentReference;

			// Recovery of computed price
			var oPrice 		= this.computePrice(product, reference);
			var basePrice 	= oPrice.basePrice;
			var baseVatPrice= oPrice.baseVatPrice;
			var vatRate 	= oPrice.vatRate;
			var price 		= oPrice.price;
			var vatPrice 	= oPrice.vatPrice;
			var clientDiscountPercentage = oPrice.clientDiscountPercentage;

			// Recovery of pack dsicount percentage
			var packDiscountPercentage 		= percentageList[indPackItem];
			product.packDiscountPercentage	= packDiscountPercentage;

			// Client percentage discount
			if (clientDiscountPercentage > 0) {
				price 	= this.roundPrice(price - (price * clientDiscountPercentage / 100.0));
				vatPrice= this.calculateVatPrice(price, vatRate);
			}

			// Sub total (prices without pack discount)
			subTotalPrice += price;
			subTotalVatPrice += vatPrice;

			// Total (prices with pack discount)
			if (packDiscountPercentage > 0) {
				price 	= this.roundPrice(price - (price * packDiscountPercentage / 100.0));
				vatPrice= this.calculateVatPrice(price, vatRate);
			}
			totalPrice += price;
			totalVatPrice += vatPrice;

			indPackItem++;
		}
	}

	// Price of selected pack items
	var priceValueSpan = document.getElementById("gshpPackItemsPriceValue");
	if (priceValueSpan != null) priceValueSpan.innerHTML = this.formatPriceAccordingToVatDisplayMode(null, null, subTotalPrice, subTotalVatPrice, this._vatDisplayMode, this._showPriceType, false);

	// Discount value
	var discountValueSpan = document.getElementById("gshpPackDiscountValue");
	if (discountValueSpan != null) discountValueSpan.innerHTML = this.formatPriceAccordingToVatDisplayMode(null, null, subTotalPrice-totalPrice, subTotalVatPrice-totalVatPrice, this._vatDisplayMode, this._showPriceType, false);

	// Price of pack
	var priceValueSpan = document.getElementById("gshpPackPriceValue");
	if (priceValueSpan != null) priceValueSpan.innerHTML = this.formatPriceAccordingToVatDisplayMode(null, null, totalPrice, totalVatPrice, this._vatDisplayMode, this._showPriceType, false);
}

//	-------------------------------------------------------------------------
//	addReferenceToBasket, addReferenceToBasketB2B, addCurrentProductToBasket,  addCurrentPackToBasket and addCurrentAnythingToBasket
//	Adding of data to basket
//	Returns : True if adding
//	-------------------------------------------------------------------------
GshpPriceManager.prototype.addReferenceToBasket = function(	formId,
															iRefOid, sCode, sLabel, sCustomization,
															iQuantity,
															dPrice, dVatPrice,
															dBasePrice, dBaseVatPrice,
															dVat,
															dClientDiscountPercentage )
{
	// Checking of data
	var errorMsg = "";
	var form = null;
	if (this.isInit() == false) 
		errorMsg = "Price manager is not initialized!";
	else
	if (this._basketType != "B2C") 
		errorMsg = "The function addReferenceToBasket is invalid for the basket type [" + this._basketType + "]!";
	else
	if ((formId == null) || (formId == ""))
		errorMsg = "The form id to send reference is invalid!";
	else
	if ((iRefOid == null) || isNaN(iRefOid))
		errorMsg = "The reference id is invalid!";
	else
	if ((sCode == null) || (sCode == ""))
		errorMsg = "The reference code is invalid!";
	else {
		if (sLabel == null) sLabel = "";
		if (typeof(sLabel) != "string") sLabel = "" + sLabel;
		if (sCustomization == null) sCustomization = "";
		if (typeof(sCustomization) != "string") sCustomization = "" + sCustomization;
		if ((iQuantity == null) || (typeof(iQuantity) != "number") || (iQuantity < 1)) iQuantity = 1;
		if ((dPrice == null) || (typeof(dPrice) != "number")) dPrice = 0.0;
		if ((dVatPrice == null) || (typeof(dVatPrice) != "number")) dVatPrice = 0.0;
		if ((dBasePrice == null) || (typeof(dBasePrice) != "number")) dBasePrice = 0.0;
		if ((dBaseVatPrice == null) || (typeof(dBaseVatPrice) != "number")) dBaseVatPrice = 0.0;
		if ((dVat == null) || (typeof(dVat) != "number")) dVat = this._defaultVatRate;
		if ((dClientDiscountPercentage == null) || (typeof(dClientDiscountPercentage) != "number")) dClientDiscountPercentage = 0.0;

		// Recovery of form
		form = document.getElementById(formId);
		if (form == null)
			errorMsg = "The form [" + formId + "] to sent reference is not defined!";
	}

	// Error message
	if (errorMsg != "") {
		alert(errorMsg);
		return false;
	}

	// Update and submit of form
	var addToBasketForm = this.addToBasketForms[formId];
	if (addToBasketForm != null) {
		if ((addToBasketForm.action != null) && (addToBasketForm.action != ""))
			form.action							= addToBasketForm.action;
		if ((addToBasketForm.target != null) && (addToBasketForm.target != ""))
			form.target							= addToBasketForm.target;
	}
	form.cmd.value								= "addReference";
	form.basketCode.value						= sCode;
	form.basketLabel.value						= sLabel;
	form.basketCustomization.value				= sCustomization;
	form.basketQuantity.value					= iQuantity;
	form.basketPrice.value						= dPrice;
	form.basketVatPrice.value					= dVatPrice;
	form.basketBasePrice.value					= dBasePrice;
	form.basketBaseVatPrice.value				= dBaseVatPrice;
	form.basketVat.value						= dVat;
	form.basketClientDiscountPercentage.value	= dClientDiscountPercentage;
	form.basketReference.value					= iRefOid;

	form.submit();
	return true;
}

GshpPriceManager.prototype.addReferenceToBasketB2B = function(	formId,
																iRefOid, sCode, sLabel, sCustomization,
																iQuantity,
																dPrice, dBasePrice, dVat,
																sPriceSystemCombination, dCustomRate, dDiscount)
{
	// Checking of data
	var errorMsg = "";
	var form = null;
	if (this.isInit() == false) 
		errorMsg = "Price manager is not initialized!";
	else
	if (this._basketType != "B2B") 
		errorMsg = "The function addReferenceToBasketB2B is invalid for the basket type [" + this._basketType + "]!";
	else
	if ((formId == null) || (formId == ""))
		errorMsg = "The form id to send reference is invalid!";
	else
	if ((iRefOid == null) || isNaN(iRefOid))
		errorMsg = "The reference id is invalid!";
	else
	if ((sCode == null) || (sCode == ""))
		errorMsg = "The reference code is invalid!";
	else {
		if ((formId == null) || (formId == "")) return false;
		if ((iRefOid == null) || isNaN(iRefOid)) return false;
		if ((sCode == null) || (sCode == "")) return false;
		if (sLabel == null) sLabel = "";
		if (typeof(sLabel) != "string") sLabel = "" + sLabel;
		if (sCustomization == null) sCustomization = "";
		if (typeof(sCustomization) != "string") sCustomization = "" + sCustomization;
		if ((iQuantity == null) || (typeof(iQuantity) != "number") || (iQuantity < 1)) iQuantity = 1;
		if ((dPrice == null) || (typeof(dPrice) != "number")) dPrice = 0.0;
		if ((dBasePrice == null) || (typeof(dBasePrice) != "number")) dBasePrice = 0.0;
		if ((dVat == null) || (typeof(dVat) != "number")) dVat = this._defaultVatRate;
		if (sPriceSystemCombination == null) sPriceSystemCombination = "basePrice";
		if ((dCustomRate == null) || (typeof(dCustomRate) != "number")) dCustomRate = "";
		if ((dDiscount == null) || (typeof(dDiscount) != "number")) dDiscount = "";

		// Recovery of form
		form = document.getElementById(formId);
		if (form == null)
			errorMsg = "The form [" + formId + "] to sent reference is not defined!";
	}

	// Error message
	if (errorMsg != "") {
		alert(errorMsg);
		return false;
	}

	// Update and submit of form
	var addToBasketForm = this.addToBasketForms[formId];
	if (addToBasketForm != null) {
		if ((addToBasketForm.action != null) && (addToBasketForm.action != ""))
			form.action							= addToBasketForm.action;
		if ((addToBasketForm.target != null) && (addToBasketForm.target != ""))
			form.target							= addToBasketForm.target;
	}
	form.cmd.value								= "addReference";
	form.basketCode.value						= sCode;
	form.basketLabel.value						= sLabel;
	form.basketCustomization.value				= sCustomization;
	form.basketQuantity.value					= iQuantity;
	form.basketPrice.value						= dPrice;
	form.basketBasePrice.value					= dBasePrice;
	form.basketVat.value						= dVat;
	form.basketPriceSystemCombination.value		= sPriceSystemCombination;
	form.basketCustomRate.value					= dCustomRate;
	form.basketDiscount.value					= dDiscount;
	form.basketReference.value					= iRefOid;

	form.submit();
	return true;
}

GshpPriceManager.prototype.addCurrentProductToBasket = function()
{
	// Recovery of current product
	if (this.currentProduct == null) {
		alert("No current product!");
		return false;
	}

	// Add into basket depends of dimensions render
	var productMode = this.currentProduct.mode;
	var dimensionRender = this.getDimensionsRender(productMode);
	if ((dimensionRender == "1row") || (dimensionRender == "2rows")) {
		return this._addCurrentReferenceToBasket(this.currentProduct);
	}
	else
	if ((productMode == GshpPriceManager.prototype.CURRENTPRODUCT_MODE) && (dimensionRender == "grid")) {
		return this._addGridReferencesToBasket(this.currentProduct);
	}
	return false;
}


GshpPriceManager.prototype.addCurrentPackToBasket = function()
{
	if (this.currentPack == null) return false;
	if (this.currentPack.isHidden == true) return false;

	// Recovery of form
	var formId = this.addPackToBasketFormId;
	var form = document.getElementById(formId);
	if (form == null) {
		alert("The form [" + formId + "] to sent pack is not defined!");
		return false;
	}

	// Recovery of descriptions for selected references
	var quantity = 1;
	var packReferencesDescr = "";
	var productList = this.currentPack.productList;
	for (var ind=0; ind<productList.length; ind++) {
		var product = productList[ind];
		if (product.isSelectedPackItem() == true) {
			var description = this._buildPackItemDescription(product, quantity);
			if (description != "") {
				if (packReferencesDescr != "") packReferencesDescr += "|";
				packReferencesDescr += description;
			}
		}
	}

	// Update of form
	if (packReferencesDescr != "") {
		var addToBasketForm = this.addToBasketForms[formId];
		if (addToBasketForm != null) {
			if ((addToBasketForm.action != null) && (addToBasketForm.action != ""))
				form.action				= addToBasketForm.action;
			if ((addToBasketForm.target != null) && (addToBasketForm.target != ""))
				form.target				= addToBasketForm.target;
		}
		form.cmd.value					= "addPack";
		form.basketPack.value			= this.currentPack.oid;
		form.basketQuantity.value		= quantity;
		form.basketReferencesDescr.value= packReferencesDescr;

		form.submit();
		return true;
	}
	return false;
}

GshpPriceManager.prototype.addCurrentAnythingToBasket = function()
{
	var addTo = this.addCurrentPackToBasket();
	if (addTo == false)
		addTo = this.addCurrentProductToBasket();
	return addTo;
}

GshpPriceManager.prototype._addCurrentReferenceToBasket = function(product)
{
	// Recovery of current reference
	var reference = product ? product.currentReference : null;
	if (reference == null) {
		alert("No current reference!");
		return false;
	}

	// Recovery of form
	var formId = this.addReferenceToBasketFormId;
	var form = document.getElementById(formId);
	if (form == null) {
		alert("The form [" + formId + "] to sent reference is not defined!");
		return false;
	}

	// Recovery of quantity
	var quantity = 1;
	var quantityInput = document.getElementById("gshpBasketQuantityInput");
	if (quantityInput != null) {
		quantity = parseInt(quantityInput.value, 10);
		if (isNaN(quantity) || quantity < 1) quantity = 1;
	}

	// Recovery of computed price
	var oPrice 			= this.computePrice(product, reference);
	var basePrice 		= oPrice.basePrice;
	var baseVatPrice	= oPrice.baseVatPrice;
	var vatRate 		= oPrice.vatRate;
	var price 			= oPrice.price;
	var vatPrice 		= oPrice.vatPrice;
	var customRateB2B	= oPrice.customRateB2B;
	var discountB2B		= oPrice.discountB2B;	
	var clientDiscountPercentage = oPrice.clientDiscountPercentage;

	// Update and submit of form (Customization is not done here)
	var addToBasketForm = this.addToBasketForms[formId];
	if (addToBasketForm != null) {
		if ((addToBasketForm.action != null) && (addToBasketForm.action != ""))
			form.action							= addToBasketForm.action;
		if ((addToBasketForm.target != null) && (addToBasketForm.target != ""))
			form.target							= addToBasketForm.target;
	}
	form.cmd.value 								= "addReference";
	form.basketCode.value 						= reference.code;
	form.basketLabel.value 						= this.currentProduct.label;
	form.basketQuantity.value 					= quantity;
	form.basketPrice.value 						= price;
	form.basketBasePrice.value 					= basePrice;
	form.basketVat.value 						= vatRate;
	form.basketReference.value 					= reference.oid;
	if (this._basketType == "B2B") {
		form.basketPriceSystemCombination.value = this._priceSystemCombination;
		form.basketCustomRate.value 			= (customRateB2B ? customRateB2B : "");
		form.basketDiscount.value 				= (discountB2B ? discountB2B : "");
	}
	else
	if (this._basketType == "B2C") {
		form.basketVatPrice.value 				= vatPrice;
		form.basketBaseVatPrice.value 			= baseVatPrice;
		form.basketClientDiscountPercentage.value 	= clientDiscountPercentage;
	}

	form.submit();
	return true;
}

GshpPriceManager.prototype.getModifiedReferencesDescr = function(product)
{
	if(product == null) product = this.currentProduct;
	var referencesDescr = "";
	for (var refOid in product.references) {
		var reference = product.references[refOid];
		if (reference.quantityGridInputId != "") {
			// Recovery of quantity
			var quantity = 0;
			var quantityInput = document.getElementById(reference.quantityGridInputId);
			if (quantityInput != null) {
				quantity = parseInt(quantityInput.value, 10);
				if (isNaN(quantity) || quantity < 0) quantity = 0;
			}

			// Description is generated if required quantity is different of basket quantity
			if (quantity != reference.basketQuantity) {
				var description = this._buildReferenceDescription(product, reference, "", quantity);
				if (description != "") {
					if (referencesDescr != "") referencesDescr += "|";
					referencesDescr += description;
				}
			}
		}
	}
	return referencesDescr;
}

GshpPriceManager.prototype._addGridReferencesToBasket = function(product)
{
	// Recovery of form
	var formId = this.addReferencesToBasketFormId;
	var form = document.getElementById(formId);
	if (form == null) {
		alert("The form [" + formId + "] to sent several references is not defined!");
		return false;
	}

	// Recovery of descriptions for selected references
	var referencesDescr = this.getModifiedReferencesDescr(product);

	// Update and submit of form
	if (referencesDescr != "") {
		var addToBasketForm = this.addToBasketForms[formId];
		if (addToBasketForm != null) {
			if ((addToBasketForm.action != null) && (addToBasketForm.action != ""))
				form.action				= addToBasketForm.action;
			if ((addToBasketForm.target != null) && (addToBasketForm.target != ""))
				form.target				= addToBasketForm.target;
		}
		form.cmd.value					= "manageReferences";
		form.basketReferencesDescr.value= referencesDescr;

		form.submit();
		return true;
	}
}


//	-------------------------------------------------------------------------
//	getStockRuleKey
//	Generation of key about stock rule
//	-------------------------------------------------------------------------
GshpPriceManager.prototype.getStockRuleKey = function(reference)
{
	var key = "";
	if (reference.notCommandable == true)
		key += "AS_NC";
	else {
		if (reference.stock > reference.warningStock)
			key += "GS_";
		else
		if ((reference.warningStock >= reference.stock ) && (reference.stock > reference.criticalStock))
			key += "WS_";
		else
			key += "CS_";
		key += reference.notReorderable ? "NR" : "R";
	}
	return key;
}


//	-------------------------------------------------------------------------
//	getManagerComplement/setManagerComplement
//	Get/Set of price manager complement
//	-------------------------------------------------------------------------
GshpPriceManager.prototype.getManagerComplement = function()
{
	return this._oComplement;
}

GshpPriceManager.prototype.setManagerComplement = function(managerComplement)
{
	this._oComplement = managerComplement;
}


//
// ------------------------------------- class GshpMode
//
function GshpMode(mode, productUse, dimensionsRender)
{
	this.mode 				= mode;
	this.productUse			= productUse;
	this.dimensionsRender	= dimensionsRender;
}


//
// ------------------------------------- class GshpDimensionModel
//
function GshpDimensionModel(rank, isOpen, label)
{
	this.rank		= rank;
	this.isOpen		= isOpen;
	this.label		= label;
	this.valueMap	= new Object();
}

GshpDimensionModel.prototype.addValue = function(record)
{
	if ((this.isOpen == true) && (record.length == 1))
		this.valueMap[record[0]] = record[0];
	else
	if ((this.isOpen == false) && (record.length == 2))
		this.valueMap[record[0]] = record[1];
}

//
// ------------------------------------- class GshpStockRule
//
function GshpStockRule(type, actionOnRef, showWarningMsg, warningMsg)
{
	this._type				= type;
	this._actionOnRef		= actionOnRef;
	this._showWarningMsg	= showWarningMsg;
	this._warningMsg		= warningMsg;
}

GshpStockRule.prototype.isHiddenReference = function()
{
	return (this._actionOnRef == "hideRef");
}

GshpStockRule.prototype.canCommandReference = function()
{
	return (this._actionOnRef == "authorizeRefCommand");
}

GshpStockRule.prototype.cannotCommandReference = function()
{
	return (this._actionOnRef != "authorizeRefCommand");;
}

GshpStockRule.prototype.haveWarningMsg = function()
{
	return ((this._showWarningMsg == true) && (this._warningMsg != ""));
}

GshpStockRule.prototype.getType = function()
{
	return this._type;
}

GshpStockRule.prototype.getWarningMsg = function()
{
	if (this.haveWarningMsg() == true)
		return this._warningMsg;
	return "";
}


//
// ------------------------------------- class GshpComputedPrice
//
function GshpComputedPrice(reference)
{
	this.basePrice = 0.0;
	this.baseVatPrice = 0.0;
	this.vatRate = 0.0
	this.price = 0.0;
	this.vatPrice = 0.0;
	this.clientDiscountPercentage = 0.0;
	this.customRateB2B = null;
	this.discountB2B = null;
	this.customPriceB2B = 0.0;	

	this.startValidityDate = null;
	this.endValidityDate = null;
}

GshpComputedPrice.prototype.isValid = function()
{
	var now = new Date().getTime();
	return (((this.startValidityDate == null) || (this.startValidityDate <= now)) &&
			((this.endValidityDate == null) || (now <= this.endValidityDate)));
}

GshpComputedPrice.prototype.setVat = function(vatRate)
{
	this.vatRate = vatRate;
}

GshpComputedPrice.prototype.setBasePrice = function(price, vatPrice)
{
	this.basePrice = price;
	this.baseVatPrice = vatPrice;
	this.setDiscountedPrice(price, vatPrice, 0.0);
}

GshpComputedPrice.prototype.setDiscountedPrice = function(price, vatPrice, clientDiscountPercentage)
{
	this.price = price;
	this.vatPrice = vatPrice;
	this.clientDiscountPercentage = clientDiscountPercentage;
}

GshpComputedPrice.prototype.setCustomPriceB2B = function(customRate, discount, customPrice)
{
	this.customRateB2B = customRate;
	this.discountB2B = discount;
	this.customPriceB2B = customPrice;
}

GshpComputedPrice.prototype.setValidityDates = function(startDate, endDate)
{
	this.startValidityDate = startDate;
	this.endValidityDate = endDate;
}


//
// ------------------------------------- class GshpFlashSale
//
function GshpFlashSale(oid, label, startDate, endDate, price, priceType)
{
	this.oid		= oid;
	this.label		= label;
	this.startDate	= startDate;
	this.endDate	= endDate;
	this.price		= price;
	this.priceType	= priceType;
}

GshpFlashSale.prototype.isValid = function()
{
	var now = new Date().getTime();
	return (((this.startDate == null) || (this.startDate <= now)) &&
			((this.endDate == null) || (now <= this.endDate)));
}


//
// ------------------------------------- class GshpPack
//
function GshpPack(oid)
{
	this.oid	= oid;
	this.label 	= "";

	this.isHidden 			= false;
	this.managePlusMinus	= false;
	this.hasCurrentProduct	= false;
	this.productList 		= new Array();

	this.promoOid 				= null;
	this.promoDescription		= "";
	this.discountPercentageLists= new Array();
}

GshpPack.prototype.addProduct = function(product)
{
	if (product.mode == GshpPriceManager.prototype.PACK_MODE)
		this.productList[this.productList.length] = product;
}

GshpPack.prototype.getDiscountPercentageList = function(nbProduct)
{
	var percentageList = this.discountPercentageLists[nbProduct];
	if (percentageList == null)  {
		percentageList = new Array();

		// Recovery of list with less products
		for (var ind=nbProduct-1; ind>=0; ind--) {
			var tmpPercentageList = this.discountPercentageLists[ind];
			if (tmpPercentageList != null) {
				for (var ind2=0; ind2<tmpPercentageList.length; ind2++) {
					percentageList[ind2] = tmpPercentageList[ind2];
				}
				break;
			}
		}

		// 0.0 is complement percentage
		for (var ind=percentageList.length; ind<nbProduct; ind++) {
			percentageList[ind] = 0.0;
		}
	}
	return percentageList;
}

GshpPack.prototype.setPromoModel = function(promoOid, promoDescription)
{
	this.promoOid 			= promoOid;
	this.promoDescription	= promoDescription;
	this._buildDiscountPercentageLists();
}

GshpPack.prototype._buildDiscountPercentageLists = function()
{
	this.discountPercentageLists = new Array();
	var discountList = this.promoDescription.split("\n");
	for (var ind=0; ind<discountList.length; ind++) {
		var discount = discountList[ind];
		if (discount == "") continue;
		var discountValueList = discount.split(" ");

		var percentageList = new Array();
		for (var ind2=0; ind2<discountValueList.length; ind2++) {
			var percentage = parseFloat(discountValueList[ind2]);
			if (isNaN(percentage)) continue;
			percentageList[percentageList.length] = percentage;
		}

		this.discountPercentageLists[percentageList.length] = percentageList;
	}
}


//
// ------------------------------------- class GshpProduct
//
function GshpProduct(mode, use, oid)
{
	this.mode	= mode;
	this.use	= use;
	this.oid	= oid;

	this.studied			= false;
	this.label 				= "";

	this.flashSale			= null;
	this.currentReference	= null;
	this.mouseOverReference	= null;
	this.references 		= new Object();

	this.useOpenDimension	= false;
	this.openDimensionLabel	= "";
	this.dimensionModels 	= new Array(null,null,null,null,null);

	this.dimensionCodes		= new Array();		// Used (visible reference) dimension values
	this.referenceByDim		= new Object();
	this.openCategories		= new Array("","","","","");

	this.nbReference				= 0;
	this.nbNotCommandableReference	= 0;
	this.nbHiddenReference			= 0;

	this.allRefAreNotCommandable= false;
	this.allRefAreHidden 		= false;

	// Data about pack
	this.isCheckedPackItem 		= false;
	this.packDiscountPercentage	= 0.0;

	// Data about dimension render : grid
	this.dimensionQuantityGridSpanIds		= new Object();
	this.hasUnavailableRequestedReference	= false;
}

//	-------------------------------------------------------------------------
//	Get functions
//	-------------------------------------------------------------------------
GshpProduct.prototype.getReferenceByOid = function(oid)
{
	return this.references[oid];
}

GshpProduct.prototype.getReferenceByDimensions = function(dimensions)
{
	for (var refOid in this.references) {
		var reference = this.references[refOid];
		var ok = true;
		if (this.useOpenDimension == true) {
			var dimension = dimensions[0];
			if ((dimension != null) && (dimension != reference.openDimension))
				ok = false;
		}
		else {
			for (var i=0; i<5; i++) {
				var dimension = dimensions[i];
				if (dimension == null) continue;
				var oid = reference.dimensionOids[i];
				if (oid != dimension) {
					ok = false;
					break;
				}
			}
		}

		if (ok)
			return reference;
	}
	return null;
}

//	-------------------------------------------------------------------------
//	Set functions
//	-------------------------------------------------------------------------
GshpProduct.prototype.setFlashSale = function(flashSale)
{
	this.flashSale = flashSale;
}

GshpProduct.prototype.setCurrentReference = function(reference)
{
	if (reference == null)
		this.currentReference = reference;
	else
	if (this.references[reference.oid] != null)
		this.currentReference = reference;
}

GshpProduct.prototype.setReferenceWithMouseOver = function(reference)
{
	if (reference == null)
		this.referenceWithMouseOver = reference;
	else
	if (this.references[reference.oid] != null)
		this.referenceWithMouseOver = reference;
}

//	-------------------------------------------------------------------------
//	Addition of reference
//	-------------------------------------------------------------------------
GshpProduct.prototype.addReference = function(record)
{
	var reference = new GshpReference();
	if (reference != null) {
		reference.init(record);
		this.references[reference.oid] = reference;
	}
	return reference;
}

//	-------------------------------------------------------------------------
//	Addition of span id about grid for count of ordered articles
//	-------------------------------------------------------------------------
GshpProduct.prototype.addDimensionQuantityGridSpanId = function(dimensionOid, spanId)
{
	if (dimensionOid != null)
		this.dimensionQuantityGridSpanIds[dimensionOid] = spanId;
}

//	-------------------------------------------------------------------------
//	Recovery of selection status for pack mode
//	-------------------------------------------------------------------------
GshpProduct.prototype.isSelectedPackItem = function()
{
	return (this.nbReference - this.nbNotCommandableReference > 0) &&
			((this.mode == GshpPriceManager.prototype.PACK_MODE) &&
			((this.isCurrentProduct == true) || (this.isCheckedPackItem == true)));
}


//
// ------------------------------------- class GshpReference
//
function GshpReference()
{
	// Data
	this.oid 				= "";
	this.label 				= "";
	this.code 				= "";
	this.publicCode			= "";

	this.basePrice			= 0.0;
	this.baseVatPrice 		= 0.0;
	this.vatRate 			= 0.0;

	this.customRateB2B		= null;
	this.discountB2B		= null;
	this.customPriceB2B		= 0.0;

	this.ecoTax				= 0.0;

	this.openDimension		= "";
	this.dimensionOids 		= new Array();
	this.dimensionLabels	= new Array();

	this.discountedPrice	= 0.0;
	this.discountedVatPrice	= 0.0;

	this.notCommandable		= false;
	this.notReorderable		= false;

	this.minimalQuantity	= 1;
	this.byHowMuch			= 1;
	this.stock				= 0;
	this.basketQuantity		= 0;
	this.warningStock		= 0;
	this.criticalStock		= 0;

	this.clientDiscountPercentage 						= 0;
	this.applyClientDiscountPercentageOnDiscountedPrice = false;

	this.groupId 			= "";
	this.groupPivot 		= "";

	// Stock rule applied for reference
	this.stockRule	= null;

	// Data about dimension render 'grid'
	this.quantityGridInputId = "";
}

//	-------------------------------------------------------------------------
//	Init
//	-------------------------------------------------------------------------
GshpReference.prototype.init = function(record)
{
	// Reading of record
	this.oid 			= record[0];
	this.code 			= record[1];
	this.publicCode		= record[2];
	this.label 			= record[3];

	this.basePrice		= parseFloat(record[4]);
	this.baseVatPrice 	= parseFloat(record[5]);
	this.vatRate 		= parseFloat(record[6]);
	this.discountedPrice	= parseFloat(record[7]);
	this.discountedVatPrice	= parseFloat(record[8]);
	
	this.customRateB2B	= (record[9] == "") ? null : parseFloat(record[9]);
	this.discountB2B	= (record[10] == "") ? null : parseFloat(record[10]);
	this.customPriceB2B	= parseFloat(record[11]);

	this.openDimension	= record[12];

	this.dimensionOids 	= new Array();
	this.dimensionLabels= new Array();
	for (var i=0; i<5; i++) {
		this.dimensionOids[i]	= record[13 + 2 * i];
		this.dimensionLabels[i] = record[14 + 2 * i];
	}

	this.notCommandable	= (record[23] == "true");
	this.notReorderable	= (record[24] == "true");

	this.stock			= parseInt(record[25], 10);
	this.byHowMuch		= parseInt(record[26], 10);
	this.basketQuantity	= parseInt(record[27], 10);
	this.warningStock	= parseInt(record[28], 10);
	this.criticalStock	= parseInt(record[29], 10);

	this.clientDiscountPercentage 						= parseFloat(record[30]);
	this.applyClientDiscountPercentageOnDiscountedPrice = (record[31] == "true");

	this.ecoTax			= parseFloat(record[32]);

	this.minimalQuantity= parseInt(record[33], 10);

	this.groupId 		= record[34];
	this.groupPivot 	= record[35];
}

//	-------------------------------------------------------------------------
//	Recovery of reference actions
//	-------------------------------------------------------------------------
GshpReference.prototype.canCommand = function()
{
	return !(this.notCommandable || (this.stockRule && this.stockRule.cannotCommandReference()));
}

GshpReference.prototype.isHidden = function()
{
	return (this.stockRule && this.stockRule.isHiddenReference());
}

GshpReference.prototype.hasComputedPrice = function()
{
	return ((this.computedPrice != null) && (this.computedPrice.isValid() == true));
}

//	-------------------------------------------------------------------------
//	Set functions
//	-------------------------------------------------------------------------
GshpReference.prototype.setStockRule = function(stockRule)
{
	this.stockRule = stockRule;
}

GshpReference.prototype.setComputedPrice = function(computedPrice)
{
	this.computedPrice = computedPrice;
}

GshpReference.prototype.setQuantityGridInputId = function(inputId)
{
	this.quantityGridInputId = inputId;
}


// ------------------------------------- Global object
//
var objGshpPriceManagerComplement;	// May be overriden by decor
var objGshpPriceManager = new GshpPriceManager();

// Recovery of overriden of default manager complement
if (objGshpPriceManagerComplement != null)
	objGshpPriceManager.setManagerComplement( objGshpPriceManagerComplement );
else
	objGshpPriceManager.setManagerComplement( new GshpPriceManagerComplement() );
