/**
 * @fileoverview This file contains JavaScript objects that support
 * the L'Oreal Core System V2.2. This file is commented using conventions
 * that support the documenting tool JSDoc
 * {@link http://sourceforge.net/projects/jsdoc JSDoc}
 * Syntax for the comments can be found at:
 * {@link http://jsdoc.sourceforge.net/#tagref JSDoc Comments}
 * {@link http://java.sun.com/j2se/javadoc/writingdoccomments/ Javadoc Comments}
 *
 * @author INS - Fatri Nesimi: <a href="mailto:fatri.nesimi@ins.com">fatri.nesimi@ins.com</a>
 * @author INS - Anthony Sena: <a href="mailto:anthony.sena@ins.com">anthony.sena@ins.com</a>
 * @version 1.0
 */
/** 
 * This function was supported in Ajax so called Atlas. Unfortunately, it seems
 * not to be supported so to let the rest of javascript unchanged I am creating this function instead
 *
 */
 /*
function $(elementId) {
   return document.getElementById(elementId);
}
*/
/**
 * IsTypeDefined is a boolean indicating wether the TYPE is defined or no
 * which is part of the MS AJAX
 */
var IsTypeDefined=false; 
/** 
 * Determines if TYPE is defined and if so, it set a global variable to true
 */
function SetTypeState() {
       if (typeof(Type)!='undefined') {
               IsTypeDefined=true
       }
       else {
            IsTypeDefined=false;
            eval("Core=function() {  }");
       
       }
}
/** 
 * calls SetTypeState and sets it to true if TYPE is defined
 */
SetTypeState();


/*
 * It Creates a namespace using MS Ajax Libraries "making javascript easier" if TYPE is defined
 */
 if (IsTypeDefined){ Type.registerNamespace("Core");  }


/**
 * @class WebServiceAPI_Class is intended to centralize all the webservices calls.
 * If a web service is timed out, the control is passed to js function onTimeout.
 * If an error is raised, the control is passed to js function onError.
 * @constructor
 * @see onTimeout({object} result)
 * @see onError({object} result)
 */ 
Core.WebServiceAPI_Class= function() {
    /*
     * Methods
     */

    /**
     * Used to remove a product from a customer's favorite list
     * @param {string} CustomerId The customer ID GUID
     * @param {string} Topic Code
     * @param {string} TopicType
     * @param {function} OnCompleteFuncName This is the callback function after the web service returns the result data
     */
    this.RemoveTopicFromFavorites=function(CustomerId, TopicCode, TopicType, OnCompleteFuncName) {
        if(!IsAjaxLoaded()) {return false;}

        try {
            DoWait();
            MicrosoftFrance.MCS.Commerce.WS.AJAXProject.FavoritesWebService.FavoriteTopicRemove(CustomerId, TopicCode, TopicType,eval(OnCompleteFuncName),onError);
        }
        catch (e) {
            DoDefault();
            window.status = e.message;
        }
        return false;
    }

    /**
     * Used to add a product to a customer's favorite list
     * @param {string} CustomerId The customer ID GUID
     * @param {int} FavoriteProductType The type of favorite list to retrieve
     * @param {string} RetailerCode The current retailer code
     * @param {string} ProductCode The product code to add to the customer's favorite list
     * @param {function} OnCompleteFuncName This is the callback function after the web service returns the result data
     */
    this.AddToFavorites=function(CustomerId, FavoriteProductType, RetailerCode, ProductCode, OnCompleteFuncName) {
        if(!IsAjaxLoaded()) { return false; }
        try {
            //DoWait();
            MicrosoftFrance.MCS.Commerce.WS.AJAXProject.FavoritesWebService.FavoriteListProductAdd(CustomerId, FavoriteProductType, RetailerCode, ProductCode,eval(OnCompleteFuncName),onError,onTimeout);
        }
        catch (e)  {
            DoDefault();
            window.status = e.message;
        }
        return false;
    }    

    /**
     * Adds rating information for the selected <i>CustomerID</i>, <i>ProductForumName</i> and <i>ProductCode</i>
     * 
     * @param {string} ProductForumName The product forum name used for this rating
     * @param {string} ProductCode The source product code used to find the associated products
     * @param {string} CustomerID String in a form of GUID representing the Customer ID
     * @param {int} RateLevel The integer rating from the customer
     * @param {function} OnCompleteFuncName This is the callback function after the web service returns the result data
     */
    this.AddProductRating=function(ProductForumName, ProductCode, CustomerID, RateLevel, OnCompleteFuncName){
        if(!IsAjaxLoaded()) {return false;}

        try
        {
            //DoWait();
            MicrosoftFrance.MCS.Commerce.WS.AJAXProject.ProductWebService.AddProductRating(ProductForumName, ProductCode, CustomerID, RateLevel,eval(OnCompleteFuncName),onError,onTimeout);

        }
        catch (e)
        {
            DoDefault();
            window.status = e.message;
        }
        return false;
    }

    /** 
     * Checks to see if a product is a part of a customer's favorite list.
     * @param {string} CustomerId The customer ID GUID
     * @param {int} FavoriteProductType The type of favorite list to retrieve
     * @param {string} RetailerCode The current retailer code
     * @param {string} ProductCode The product code to add to the customer's favorite list
     * @param {function} OnCompleteFuncName This is the callback function after the web service returns the result data
     */
    this.FavoriteListProductMembership=function(CustomerId, FavoriteProductType, RetailerCode, ProductCode, OnCompleteFuncName) {    
        if(!IsAjaxLoaded()) {return false;}

        try
        {
            //DoWait();
            MicrosoftFrance.MCS.Commerce.WS.AJAXProject.FavoritesWebService.FavoriteListProductMembership(CustomerId, FavoriteProductType, RetailerCode, ProductCode,eval(OnCompleteFuncName),onError,onTimeout);
        }
        catch (e)
        {
            DoDefault();
            window.status = e.message;
        }
        return false;                
    }

    /**
     * This method provides a way for a customer to log into the website. This method should
     * be called using a secured page so that information is sent encrypted
     * over the wire.
     * @param {string} CustomerId The customer ID GUID
     * @param {string} Login The customer login (typically email address)
     * @param {string} Password The customer password
     * @param {function} OnCompleteFuncName This is the callback function after the web service returns the result data
     */
    this.CustomerLogin=function(CustomerId, Login, Password, OnCompleteFuncName) {
        if(!IsAjaxLoaded()) { return false; }
        try {
            //DoWait();
            MicrosoftFrance.MCS.Commerce.WS.AJAXProject.CustomerWebService.Login(CustomerId, Login, Password,eval(OnCompleteFuncName),onError,onTimeout);
        }
        catch (e)  {
            DoDefault();
            window.status = e.message;
        }
        return false;
    }

    /**
     * This method provides a way for a customer to register on the website. This method should
     * be called using a secured page so that information is sent encrypted
     * over the wire.
     * @param {string} CustomerId The customer ID GUID
     * @param {string} FirstName The customer first name
     * @param {string} LastName The customer last name
     * @param {string} Email The customer email (will be the customer's login)
     * @param {string} Password The customer password
     * @param {function} OnCompleteFuncName This is the callback function after the web service returns the result data
     */
     this.CustomerRegister=function(CustomerId, FirstName, LastName, Email, Password, OnCompleteFuncName){
        if(!IsAjaxLoaded()) { return false; }

        try {
            //DoWait();
            MicrosoftFrance.MCS.Commerce.WS.AJAXProject.CustomerWebService.Register(CustomerId, FirstName, LastName, Email, Password, eval(OnCompleteFuncName),onError,onTimeout);
        }
        catch (e)  {
            DoDefault();
            window.status = e.message;
        }
        return false;
    }
    
    /**
     * Retrieves a list of a customer's favorite products
     * @param {string} CustomerId The customer ID GUID
     * @param {int} FavoriteProductType The type of favorite list to retrieve
     * @param {string} RetailerCode The current retailer code
     * @param {function} OnCompleteFuncName This is the callback function after the web service returns the result data
     */
    this.GetFavorites=function(CustomerId, FavoriteProductType, RetailerCode, OnCompleteFuncName) {
        if(!IsAjaxLoaded()) { return false; }

        try {
            //DoWait();
            MicrosoftFrance.MCS.Commerce.WS.AJAXProject.FavoritesWebService.FavoriteListGet(CustomerId, FavoriteProductType, RetailerCode, eval(OnCompleteFuncName),onError,onTimeout);
        }
        catch (e)  {
            DoDefault();
            window.status = e.message;
        }
        return false;
    }
    
    /**
     * This method loads product information for a selected retailer
     * @param {string} RetailerCode Retailer Code
     * @param {string} ProductCode Product Code(SKU)
     * @param {bool} VariantsWanted If true, variants are also loaded with the product information
     * @param {function} OnCompleteFuncName This is the callback function after the web service returns the result data
     */
    this.GetProductInformationByRetailer=function(RetailerCode, ProductCode, VariantsWanted, OnCompleteFuncName) {
        if(!IsAjaxLoaded()) { return false; }

        try {
            //DoWait();
            if (VariantsWanted) {
                MicrosoftFrance.MCS.Commerce.WS.AJAXProject.ProductWebService.GetProductInformationVariantsWantedByRetailer(RetailerCode, ProductCode, VariantsWanted,  eval(OnCompleteFuncName),onError,onTimeout);

            }
             else {
                 MicrosoftFrance.MCS.Commerce.WS.AJAXProject.ProductWebService.GetProductInformationByRetailer(RetailerCode, ProductCode, eval(OnCompleteFuncName),onError,onTimeout);
            }
        }
        catch (e)  {
            DoDefault();
            window.status = e.message;
        }
        return false;
    }
   
    /**
     * This method loads a particular product based on product code or a particular variant
     * @param {string} ProductCode Product Code(SKU)
     * @param {bool} VariantsWanted If true, variants are also loaded with the product information
     * @param {function} OnCompleteFuncName This is the callback function after the web service returns the result data
     */
    this.LoadProduct=function(ProductCode, VariantsWanted, OnCompleteFuncName)  {
        if(!IsAjaxLoaded()) { return false; }

        try {
            //DoWait();
            if (VariantsWanted) {
             MicrosoftFrance.MCS.Commerce.WS.AJAXProject.ProductWebService.GetProductInformationVariantsWanted(ProductCode,true,eval(OnCompleteFuncName),onError,onTimeout);
            }
            else {
                MicrosoftFrance.MCS.Commerce.WS.AJAXProject.ProductWebService.GetProductInformation(ProductCode,eval(OnCompleteFuncName),onError,onTimeout);
               
            }
        }
        catch (e)  {
            DoDefault();
            window.status = e.message;
        }
        return false;
    }
        
    /**
     * This method loads a pariticular product for a selected retailer. Allows for loading
     * product information for products that are inactive or offline. 
     * @param {string} RetailerCode Retailer Code
     * @param {string} ProductCode Product Code(SKU)
     * @param {bool} IgnoreFlags If true, load the product information regardless of its online status
     * @param {bool} VariantsWanted If true, variants are also loaded with the product information
     * @param {function} OnCompleteFuncName This is the callback function after the web service returns the result data
     */
    this.LoadProductIgnoreFlags=function(RetailerCode, ProductCode, IgnoreFlags, VariantsWanted, OnCompleteFuncName) {
        if(!IsAjaxLoaded()) { return false; }
        try {
            DoWait();
            if (VariantsWanted) {
                   MicrosoftFrance.MCS.Commerce.WS.AJAXProject.ProductWebService.GetProductInformationVariantsWantedIgnoreFlags(RetailerCode, ProductCode, IgnoreFlags, VariantsWanted,eval(OnCompleteFuncName),onError,onTimeout);
            }
            else {
               
                   MicrosoftFrance.MCS.Commerce.WS.AJAXProject.ProductWebService.GetProductInformationIgnoreFlags(RetailerCode, ProductCode, IgnoreFlags,   eval(OnCompleteFuncName),onError,onTimeout);
            }
        }
        catch (e)  {
            DoDefault();
            window.status = e.message;
        }
        return false;
    }

    /**
     * Retreieve variant information from the server for the selected product code
     * @param {string} RetailerCode Retailer Code
     * @param {string} ProductCode Product Code (SKU)
     * @param {function} OnCompleteFuncName This is the callback function after the web service returns the result data
     */
    this.GetVariantInformation=function(RetailerCode, ProductCode, OnCompleteFuncName) {
        if(!IsAjaxLoaded()) { return false; }

        try {
            //DoWait();
            MicrosoftFrance.MCS.Commerce.WS.AJAXProject.ProductWebService.GetVariantInformation(RetailerCode, ProductCode,  eval(OnCompleteFuncName),onError,onTimeout);
        }
        catch (e)  {
            DoDefault();
            window.status = e.message;
        }
        return false;
    }
    
    /**  
     * This method saves product notification information for a selected email address
     * and product
     * @param {string} CustomerEmail The customer's email address
     * @param {string} ProductCode Product Code(SKU)
     * @param {function} OnCompleteFuncName This is the callback function after the web service returns the result data
     */
    this.ProductStockNotificationSave=function(CustomerEmail, ProductCode, OnCompleteFuncName) {
        if(!IsAjaxLoaded()) {return false;}

        try
        {
            //DoWait();
            MicrosoftFrance.MCS.Commerce.WS.AJAXProject.CustomerWebService.ProductStockNotificationSave(CustomerEmail, ProductCode,eval(OnCompleteFuncName),onError,onTimeout);

        }
        catch (e)
        {
            DoDefault();
            window.status = e.message;
        }
        return false;
    }

    /**
     * This methods adds an item to the shopping bag
     * @param {string} CustomerID String in a form of GUID representing the Customer ID
     * @param {string} ProductCode Product Code of the variant
     * @param {int} Quantity The number of <i>ProductCode</i> variants to add
     * @param {function} OnCompleteFuncName This is the callback function after the web service returns the result data
     */
    this.AddSingleProductToCart=function(CustomerID, ProductCode, Quantity, OnCompleteFuncName) {
        if(!IsAjaxLoaded()) {return false;}
        try
        {
            //DoWait();
            MicrosoftFrance.MCS.Commerce.WS.AJAXProject.ShoppingCartWebService.AddSingleItem(CustomerID, ProductCode, Quantity,eval(OnCompleteFuncName),onError,onTimeout);
        }
        catch (e)
        {
            DoDefault();
            window.status = e.message;
        }
        return false;
    }

    /**
     * This methods adds multiple item to the shopping bag
     * @param {string} CustomerID String in a form of GUID representing the Customer ID
     * @param {Array} ProductCodes Array of variant product codes to add to the basket
     * @param {Array} Quantity Array with the cooresponding number of <i>ProductCode</i> variants to add
     * @param {function} OnCompleteFuncName This is the callback function after the web service returns the result data
     */
    this.AddMultipleProductsToCart=function(CustomerID, ProductCodes, Quantity, OnCompleteFuncName) {
        if(!IsAjaxLoaded()) {return false;}

        try
        {
            //DoWait();
            MicrosoftFrance.MCS.Commerce.WS.AJAXProject.ShoppingCartWebService.AddMultipleItems(CustomerID, ProductCodes, Quantity, eval(OnCompleteFuncName),onError,onTimeout);
        }
        catch (e)
        {
            DoDefault();
            window.status = e.message;
        }
        return false;
    }
    
    /**
     * Retrieves the shopping cart
     * @param {string} CustomerID String in a form of GUID representing the Customer ID
     * @param {function} OnCompleteFuncName This is the callback function after the web service returns the result data
     */
    this.RetrieveShoppingCart=function (CustomerID, OnCompleteFuncName) {
        if(!IsAjaxLoaded()) {return false;}

        try
        {
            //DoWait();
            MicrosoftFrance.MCS.Commerce.WS.AJAXProject.ShoppingCartWebService.RetrieveShoppingCart(CustomerID,eval(OnCompleteFuncName),onError,onTimeout);
        }
        catch (e)
        {
            DoDefault();
            window.status = e.message;
        }
        return false;
    }

    /**
     * Retrieves the last <i>N</i> number of items from the shopping cart
     * 
     * @param {string} CustomerID String in a form of GUID representing the Customer ID
     * @param {int} intLastItems The number of items to retrieve from the shopping cart. It assumes the shopping cart is stored as a stack so that the last intLastItems will be the most recently added ones.
     * @param {function} OnCompleteFuncName This is the callback function after the web service returns the result data
     */
    this.RetrieveShoppingCartLastItems=function(CustomerID, intLastItems, OnCompleteFuncName) {
        if(!IsAjaxLoaded()) {return false;}

        try
        {
            //DoWait();
            MicrosoftFrance.MCS.Commerce.WS.AJAXProject.ShoppingCartWebService.RetrieveLastItems(CustomerID, intLastItems, eval(OnCompleteFuncName),onError,onTimeout);
        }
        catch (e)
        {
            DoDefault();
            window.status = e.message;
        }
        return false;
    }

    /**
     * Retrieves the promotion proximity for the customer's shopping 
     * cart. This method can be used to retrieve promotion proximity based on 
     * availability. See the parameter promotionAvailabilty for the available switches.
     * @param {string} CustomerID String in a form of GUID representing the Customer ID
     * @param {int} distancesToDisplay The number of distances to display. This will return up to <i>distancesToDisplay</i> promotion distances.
     * @param {string} evaluators Comma-delimited list of the type of promotions to evaluate for distance information. They are: CustomerRoleEvaluator, CustomerSegmentEvaluator, LineNotEmptyEvaluator, BasketPriceEvaluator, BasketItemsQuantityEvaluator, BasketItemsAxeEPQuantityEvaluator, BasketSpecificItemQuantityEvaluator, KeyCodeEvaluator
     * @param {int} promotionAvailability Used to get promotion distances based on promotion availability. Set this to NULL to evaluate only available promtoions. Otherwise, use the following values to tailor which promotions are returned: (0 = ALL, 1 = Available, 2 = Unavailable).
     * @param {function} OnCompleteFuncName This is the callback function after the web service returns the result data
     */
    this.GetPromotionProximity=function(CustomerId, distancesToDisplay, evaluators, promotionAvailability, OnCompleteFuncName) {
        if(!IsAjaxLoaded()) { return false; }

        try {
            //DoWait();
            if (promotionAvailability != null) {
               MicrosoftFrance.MCS.Commerce.WS.AJAXProject.ShoppingCartWebService.GetPromotionProximityByAvailability(CustomerId, distancesToDisplay, evaluators, promotionAvailability,eval(OnCompleteFuncName),onError,onTimeout);
            }
            else {
              
               MicrosoftFrance.MCS.Commerce.WS.AJAXProject.ShoppingCartWebService.GetPromotionProximity(CustomerId, distancesToDisplay, evaluators, eval(OnCompleteFuncName),onError,onTimeout);
            }
        }
        catch (e)  {
            DoDefault();
            window.status = e.message;
        }
        return false;
    }
    
    /**
     * Retrieves the product association specified for the selected <i>AssociationName</i> and <i>ProductCode</i>
     * TODO - TEST
     * @param {string} RetailerCode The retailer code
     * @param {string} ProductCode The source product code used to find the associated products
     * @param {string} AssociationName The product association name
     * @param {bool} VariantsWanted When true, the variants for each product in the association are returned
     * @param {function} OnCompleteFuncName This is the callback function after the web service returns the result data
     */
    this.GetProductAssociations=function(RetailerCode,ProductCode,AssociationName,VariantsWanted,OnCompleteFuncName)  {
        if(!IsAjaxLoaded()) {return false;}

        try
        {
            //DoWait();
            MicrosoftFrance.MCS.Commerce.WS.AJAXProject.ProductWebService.GetProductAssociations(RetailerCode, ProductCode,AssociationName,VariantsWanted, eval(OnCompleteFuncName),onError,onTimeout);
        }
        catch (e)
        {
            DoDefault();
            window.status = e.message;
        }
        return false;
    }
    
    /**
     * Retrieves topic information
     * @param {string} TopicCode The selected topic code
     * @param {string} TopicType The topic type
     * @param {function} OnCompleteFuncName This is the callback function after the web service returns the result data
     */
    this.GetTopicInformation=function(TopicCode, TopicType, OnCompleteFuncName) {
        if(!IsAjaxLoaded()) {return false;}

        try {
            //DoWait();
            MicrosoftFrance.MCS.Commerce.WS.AJAXProject.TopicWebService.GetTopicInformation(TopicCode, TopicType,  eval(OnCompleteFuncName),onError,onTimeout);
        }
        catch (e) {
            DoDefault();
            window.status = e.message;
        }
        return false;
    }

    /**
     * Retrieves the products associated to the selected <i>TopicCode</i> and <i>TopicType</i>
     * 
     * @param {string} TopicCode The selected topic code
     * @param {string} TopicType The topic type
     * @param {function} OnCompleteFuncName This is the callback function after the web service returns the result data
     */
    this.GetTopicProducts= function (TopicCode, TopicType, OnCompleteFuncName)  {
        if(!IsAjaxLoaded()) {return false;}

        try {
            //DoWait();
            MicrosoftFrance.MCS.Commerce.WS.AJAXProject.TopicWebService.GetTopicProducts(TopicCode, TopicType,eval(OnCompleteFuncName),onError,onTimeout);

        }
        catch (e) {
            DoDefault();
            window.status = e.message;
        }
        return false;
    }
       /**
     * Retrieves the product codes associated to the selected <i>TopicCode</i> and <i>TopicType</i>
     * @param {string} TopicCode The selected topic code
     * @param {string} TopicType The topic type
     * @param {function} OnCompleteFuncName This is the callback function after the web service returns the result data
     */
    this.GetTopicProductsCodes= function (TopicCode, TopicType, OnCompleteFuncName)  {
        if(!IsAjaxLoaded()) {return false;}

        try {
            //DoWait();
            MicrosoftFrance.MCS.Commerce.WS.AJAXProject.TopicWebService.GetTopicProductsCodes(TopicCode, TopicType,eval(OnCompleteFuncName),onError,onTimeout);
        }
        catch (e) {
            DoDefault();
            window.status = e.message;
        }
        return false;
    }
       /**
     * Retrieves the product codes associated to the selected <i>TopicCode1,TopicCode2,TopcCodeN</i> 
     * @param {string} TopicList comma delimited list of toiccodes
      * @param {function} OnCompleteFuncName This is the callback function after the web service returns the result data
     */
    this.GetTopicProductsCodesByTopicList= function (TopicList,OnCompleteFuncName)  {
        if(!IsAjaxLoaded()) {return false;}
        try {
            DoWait();
            MicrosoftFrance.MCS.Commerce.WS.AJAXProject.TopicWebService.GetTopicProductsCodesByTopicList(TopicList,eval(OnCompleteFuncName),onError,onTimeout);
        }
        catch (e) {
            DoDefault();
            window.status = e.message;
        }
        return false;
    }
     
    /**
     * Used to remove a product from a customer's favorite list
     * @param {string} CustomerId The customer ID GUID
     * @param {int} FavoriteProductType The type of favorite list to retrieve
     * @param {string} RetailerCode The current retailer code
     * @param {string} ProductCode The product code to remove from the customer's favorite list
     * @param {function} OnCompleteFuncName This is the callback function after the web service returns the result data
     */
    this.RemoveFromFavorites=function(CustomerId, FavoriteProductType, RetailerCode, ProductCode, OnCompleteFuncName) {
        if(!IsAjaxLoaded()) {return false;}

        try {
            //DoWait();
            MicrosoftFrance.MCS.Commerce.WS.AJAXProject.FavoritesWebService.FavoriteListProductRemove(CustomerId, FavoriteProductType, RetailerCode, ProductCode,eval(OnCompleteFuncName),onError,onTimeout);
        }
        catch (e) {
            DoDefault();
            window.status = e.message;
        }
        return false;
    }
       
    /**
     * Gets the topic information with the customer's rating information.
     * @param {string} CustomerId The customer ID GUID
     * @param {string} TopicCode The selected topic code
     * @param {string} TopicType The topic type
     * @param {function} OnCompleteFuncName This is the callback function after the web service returns the result data
     */
    this.GetTopicWithCustomerRating=function(CustomerId, TopicType, TopicCode, OnCompleteFuncName) {
        // Check to ensure the ATLAS module has been loaded before calling
        // the web service
        if(!IsAjaxLoaded()) {return false;}

        try {
            //DoWait();
            MicrosoftFrance.MCS.Commerce.WS.AJAXProject.TopicWebService.GetTopicWithCustomerRating(CustomerId, TopicType, TopicCode,  eval(OnCompleteFuncName),onError,onTimeout);
        }
        catch (e) {
            DoDefault();
            window.status = e.message;
        }
        return false;
    }

    /**
     * Saves a customer's topic rating information
     * @param {string} CustomerId The customer ID GUID
     * @param {string} TopicCode The selected topic code
     * @param {string} TopicType The topic type
     * @param {string} TopicUrl The topic URL
     * @param {int} Rating The integer rating for the topic
     * @param {string} Comment The comment the customer has submitted related to this topic
     * @param {function} OnCompleteFuncName This is the callback function after the web service returns the result data
     */
    this.TopicCustomerRatingRecord=function(CustomerId, TopicType, TopicCode, TopicUrl, Rating, Comment, OnCompleteFuncName) {
        if(!IsAjaxLoaded()) {return false;}

        try {
            //DoWait();
            MicrosoftFrance.MCS.Commerce.WS.AJAXProject.TopicWebService.TopicCustomerRatingRecord(CustomerId, TopicType, TopicCode, TopicUrl, Rating, Comment,eval(OnCompleteFuncName),onError,onTimeout);
        }
        catch (e) {
            DoDefault();
            window.status = e.message;
        }
        return false;
    }
// ------------------- NEW FOR MAYBELLINE -----------------------//  
    this.UpdatePhoneInformation=function(PhoneField, CustomerID, Phone1, Phone2, Phone3, PhoneSplit, OnCompleteFuncName) {
        if(!IsAjaxLoaded()) {return false;}

        try
        {
            //DoWait();
            Loreal.US.eCommerce.WS.Maybelline.AJAX_Project.CustomerWebService.UpdatePhoneInformation(PhoneField, CustomerID, Phone1, Phone2, Phone3, PhoneSplit, eval(OnCompleteFuncName),onError,onTimeout);
        }
        catch (e)
        {
            DoDefault();
            window.status = e.message;
        }
        return false; 
    }

  
    this.EmailAFriend=function(FromFname, FromLname, FromEmail,BodyMsg, ToEmails, toBeIncluded, Code, isProduct, templatename,format, OnCompleteFuncName) {
        if(!IsAjaxLoaded()) {return false;}

        try
        {
            //DoWait();
            Loreal.US.eCommerce.WS.Maybelline.AJAX_Project.CustomerWebService.SendMailTellAFriend(FromFname, FromLname, FromEmail, BodyMsg, ToEmails, toBeIncluded, Code, isProduct, templatename, format, eval(OnCompleteFuncName),onError,onTimeout);
        }
        catch (e)
        {
            DoDefault();
            window.status = e.message;
        }
        return false; 
    }
    
         /**
     * Retrieves products based on a CategoryCode
     * @param {string} categoryCode The selected categoryCode
     * @param {int} onlineStatus
     * @param {function} OnCompleteFuncName This is the callback function after the web service returns the result data
     */
    this.GetCategoryProductsByOnlineStatus=function(RetailerCode, CategoryCode, onlineStatus, variantsWanted,OnCompleteFuncName)  {
        if(!IsAjaxLoaded()) {return false;}

        try
        {
           MicrosoftFrance.MCS.Commerce.WS.AJAXProject.ProductWebService.GetCategoryProductsByOnlineStatus(RetailerCode, CategoryCode, onlineStatus, variantsWanted, eval(OnCompleteFuncName),onError);
        }
        catch (e)
        {
            DoDefault();
            window.status = e.message;
        }
        return false;
    }
    
    /**
     * This method loads a particular product based on product code or a particular variant
     * @param {string} ProductCode Product Code(SKU)
     * @param {bool} VariantsWanted If true, variants are also loaded with the product information
     * @param {function} OnCompleteFuncName This is the callback function after the web service returns the result data
     */
    this.LoadDiscontinuedProduct=function(RetailerCode, ProductCode,IgnoreFlags, VariantsWanted, OnCompleteFuncName)  {
        if(!IsAjaxLoaded()) { return false; }

        try {
            if (VariantsWanted) {
             MicrosoftFrance.MCS.Commerce.WS.AJAXProject.ProductWebService.GetProductInformationVariantsWantedIgnoreFlags(RetailerCode, ProductCode, IgnoreFlags, VariantsWanted,eval(OnCompleteFuncName),onError);
            }
            else {
                MicrosoftFrance.MCS.Commerce.WS.AJAXProject.ProductWebService.GetProductInformationIgnoreFlags(RetailerCode, ProductCode, IgnoreFlags, eval(OnCompleteFuncName),onError);
               
            }
        }
        catch (e)  {
            DoDefault();
            window.status = e.message;
        }
        return false;
    }
    
    /**
     * Retreieve variant information from the server for the selected product code
     * @param {string} RetailerCode Retailer Code
     * @param {string} ProductCode Product Code (SKU)
     * @param {function} OnCompleteFuncName This is the callback function after the web service returns the result data
     */
    this.GetVariantInformationIgnoreFlags=function(RetailerCode, ProductCode, ignoreFlags, OnCompleteFuncName) {
        if(!IsAjaxLoaded()) { return false; }

        try {
            ////DoWait();
            MicrosoftFrance.MCS.Commerce.WS.AJAXProject.ProductWebService.GetVariantInformationIgnoreFlags(RetailerCode, ProductCode, ignoreFlags,  eval(OnCompleteFuncName),onError);
        }
        catch (e)  {
            DoDefault();
            window.status = e.message;
        }
        return false;
    }
    
                 /**
     * Retrieves product associations based on a Product Codes
     * @param {string} categoryCode The selected categoryCode
     * @param {int} onlineStatus
     * @param {function} OnCompleteFuncName This is the callback function after the web service returns the result data
     */
    this.GetProductAssociationsByProductCodes=function(RetailerCode, ProductCodes, associationName, ignoreFlags, OnCompleteFuncName)  {
        if(!IsAjaxLoaded()) {return false;}

        try
        {
            Loreal.US.eCommerce.WS.Maybelline.AJAX_Project.ProductWebService.GetProductAssociationsByProductCodes(RetailerCode, ProductCodes, associationName, ignoreFlags, eval(OnCompleteFuncName),onError);
        }
        catch (e)
        {
            DoDefault();
            window.status = e.message;
        }
        return false;
    }
    
        /**
     * Used to remove products from a customer's favorite list
     * @param {string} CustomerId The customer ID GUID
     * @param {int} FavoriteProductType The type of favorite list to retrieve
     * @param {string} RetailerCode The current retailer code
     * @param {string} ProductCodes The product codes to remove from the customer's favorite list
     * @param {function} OnCompleteFuncName This is the callback function after the web service returns the result data
     */
    this.FavoriteListProductRemoveProductCodes=function(CustomerId, FavoriteProductType, RetailerCode, ProductCodes, OnCompleteFuncName) {
        if(!IsAjaxLoaded()) {return false;}

        try {
            //DoWait();
             Loreal.US.eCommerce.WS.Maybelline.AJAX_Project.FavoritesWebService.FavoriteListProductRemoveProductCodes(CustomerId, FavoriteProductType, RetailerCode, ProductCodes,eval(OnCompleteFuncName),onError,onTimeout);
        }
        catch (e) {
            DoDefault();
            window.status = e.message;
        }
        return false;
    }
}

/*
 * It registers the WebServiceAPI_Class using registerClass method of MS AJAX Library
 */
// if (IsTypeDefined) { Core.WebServiceAPI_Class.registerClass('Core.WebServiceAPI_Class', null); }
if (IsTypeDefined) { Core.WebServiceAPI_Class.registerClass('Core.WebServiceAPI_Class'); }



/**
 * @class CoreModalPopUp creates a modal pop up "bubble"
 */
Core.ModalPopUp= function () {
    /**
     *  The layer of the whole modal window (object)
     */
    var _backgroundElement=null;

    /**
     * The pop up that will show up (object)
     */
    this._foregroundElement=null;

    /**
     * the Id of the foregroundElement (string)
     */
    this._PopupControlID=null;
    
    /**
     * the name of the function to be called before the popup opens
     */
    this.beforeOpen=null; //null;
    /**
     * the name of the function to be called before the popup closes
     */
    this.beforeClose=null;
    
    this._IsforegroundElementLarge=false;
    
   

    /**
     * _Initialize
     */
    this._Initialize=function() {
        if (_backgroundElement==null) {
            _backgroundElement = document.createElement('div');
            _backgroundElement.style.display = 'none'; //none
            _backgroundElement.style.position = 'absolute';
            _backgroundElement.className = 'modalBackground';
            document.body.appendChild(_backgroundElement);
        }
    }

    /**
     *  _InitializeForeground
     */
    this._InitializeForeground=function() {
        this._foregroundElement = $get(this._PopupControlID);
        this._foregroundElement.style.display = 'none';
        this._foregroundElement.style.position = 'absolute';
        document.body.appendChild(this._foregroundElement);
    }

    /**
      * Show Modal
      */
    this.ShowModal=function () {
        if ((_backgroundElement==null) || (typeof(_backgroundElement)=='undefined') ) {
            this._Initialize()
        }

        if (this._PopupControlID !=null) {
            this._InitializeForeground();
        }

        var clientWidth =630;
        var clientHeight=460;
        var scrollLeft = (document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft);
        var scrollTop = (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop);

        if (window.innerWidth) {
            clientWidth = (window.__safari ? window.innerWidth : Math.min(window.innerWidth, document.documentElement.clientWidth));
        }
        else {
            clientWidth = document.documentElement.clientWidth;
        }

        if (window.innerHeight) {
            clientHeight = (window.__safari ? window.innerHeight : Math.min(window.innerHeight, document.documentElement.clientHeight));
        }
        else {
            clientHeight = document.documentElement.clientHeight;
        }

        _backgroundElement.style.left = scrollLeft+'px';
        _backgroundElement.style.top = scrollTop+'px';
        _backgroundElement.style.width = clientWidth+'px';
        _backgroundElement.style.height = clientHeight+'px';
        _backgroundElement.style.display = 'block';

        if (this._foregroundElement!=null) {
           this._foregroundElement.style.left = scrollLeft+((clientWidth-this._foregroundElement.offsetWidth -60)/2)+'px';
           if (this._IsforegroundElementLarge==true) {
                this._foregroundElement.style.top = scrollTop+((clientHeight-this._foregroundElement.offsetHeight)/10)+'px';
           }else {
             this._foregroundElement.style.top = scrollTop+((clientHeight-this._foregroundElement.offsetHeight)/4)+'px';//for large bubbles
           }
             
            this._foregroundElement.style.display = 'block';
        }
        IS_MODELPOPUP_VISIBLE=true;
        if (this.beforeOpen!=null) {
             eval(this.beforeOpen + "();");
        
        }
     }

    /**
      * Show Modal without background
      */
    this.ShowModalWithoutBackground=function () {
        this.ShowModal();
        _backgroundElement.style.display = 'none';
    }

    /**
     * Hide
     */
    this.Hide=function() {
        if (_backgroundElement!=null) {
            _backgroundElement.style.display = 'none';
        }
        if (this._foregroundElement!=null) {
            this._foregroundElement.style.display = 'none';
        }
        IS_MODELPOPUP_VISIBLE=false;
        this._IsforegroundElementLarge=false;
        if (this.beforeClose!=null) {
             eval(this.beforeClose + "();");
        
        }
    }

    /**
     * ResizeHandler 
     */
    this.ResizeHandler=function() {
        if (_backgroundElement!=null && _backgroundElement.style.display != 'none' ){
            this.ShowModal();
        }
    }

    /** 
     * ScrollHandler    
     */
    this.ScrollHandler=function() {
        if (_backgroundElement!=null && _backgroundElement.style.display != 'none' ){
            this.ShowModal();
        }
    }
}
/*
 * It registers the WebServiceAPI_Class using registerClass method of MS AJAX Library
 */
 if (IsTypeDefined) { Core.ModalPopUp.registerClass('Core.ModalPopUp'); }



/**
 * @class Quick shop class, shows and hides the quick shop image
 * that will be placed on top of the products.
 */


Core.QuickShop_Class=function (){
    /**
     * The HTML ID of the layer (div) for the quick shop class
     */
    this.QuickShop_DivID='QuickLook';

    /**
     * Code of cyrrent variant/product 
     */
    this.Code='';

    /**
     * Set to true if viewing a variant and set to false if viewing the whole product
     */
    this.IsVariant=true;

    this.hasShades=false;
    /**
     * This Method shows the quick look on top of a layer with id of RelativeObjectId
     * @param {string} RelativeObjectId The ID of the object where the quick look image/layer will be displayed as a hot spot
     * @param {string} Code ProductCode(SKU)
     * @param {bool} IsVariant true if it is variant, false otherwise
     */
    this.Show=function (RelativeObjectId,Code,IsVariant) {
        this.Code=Code;
        this.IsVariant=IsVariant;
        MM_showHideLayers(this.QuickShop_DivID,'','show',RelativeObjectId);
    }

    /**
     * This Method shows the quick look on top of a dhtml object RelativeObject
     * If AbsoluteTop or Absoluteleft is let say 200 and 250, the displacement of quick look will
     * be 200 + plusTop and 250 + plusLeft. View the Code for more details
     * @param {string} RelativeObject Object where the quick look image (layer) will be displayed as a hot spot
     * @param {string} Code ProductCode(SKU)
     * @param {bool} IsVariant True if it is variant, false otherwise
     * @param {integer} plusTop integer like +20
     * @param {integer} plusLeft integer like +20
     * @hasShades {boolean} true if product has shades
     */
    this.ShowByObjectPosition=function (RelativeObject,Code,IsVariant,plusTop,plusLeft,hasShades) {
        this.Code=Code;
        this.IsVariant=IsVariant;
        this.hasShades=hasShades;
        PositionLayerByRelativeObject(RelativeObject,$get(this.QuickShop_DivID),plusTop,plusLeft);
    }

    /**
     * Simply hides the quick shop image/layer
     */
    this.Hide=function() {
         MM_showHideLayers( this.QuickShop_DivID,'','hide')
    }

    /**
     * When the quick shop bubble is shown, the user can click on that image.
     * This method is called when the user clicks on the image.
     * The method determines if it is a Variant or Product. Based on the requests, we
     * may need to do few more cases on this method.
     */
    this.ShowBubble=function() {
        if (this.IsVariant) {
            _ProductManager.LoadMakeupVariant(this.Code)
        }
        else {
            if(this.hasShades) {
              _ProductManager.LoadMakeupProduct(this.Code);
            }
            else {
              _ProductManager.LoadSkinCareProduct(this.Code);
            }
        }
    }
    
         /**
     * This method will be called from the bubbles to add a product on the
     *  favorites from quick shop
     */
    this.AddToFavoritesFromBubble=function() {
        if(CustomerSigned == true){
            var _prdType='Product';
            if (this.IsVariant) {
                _prdType='Variant';
            }
            //_CoreModalPopUp.Hide();
            arrFavProds.push(this.Code);
            _ProductManager.AddProductToFavorites(_prdType, AJAX_DEFAULT_RTLCODE, this.Code);
        }else{
            _SignInBubble.ShowBubbleFromFavoritesBubble(this.Code);
        }
    }
    
    this.AddToFavorites=function(isVariant,Code) {
        this.FromProductBubble=true;
        this.IsVariant=isVariant;
        this.Code=Code;
        this.AddToFavoritesFromBubble();
    }
}

/*
 * It registers the QuickShop_Class using registerClass method of MS AJAX Library
 */
 if (IsTypeDefined) { Core.QuickShop_Class.registerClass('Core.QuickShop_Class'); }



/**
 * @class VariantBubble_Class
 *  This class is responsible into managing the Varianat Bubble Class
 * Please be aware that the properties of this class needs to be overridden based on the case that we will be using.
 *  The one which needs to be changed are
 *        this.VariantBubble_ImagePrefix   and    this.VariantBubble_ImageSuffix;
 * The other properties are DHTML Object IDs that needs to be populated with the data.....
 * In case there are other data that needs to be populated, we either need to support on this class or we need to prototype
 *  its methods.
 */

Core.VariantBubble_Class=function () {
    /**
     * The DHTML ID of the main layer of the Varianat bubble
     */
    this.VariantBubble_DivID="VariantBubble_Div";

    /**
     * The DHTML ID of the Product/Variant Image
     */
    this.VariantBubble_ImageID="VariantBubble_Image";

    /**
     * The DHTML ID of the quantity
     */
    this.VariantBubble_QuantityID="VariantBubble_Quantity";

    /**
     * The DHTML ID of the price label
     */
    this.VariantBubble_PriceID="VariantBubble_Price";

    /**
     * The DHTML ID of the product name label
     */
    this.VariantBubble_ProductNameID="VariantBubble_ProductName";

    /**
     * The DHTML ID of the variant name label
     */
    this.VariantBubble_VariantNameID="VariantBubble_VariantName";

    /**
     * The DHTML ID of the add to bag button on the bubble
     */
    this.VariantBubble_AddToBagID="VariantBubble_AddToBag";

    /**
     * The Prefix of the image
     */
    this.VariantBubble_ImagePrefix_LargeShade=IMAGES_RELATIVE_OR_ABSOLUTE_PATH +VARIANT_LARGE_SHADE_IMAGE_PREFIX;

    /**
     * The suffix of the image
     */
    this.VariantBubble_ImageSuffix_LargeShade=VARIANT_LARGE_SHADE_IMAGE_SUFFIX;

    /**
     * Variant Code
     */
    this.Code="";

    this.VIEWMOREDETAILS_ID="VARIANT_VIEWMOREDETAILS_OFPRODUCT";
    this.VIEWMOREDETAILS_INNERHTML_TEMPLATE="";
    /**
     * This Method is called when the webservice is done with data retrieval
     * @param {object} result The data that comes into a JASON format from a web service
     */
    this.LoadVariantRequestComplete=function(result) {
        this.PopulateData(result);
    }

    /**
     * This Method populates the variant bubble
     * @param {object} result The data that comes into a JASON format from a web service
     */
    this.PopulateData=function(result)  {
        _QuickShop_Class.Hide();
        DoDefault();

        var obj=$get(this.VariantBubble_ImageID);
        if (obj!=null) {
           obj.src=this.VariantBubble_ImagePrefix_LargeShade + this.Code + this.VariantBubble_ImageSuffix_LargeShade;
        }
        var prodnameobj=$get(this.VariantBubble_ProductNameID);
        var shadenameobj=$get(this.VariantBubble_VariantNameID);
        var priceobj=$get(this.VariantBubble_PriceID);
        var viewmoredetailsobj=$get(this.VIEWMOREDETAILS_ID);
        
        if (priceobj!=null) {
            priceobj.innerHTML="$ " + result.MainPrice;
        }
        if(prodnameobj!=null) {
            prodnameobj.innerHTML=result.ParentName;
        }
        if(shadenameobj!=null) {
            shadenameobj.innerHTML=result.Name;
        }
        
        //handle view more details
       if(viewmoredetailsobj!=null) {
       
         var strviewmoredetails=viewmoredetailsobj.innerHTML;
         if (this.VIEWMOREDETAILS_INNERHTML_TEMPLATE=="") {
            this.VIEWMOREDETAILS_INNERHTML_TEMPLATE=strviewmoredetails;//preserve for future clicks
         }
         else {
             strviewmoredetails=this.VIEWMOREDETAILS_INNERHTML_TEMPLATE;
         }
         strviewmoredetails=strviewmoredetails.replace("$$$AJAX_ParentProductCode$$$",result.ParentProductCode);
         strviewmoredetails=strviewmoredetails.replace("$$$AJAX_VariantCode$$$",this.Code);
         viewmoredetailsobj.innerHTML= strviewmoredetails;
       }
        MM_showHideLayers(this.VariantBubble_DivID,'','show','QuickLook');//revist this part in a better manner!
        _CoreModalPopUp._PopupControlID=this.VariantBubble_DivID;
        _CoreModalPopUp.ShowModal();
        //The line below sets the last item shopping Cart Item
        _LastShoppingCartItem.PopulateData(this.Code,result.Name,result.ParentProductCode,result.ParentName,result.MainPrice);

    }

    /**
     * This method is called when add to bag is clicked on the variant bubble,
     * it determines the SKU, quantity and customer ID automatically and passes to a web service
     */
    this.AddSingleProductToCart=function () {
        var ItemQuantity=1;
        ItemQuantity=GetSelectedValue(this.VariantBubble_QuantityID);
        MM_showHideLayers(_VariantBubble_Class.VariantBubble_DivID,'','hide')
        _CoreModalPopUp.Hide();
        //Set the last Item Item Shopping Cart Item Quantity
         _LastShoppingCartItem.ItemQuantity=ItemQuantity;
        // call webservice method
        _WebServiceAPI.AddSingleProductToCart (GetCurrentCustomerID(),this.Code,ItemQuantity,_ShoppingCartBubble_Class.AddSingleProductToCartResultHandler)
    }
}

/*
 * It registers the VariantBubble_Class using registerClass method of MS AJAX Library
 */
 if (IsTypeDefined) { Core.VariantBubble_Class.registerClass('Core.VariantBubble_Class'); }


/**
 * @class ProductBubble_Class
 * This class is responsible into managing the Product Bubble Class
 * Please be aware that the properties of this class needs to be overridden based on the case that we will be using.
 * The one which needs to be changed are
 *        this.VariantBubble_ImagePrefix   and    this.VariantBubble_ImageSuffix;
 * The other properties are DHTML Object IDs that needs to be populated with the data.....
 * In case there are other data that needs to be populated, we either need to support on this class or we need to prototype
 * its methods.
 *  this.RowSize=8 is a very important property, it manages how many variants will be shown in one row if
 * the product is a makeup product. It customizes building of shade table.
 */

Core.ProductBubble_Class=function() {
    /**
     * The DHTML ID of the main layer of the Product bubble
     */
    this.Bubble_DivID="ProductBubble_Div";
    /**
     * The DHTML ID of the Product Image object
     */
    this.Bubble_ImageID="ProductBubble_Image";
    /**
     * The DHTML ID of the Quantity object
     */
    this.Bubble_QuantityID="ProductBubble_Quantity";
    /**
     * The DHTML ID   of the Product price label
     */
    this.Bubble_PriceID="ProductBubble_Price";
    /**
     * The DHTML ID   of the Product Name label
     */
    this.Bubble_ProductNameID="ProductBubble_ProductName";
    
     this.Bubble_ProductNameID2="ProductBubble2_ProductName";
    /**
     * The DHTML ID   of the Product description label
     */
    this.Bubble_ProductDescriptionID="ProductBubble_ProductDescription";
    /**
     * The DHTML ID   of the Add to bag object
     */
    this.Bubble_AddToBagID="ProductBubble_AddToBag"; //not used yet on js code

    //Small Product Images
    /**
     * Small Image Prefix
     */
    this.Bubble_ImagePrefix_Product_Small=IMAGES_RELATIVE_OR_ABSOLUTE_PATH + PRODUCT_SMALL_IMAGE_PREFIX;
    /**
     * Small Image Suffix
     */
    this.Bubble_ImageSuffix_Product_Small=PRODUCT_SMALL_IMAGE_SUFFIX;

    //Small Shades
    /**
     * small shades prefix
     */
    this.Bubble_ImagePrefix_SmallShade=IMAGES_RELATIVE_OR_ABSOLUTE_PATH + VARIANT_SMALL_SHADE_IMAGE_PREFIX;
    /**
     * small shades suffix
     */
    this.Bubble_ImageSuffix_SmallShade=VARIANT_SMALL_SHADE_IMAGE_SUFFIX;

    //thumbnails
    /**
     * product thumbnails prefix
     */
    this.Bubble_ImagePrefix_MediumShade=IMAGES_RELATIVE_OR_ABSOLUTE_PATH + VARIANT_MEDIUM_SHADE_IMAGE_PREFIX;
    /**
     * product thumbnails suffix
     */
    this.Bubble_ImageSuffix_MediumShade=VARIANT_MEDIUM_SHADE_IMAGE_SUFFIX;

    /**
     * Product Code
     */
    this.Code="";
    /**
     *  The DHTML ID   of the drop down layer that lists all variants
     */
    this.Bubble_LayerDropDownListID="ProductBubble_VariantDropDownList";
    /**
     * The DHTML ID   of the drop down that lists all variants
     */
    this.Bubble_DropDownListID="DropDown_" + this.Bubble_LayerDropDownListID;
    /**
     * The DHTML ID   of small shades layer
     */
    this.ProductBubble_Small_ShadesID="ProductBubble_Small_Shades"
    /**
     * set to tru if has shades else set to false //check any valid property in db ???
     */
    this.IsMakeupProduct=false;
    /**
     * Number of elements per row
     */
    this.RowSize=7;        //Can be Changed
    /**
     * Current Index of the row
     */
    this.CurrentIndex=0;
    /**
     * temporary x postion of the mouse
     */
    this.tempX=0;
    /**
     * temporary y position of the mouse
     */
    this.tempY=0
    /**
     * The DHTML ID   of the variants thumbnail table
     */
    this.Variants_Main_All_Thumbnails='Ajax_Main_Bubble_All_Thumbnail_Shades';
    /**
     * The DHTML ID   of all variants
     */
    this.Variants_ThumbnailDivID='Ajax_allShades_layer';
    /**
     * set to true if multiple prices else set to false
     */
    this.HasMultiplePrices=false;
    /**
     * if all variants same price, this variable will hold the variant price
     */
    this.DistinctPrice=0;

    this.VIEWMOREDETAILS_ID="PRODUCT_BUBBLE_VIEWMOREDETAILS";
    this.VIEWMOREDETAILS_INNERHTML_TEMPLATE="";
    this.SelectShadeLabel="selectshadeLabel";
    this.DropDownShadeLabel="DropDownShadeLabel";
    this.DropDownSizeLabel="DropDownSizeLabel";
    //
    this.VIEWMOREDETAILS2_ID="PRODUCT_BUBBLE2_VIEWMOREDETAILS";
    this.VIEWMOREDETAILS_INNERHTML_TEMPLATE2="";
    
    /**
     * This Method is called when the webservice is done with data retrieval
     * @param {object} result the data that comes into a JASON format from a web service
     */
    this.LoadProductRequestComplete=function(result) {
        this.PopulateData(result);
    }

    /**
     * populates the product bubble
     * If it belongs to make up, it also builds the shade table with defautl 8 cells in one row.
     * @param {object} result the data that comes into a JASON format from a web service
     */
    this.PopulateData=function(result)  {
        if (result==null) {return false;}
        if (result.Variants==null) {return false;}               //product has no variants
        if (typeof(result)=='undefined') {return false;}
        if (typeof(result.Variants)=='undefined') {return false;} //product has no variants

        //check if the main layer exist. If it does not, return.
        var prodBubble=$get(this.Bubble_DivID);
        if ((prodBubble==null) || (prodBubble=='undefined')) {
            alert('The \"' + this.Bubble_DivID + '\" is not found.');
            return;
        }

        this.DetermineMultiplePrices(result.Variants);
        _QuickShop_Class.Hide();
        DoDefault();

        var obj=$get(this.Bubble_ImageID);
        if (obj!=null) {
            obj.src=this.Bubble_ImagePrefix_Product_Small + this.Code + this.Bubble_ImageSuffix_Product_Small;
        }

        var prodnameobj=$get(this.Bubble_ProductNameID);
        var prodnameobj2=$get(this.Bubble_ProductNameID2);
      
        var priceobj=$get(this.Bubble_PriceID);
        var dropdownlistObj=$get(this.Bubble_LayerDropDownListID);
        var productBubbleSmShadesObj =$get(this.ProductBubble_Small_ShadesID);
        var productdescrobj=$get(this.Bubble_ProductDescriptionID);
        if (priceobj!=null) {
            //priceobj.innerHTML="$ " + result.MainPrice;
            if (this.DistinctPrice!=0) { //means same price variants
                priceobj.innerHTML="$ " + this.DistinctPrice;
            }
            else { //means multiple prices
                priceobj.innerHTML=""; 
            }
            //
            if(prodnameobj!=null) {
                prodnameobj.innerHTML=result.Name;
            }
            //
            if(prodnameobj2!=null) {
                prodnameobj2.innerHTML=result.Name;
            }
            //
            if (productdescrobj!=null) {
               productdescrobj.innerHTML=result.Description;
            }
            //
            var labelObj=$get( this.SelectShadeLabel);
            //
            var obj1=$get(this.DropDownShadeLabel);
            //
            var obj2=$get(this.DropDownSizeLabel);
           
            if (productBubbleSmShadesObj!=null) { //products with shades
                if (this.IsMakeupProduct) {
                    
                    if (labelObj!=null) {
                      labelObj.style.display="";
                    }
                    if (obj1!=null) {
                      obj1.style.display="";
                    }
                    if (obj2!=null) {
                      obj2.style.display="none";
                    }
                    
                     productBubbleSmShadesObj.innerHTML=this.GetShadeTableString(result,true);//'Makeup shades go here';
                     productBubbleSmShadesObj.style.display="";
             }
                else { //products with no shades
              
                     if (labelObj!=null) {
                      labelObj.style.display="none";
                     }
                       if (obj1!=null) {
                      obj1.style.display="none";
                    }
                     if (obj2!=null) {
                      obj2.style.display="";
                    }
                    productBubbleSmShadesObj.innerHTML="";
                    productBubbleSmShadesObj.style.display="none";
                }
            }
            
            if (dropdownlistObj!=null) {
                if (result.Variants!=null) {
                    var hasuniqueprices=false;
                    if (this.DistinctPrice!=0) {
                    hasuniqueprices=true;
                    }
                    dropdownlistObj.innerHTML=GenerateDropDownVariants(result.Variants,this.Bubble_DropDownListID,hasuniqueprices);
                    //Instead request a span or div and use inner HTML.
                    dropdownlistObj.style.visibility='visible';
                    //dropdownlistObj.style.display='block';
                }
                else {
                    dropdownlistObj.style.visibility='hidden';
                    dropdownlistObj.style.display='none';
                }
            }
             var viewmoredetailsobj=$get(this.VIEWMOREDETAILS_ID);
             if(viewmoredetailsobj!=null) {
       
                 var strviewmoredetails=viewmoredetailsobj.innerHTML;
                 if (this.VIEWMOREDETAILS_INNERHTML_TEMPLATE=="") {
                    this.VIEWMOREDETAILS_INNERHTML_TEMPLATE=strviewmoredetails;//preserve for future clicks
                 }
                 else {
                     strviewmoredetails=this.VIEWMOREDETAILS_INNERHTML_TEMPLATE;
                 }
                  strviewmoredetails=strviewmoredetails.replace("$$$AJAX_ParentProductCode$$$",this.Code);
                 viewmoredetailsobj.innerHTML= strviewmoredetails.toString();
               }
            //Populate some of the LastShoppingCartItem object properties, be sure to handle the price upon the addtobag item
            _LastShoppingCartItem.PopulateData("","",this.Code,result.Name,this.DistinctPrice);

            //MM_showHideLayers( this.Bubble_DivID,'','show','QuickLook'); //????
            $get(this.Bubble_DivID).style.visibility='visible'
            _CoreModalPopUp._PopupControlID=this.Bubble_DivID;
            _CoreModalPopUp.ShowModal();
        }
    }

    /**
     * determines if all variants has the same exact price or a diffrent one. It will be needed the way
     * variants are displayed
     * @param {object} _Variants the data that comes into a JASON format from a web service
     */
    this.DetermineMultiplePrices=function(_Variants) {
        this.DistinctPrice=0;
        this.HasMultiplePrices=false;
        var ComparePrice =-1;

        for(var i=0; i<_Variants.length; i++){
            if(_Variants[i].MainPrice !=ComparePrice &&  i > 0) {
                this.HasMultiplePrices=true;
                break;
            }
            ComparePrice=_Variants[i].MainPrice;
        }

        if (!this.HasMultiplePrices) {
            this.DistinctPrice=ComparePrice;
        }
    }

    /**
     * it manages to build up the shade table
     * @param {object} ProductObject the data that comes into a JASON format from a web service
     */
    this.DisplayShadeTable=function(ProductObject) {
        if (ProductObject.Result!=null  && ProductObject.Result.Variants!=null) {
            var innerHTMlString = this.GetShadeTableString(ProductObject.Result,false);
           // var obj = $get(this.Variants_Main_All_Thumbnails);
           var obj = $get(this.Variants_ThumbnailDivID);
           
            if (obj!=null) {
                //alert(innerHTMlString);
                obj.innerHTML=innerHTMlString; 
            }
            var prodnameobj2=$get(this.Bubble_ProductNameID2);

            if(prodnameobj2!=null) {
                prodnameobj2.innerHTML= ProductObject.Result.Name;
            }
            //href
            var viewmoredetailsobj=$get(this.VIEWMOREDETAILS2_ID);
             if(viewmoredetailsobj!=null) {
       
                 var strviewmoredetails=viewmoredetailsobj.innerHTML;
                 if (this.VIEWMOREDETAILS_INNERHTML_TEMPLATE2=="") {
                    this.VIEWMOREDETAILS_INNERHTML_TEMPLATE2=strviewmoredetails;//preserve for future clicks
                 }
                 else {
                     strviewmoredetails=this.VIEWMOREDETAILS_INNERHTML_TEMPLATE2;
                 }
                  strviewmoredetails=strviewmoredetails.replace("$$$AJAX_ParentProductCode$$$",this.Code);
                 viewmoredetailsobj.innerHTML= strviewmoredetails.toString();
             }
            //
            this.ShowShades();
        }
    }

    /**
     * it manages to build up the string of the shade table
     * please be aware that this method uses the javascript
     * string builder class to improve the performance vs the regular string concatination
     * @param {object} result the data that comes into a JASON format from a web service
     * @param {bool} SmallShadesWanted true or false, if true, we build the thumbnails
     */
    this.GetShadeTableString=function(result,SmallShadesWanted) {
        if (result!=null  && result.Variants!=null) {
            var VariantsToBeDisplayed=result.Variants;
            var CurrentRowNumber=0;
            var CurrentCellInCurrentRow=0;
            var sb = new StringBuilder();
            var HasShadeSubGroup=false;
            var StartSubGroupConst='$#Begin#$';
            var PreviousSubGroupValue=StartSubGroupConst;
              var swatchW;
              var swatchH;
              if (SmallShadesWanted) {
                    swatchW=VARIANT_SMALL_SHADE_WIDTH;
                    swatchH=VARIANT_SMALL_SHADE_HEIGHT;
              }
              else {
              
                    swatchW=VARIANT_MEDIUM_SHADE_WIDTH;
                    swatchH=VARIANT_MEDIUM_SHADE_HEIGHT;
              }
            
            //alert(VariantsToBeDisplayed.Properties);
            if (typeof(SHADE_SUB_GROUP_FLD)!='undefined' || SHADE_SUB_GROUP_FLD!='') {
                   HasShadeSubGroup=true;
                   sb.append("<table border=0 cellspacing=1 cellpadding=1><tr><td >");
            }
            else {
                    sb.append("<table border=0 cellspacing=1 cellpadding=1><tr>");
            }
            
            for(var i=0; i<VariantsToBeDisplayed.length; i++) {
               if (HasShadeSubGroup==true) {
              //subgrouping get value
               var currenSubGroupValue="";
               if (VariantsToBeDisplayed[i].Properties!=null) {
                    var _Properties=VariantsToBeDisplayed[i].Properties;
                    for(var j=0; j<_Properties.length; j++) {
                        //alert(_Properties[j].Name);
                        //alert(_Properties[j].Value);
                        if (_Properties[j].Name==SHADE_SUB_GROUP_FLD) {
                          currenSubGroupValue=_Properties[j].Value;
                          }
                    }
                }

                //subgrouping build table
                 if (PreviousSubGroupValue!=currenSubGroupValue && HasShadeSubGroup==true) {
                        if (PreviousSubGroupValue!=StartSubGroupConst) { //close subgrouping
                            if (CurrentRowNumber>0 && CurrentCellInCurrentRow<this.RowSize) {
                                for(var k=CurrentCellInCurrentRow; k<this.RowSize; k++)
                                {
                                    sb.append("<td><img src=\"" + SPACER_IMAGE + "\"" + " width=\"" + swatchW + "\" height=\"" +swatchH + "\" border=\"0\"></td>");
                                   
                                }
                             }
                            sb.append("</tr></table></div></td></tr></table></div>" );
                        }
                       // sb.append("<table border=0 cellspacing=1 cellpadding=1><tr height=\"1px\"><td  colspan=\"2\"><hr class=\"BL_pink1px\"></td></tr><tr><td width=\"29%\" class=\"Adrkpink10pxR\" >" );
                        sb.append("<div class=\"BL_pink1px\"><table border=0 cellspacing=1 cellpadding=1><tr><td width=\"29%\" class=\"Adrkpink10pxR\" >" );
                      
                        sb.append(currenSubGroupValue);
                        sb.append("</td><td align=\"left\">" );
                        sb.append("<div class=\"Adrkpink10pxR\"><table border=0 cellspacing=1 cellpadding=1><tr>");
                        CurrentRowNumber+=1;
                        CurrentCellInCurrentRow=0;
                        PreviousSubGroupValue=currenSubGroupValue;
                
                  }
                 }
               
                //CurrentCellInCurrentRow = i -  CurrentRowNumber * this.RowSize - this.CurrentIndex;
               
                if (CurrentCellInCurrentRow >= this.RowSize ) {
                    sb.append("</tr><tr>");
                    CurrentRowNumber+=1;
                    CurrentCellInCurrentRow=0;
                }
            
                if (SmallShadesWanted) {
                   // sb.append("<td><img id='A_" + VariantsToBeDisplayed[i].SKU +"' src='" + this.Bubble_ImagePrefix_SmallShade + VariantsToBeDisplayed[i].SKU +  this.Bubble_ImageSuffix_SmallShade + "' onclick=\"javascript:SetDropDownItemSelected('" + this.Bubble_DropDownListID + "','" + VariantsToBeDisplayed[i].SKU +"');\" style=\"cursor:pointer\" ></td>");
                    sb.append("<td><img id='A_" + VariantsToBeDisplayed[i].SKU +"' src='" + this.Bubble_ImagePrefix_SmallShade + VariantsToBeDisplayed[i].SKU +  this.Bubble_ImageSuffix_SmallShade + "' onclick=\"javascript:SetDropDownItemSelected('" + this.Bubble_DropDownListID + "','" + VariantsToBeDisplayed[i].SKU +"');\" style=\"cursor:pointer\""  + " width=\"" + swatchW + "\"  height=\"" +swatchH + "\"></td>");
           
                }
                else {
                    
                    //    sb.append("<td><img id='A_" + VariantsToBeDisplayed[i].SKU +"' src='" +  this.Bubble_Thumbnail_ImagePrefix + VariantsToBeDisplayed[i].SKU +  this.Bubble_Thumbnail_ImageSuffix + "'       onmouseover=\"javascript:_QuickShop_Class.ShowByObjectPosition(this,'" + VariantsToBeDisplayed[i].SKU +"',true,5,5);\" style=\"cursor:pointer;\"  width=\"100\" height=\"100\"></td>");
                     sb.append("<td><img id='A_" + VariantsToBeDisplayed[i].SKU +"' src='" +  this.Bubble_ImagePrefix_MediumShade + VariantsToBeDisplayed[i].SKU +  this.Bubble_ImageSuffix_MediumShade + "'       onmouseover=\"javascript:_QuickShop_Class.ShowByObjectPosition(this,'" + VariantsToBeDisplayed[i].SKU +"',true,5,5);\" style=\"cursor:pointer;\""  + " width=\"" + swatchW + "\"  height=\"" +swatchH + "\"></td>");
       
                }
                 CurrentCellInCurrentRow+=1;
             }
             //
             if (CurrentRowNumber>0 && CurrentCellInCurrentRow<this.RowSize) {
                    for(var i=CurrentCellInCurrentRow; i<this.RowSize; i++)
                    {
                       // sb.append("<td>&nbsp;</td>");
                       sb.append("<td><img src=\"" + SPACER_IMAGE + "\"" + " width=\"" + swatchW + "\" height=\"" +swatchH + "\" border=\"0\"></td>");
                                   
                    }
             }
             //
             sb.append("</tr></table>");
             //
             if (HasShadeSubGroup) {
                sb.append("</div></td></tr></table></div></td></tr></table>" );
             }
             if (CurrentRowNumber>5) {
               _CoreModalPopUp._IsforegroundElementLarge=true;
             }
             else {
               _CoreModalPopUp._IsforegroundElementLarge=false;
             }
             
             //alert(sb.toString());
            return sb.toString();
        }
        return "";
    }

    /**
     * set the shade table visible
     */
    this.ShowShades=function () {
        var obj= $get(this.Variants_Main_All_Thumbnails);
        
        if (obj!=null) {
                /*
                   obj.style.visibility='visible';
                   _CoreModalPopUp._IsforegroundElementLarge=true;
                   _CoreModalPopUp._PopupControlID=this.Variants_Main_All_Thumbnails;
                   _CoreModalPopUp.ShowModal();
                */
             var scrollLeft = (document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft);
             var scrollTop = (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop);
             scrollLeft=scrollLeft+310;
             if (scrollTop==0) {
                scrollTop=100;
             }
             scrollTop=scrollTop +150;
             obj.style.visibility='visible';
             obj.style.top=scrollTop + "px";
             obj.style.left=scrollLeft +"px";
           // obj.style.top=this.tempY + "px";
           // obj.style.left=this.tempX +"px";
        }
    }

    /**
     * hides shades/variants
     */
    this.HideShades=function() {
        var obj= $get(this.Variants_Main_All_Thumbnails);
        if (obj!=null) {
            obj.style.visibility='hidden';
        }
        
        _QuickShop_Class.Hide();
    }

    /**
     * saves the current cursor coordinates when clicked on a particular link
     * needed when we want to display the bubble relative with cursor position clicked
     */
    this.LockCoordinates=function() {
        this.tempX=GetMouseCoordinateX();
        this.tempY=GetMouseCoordinateY();
    }

    /**
     * Adds an item in the bag, the function determines the selected sku and calls the webservice method
     * to add item to the bag
     */
    this.AddSingleProductToCart=function () {
         var ItemQuantity=1;
         ItemQuantity=GetSelectedValue(this.Bubble_QuantityID);
         var ItemCode="";
         ItemCode=GetSelectedValue(this.Bubble_DropDownListID);
        //alert(ItemCode);
         MM_showHideLayers(this.Bubble_DivID,'','hide') 
        //set shopping cart last item properties
         _LastShoppingCartItem.ItemQuantity=ItemQuantity; //save the quantity for later retrival
         _LastShoppingCartItem.ItemCode=ItemCode;         //save variant code
         // _LastShoppingCartItem.ItemPrice=0; //figure out an algorithm of populating the price  for the variant added to cart
       // hide modal
        _CoreModalPopUp.Hide();
        //call web service methods
        _WebServiceAPI.AddSingleProductToCart (GetCurrentCustomerID(),ItemCode,ItemQuantity,_ShoppingCartBubble_Class.AddSingleProductToCartResultHandler)
    }
}

/**
 * It registers the ProductBubble_Class using registerClass method of MS AJAX Library
 */
 if (IsTypeDefined) { Core.ProductBubble_Class.registerClass('Core.ProductBubble_Class'); }



/**
 * @class ProductBubble_Class
 * This class handles operation with shopping cart like add to baga, retrive shopping cart, display etc..
 * for more details, look at its method
 * P.S: This class has not been quite finished as it needs some more methods in order to hanadle most of our needs
 * @constructor 
 */
 Core.ShoppingCartBubble_Class=function () {
    //Properties
     /**
     *  The main dhtml layer for the shopping cart
     */
    this.ShoppingCartBubble_DivID='ShoppingCartBubble_Div';
    //IDS
    /**
     *  A dhtml layer where subtotal will be displayed
     */
    this.ShoppingCartBubble_SubTotalID='ShoppingCartBubble_SubTotal';
     /**
     *  A dhtml layer where subtotal will be displayed on the header outside of the bubble
     */
   this.ShoppingCartBubble_SubTotalID_Header='ShoppingCartBubble_SubTotal_header';
    /**
     *  A dhtml layer where total will be displayed
     */
    this.ShoppingCartBubble_TotalID='ShoppingCartBubble_Total';
    /**
     *  A dhtml layer where tax will be displayed
     */
    this.ShoppingCartBubble_TaxTotalID='ShoppingCartBubble_TaxTotal';
    /**
     *  A dhtml layer where shipping subtotal will be displayed
     */
    this.ShoppingCartBubble_ShippingSubTotalID='ShoppingCartBubble_ShippingSubTotal';
    //
    /**
     * A dhtml layer where total items will be displayed
     */
    this.ShoppingCartBubble_TotalItemsID='ShoppingCartBubble_TotalItems'
    /**
     * A dhtml layer where total items will be displayed outside of the bubble
     */
    this.ShoppingCartBubble_TotalItemsID_Header_Outside='ShoppingCartBubble_TotalItems_header'
    /**
     *  success layer, not used yet
     */
    this.ShoppingCartBubble_SuccessID='ShoppingCartBubble_Success';
    /**
     *  failure layer not used yet
     */
    this.ShoppingCartBubble_FailureID='ShoppingCartBubble_Failure';

 
    /**
     * It holds the DHTML Object ID for product Name of last item added
     */
    this.ShoppingCartBubble_ProductNameID="ShoppingCartBubble_ProductName";  
    /**
     * It holds the DHTML Object ID for Variant Name of last item added
     */
    this.ShoppingCartBubble_VariantNameID="ShoppingCartBubble_VariantName";  
    /**
     * It holds the DHTML Object ID for item unit price of last item added
     */
    this.ShoppingCartBubble_ItemPriceID="ShoppingCartBubble_ItemPrice";      
    /**
     * It holds the DHTML Object ID for item quantity of last item added
     */
    this.ShoppingCartBubble_ItemQuantityID="ShoppingCartBubble_ItemQuantity"; 
    /**
     * It holds the DHTML Object ID for last item total example: UnitPrice * Quantity
     */
    this.ShoppingCartBubble_LastItemTotalAmountID="ShoppingCartBubble_LastItemTotalAmount";
    
    /**
     *
     * Events
     */
     /**
     * the name of the function to be called before the popup opens
     */
    this.beforeOpen=null; 
    
    /**
     * the name of the function to be called before the popup closes
     */
    this.beforeClose=null;
    /**
     * Handles the callback from the web service AddSingleProductToCart
     * @param {object} result the data that comes into a JASON format from a web service
     */
    this.AddSingleProductToCartResultHandler=function(result)  {
          DoDefault();
        if (result != null) {
            if (result.ActivityStatus==true) { 
                //Display The Shopping Cart
                //var _WebServiceAPI=new  WebServiceAPI_Class();
                _WebServiceAPI.RetrieveShoppingCart(GetCurrentCustomerID(),_ShoppingCartBubble_Class.RetrieveShoppingCartResultHandler);
            }
            else  {
                //Display a Message
                //  alert ('Item failed to be added');
                alert(result.ErrorString);
            }  
        }
    }

    /**
     * Handles the callback from the web service RetrieveShoppingCartLastItems
     * @param {object} result the data that comes into a JASON format from a web service
     */
    this.RetrieveShoppingCartLastItemsResultHandler=function (result) {
        DoDefault();
        if (result != null) {
            _ShoppingCartBubble_Class.DisplayShoppingCartAndLastItems(result);
        }
    }

    /**
     * Displays the shopping and last items
     */
    this.DisplayShoppingCartAndLastItems=function() {
        alert('this method is not finished yet, it is in progress');
        this.Show();
    }

    /**
     * Handles the callback from the web service RetrieveShoppingCart
     * @param {object} result the data that comes into a JASON format from a web service
     */
    this.RetrieveShoppingCartResultHandler=function (result) {
        DoDefault();
        if (result != null) {
            _ShoppingCartBubble_Class.DisplayShoppingCart(result);
        }
    }

    /**
     * Displays the shopping cart information
     * @param {object} result the data that comes into a JASON format from a web service
     */
    this.DisplayShoppingCart=function(result) {
        DoDefault();
        //display subtotal
        if ($get(this.ShoppingCartBubble_SubTotalID)!=null) {
            $get(this.ShoppingCartBubble_SubTotalID).innerHTML=result.SubTotal.toFixed(2);;
        }
        //populate header subtotal
        var obj_h=$get(this.ShoppingCartBubble_SubTotalID_Header);
        
        if (obj_h!=null) {
            obj_h.innerHTML=result.SubTotal.toFixed(2);
            obj_h.innerHTML="$ " + obj_h.innerHTML;
        }
         
        //display total amount
        if ($get(this.ShoppingCartBubble_TotalID)!=null) {
            $get(this.ShoppingCartBubble_TotalID).innerHTML=result.Total.toFixed(2);
        }
        //display tax 
        if ($get(this.ShoppingCartBubble_TaxTotalID)!=null) {
            $get(this.ShoppingCartBubble_TaxTotalID).innerHTML=result.TaxTotal.toFixed(2);
        }
        //display shipping cost
        if ($get(this.ShoppingCartBubble_ShippingSubTotalID)!=null) {
         $get(this.ShoppingCartBubble_ShippingSubTotalID).innerHTML=result.ShippingSubTotal.toFixed(2);
        
        }
        //total items within bubble
        if ($get(this.ShoppingCartBubble_TotalItemsID)!=null) {
            $get(this.ShoppingCartBubble_TotalItemsID).innerHTML=result.Quantity;
        }
        //updating total items outside of bubble like header
         if ($get(this.ShoppingCartBubble_TotalItemsID_Header_Outside)!=null) {
            $get(this.ShoppingCartBubble_TotalItemsID_Header_Outside).innerHTML=result.Quantity;
        }
         this.DisplayShoppingCartLastItem(); //new
         this.Show();
    }

   /**
     * Displays the shopping cart information
     */
    this.DisplayShoppingCartLastItem=function() { //new method
        //product name
       if ($get(this.ShoppingCartBubble_ProductNameID)!=null) {
            $get(this.ShoppingCartBubble_ProductNameID).innerHTML=  _LastShoppingCartItem.ItemParentName;
        }
        
        //variant name
        if ($get(this.ShoppingCartBubble_VariantNameID)!=null) {
            $get(this.ShoppingCartBubble_VariantNameID).innerHTML=  _LastShoppingCartItem.ItemName;
        }
        //variant price
        if ($get(this.ShoppingCartBubble_ItemPriceID)!=null) {
               $get(this.ShoppingCartBubble_ItemPriceID).innerHTML=  _LastShoppingCartItem.ItemPrice;//.toFixed(2);
        }
        //variant quantity
        if ($get( this.ShoppingCartBubble_ItemQuantityID)!=null) {
               $get( this.ShoppingCartBubble_ItemQuantityID).innerHTML=  _LastShoppingCartItem.ItemQuantity;
        }
     
        //total item for last item quantity * price
        if ($get( this.ShoppingCartBubble_LastItemTotalAmountID)!=null) {
                var _ItemTotalAmount=0
                _ItemTotalAmount=parseInt(_LastShoppingCartItem.ItemQuantity) * _LastShoppingCartItem.ItemPrice;
               $get( this.ShoppingCartBubble_LastItemTotalAmountID).innerHTML=  _ItemTotalAmount.toFixed(2);
        }
    
    
    }
    /**
     * Displays the shopping cart bubble
     */
    this.Show=function() {
        var obj=$get(this.ShoppingCartBubble_DivID);
        obj.style.visibility='visible';
        obj.style.display='';
        // slideContent(this.ShoppingCartBubble_DivID.toString(),10);
          if (this.beforeOpen!=null) {
             eval(this.beforeOpen + "();");
        
        }
    }

    /**
     * Hides the shopping cart bubble
     */
    this.Hide=function() {
        var obj=$get(this.ShoppingCartBubble_DivID);
        obj.style.visibility='hidden';
         obj.style.display='none';
        _QuickShop_Class.Hide();
        if (this.beforeClose!=null) {
             eval(this.beforeClose + "();");
        
        }
    }
}

 /**
 * It registers the ShoppingCartBubble_Class using registerClass method of MS AJAX Library
 */
 if (IsTypeDefined) { Core.ShoppingCartBubble_Class.registerClass('Core.ShoppingCartBubble_Class'); }

/**
 * @class ShoppingCartItem_Class
 * This class stores the information of the last item added to bag
 * @constructor 
 */
 Core.ShoppingCartItem_Class=function () {
    /**
     * Variant code of the item added to shopping cart
     */    
    this.ItemCode="";
    /**
     * Variant name
     */ 
    this.ItemName="";
    /**
     * Product code(parent product code of the variant)
     */ 
    this.ItemParentCode="";
    /**
     * Product Name(parent product name of the variant)
     */ 
    this.ItemParentName="";
    /**
     * quantity of the last add to bag
     */ 
    this.ItemQuantity=1;
    /**
     * item unit price
     */ 
    this.ItemPrice=0;
    
    /**
     * Populates the major data of the object
     @param {_ItemCode,_ItemName,_ItemParentCode,_ItemParentName,_ItemPrice} 
     */ 
    this.PopulateData=function(_ItemCode,_ItemName,_ItemParentCode,_ItemParentName,_ItemPrice){
                this.ItemCode=_ItemCode;
                this.ItemName=_ItemName;
                this.ItemParentCode=_ItemParentCode;
                this.ItemParentName=_ItemParentName;
                this.ItemPrice=_ItemPrice;
        
        }
}

/**
 * It registers the Core.ShoppingCartItem_Class using registerClass method of MS AJAX Library
 */
 if (IsTypeDefined) { Core.ShoppingCartItem_Class.registerClass('Core.ShoppingCartItem_Class'); }


/*
 *It handle the window on resize event
 */
 window.onresize =  OnResizeHandler; 
/*
 *It handle the window on scroll event
 */
  window.onscroll =  OnScrollHandler; 


/**
 * @class Product_Class
 * This class has only properties
 * Result will hold the data that comes from the webservices
 * in JSON format
 * When a product object is created, it is added in the collection by productmanager
 * with Loaded=false
 * when successful response comes from the web service, loaded is set to true
 * so next time, if the user will access the same product, and if ENABLE_PRODUCT_CACHING is
 * set to true, the data will be taken from the memory vs webservice call. This is done to improve the performance
 * and minimize the calls to the server.
 * @constructor 
 */

Core.Product_Class=function () {
    /**
     * Product Code which is prd_code in DB
     */    
    this.ProductCode="";

    /**
     *  The json object reurned via webservices
     */
    this.Result;

    /**
     * Product Name
     */
    this.Name="";

    /**
     * it is set to true if loaded and set to false otherwise.
     */
    this.Loaded=false;
    
    this.Discont_Association="";
    this.Finish="";
    this.SkinTone="";
    this.ShadeColor="";
    this.ParentProductTeaser="";
    this.Variant_QSName="";
    
    this.PopulateData=function(result){
        this.ProductCode = result.SKU;
        this.Name = result.Name;
        this.Result = result;        
        var props = result.Properties;
        for (j=0; j<props.length;j++){
            switch(props[j].Name){
                case 'Discont_Association':{this.Discont_Association = props[j].Value;break;}
                case 'Shade_Finish':{this.Finish = props[j].Value;break;}
                case 'BestForSkinTones':{this.SkinTone = props[j].Value;break;}
                case 'HexValue':{this.ShadeColor = props[j].Value;break;}
                case 'Parent_ProductTeaser':{this.ParentProductTeaser = props[j].Value;break;}
                case 'Variant_QSName':{this.Variant_QSName = props[j].Value;break;}
                default:{break;}
            }
        }
    }
}
/**
 * It registers the Product_Class using registerClass method of MS AJAX Library
 */
 if (IsTypeDefined) {Core.Product_Class.registerClass('Core.Product_Class'); }


/**
 * @class ProductManager_Class
 * This class Manages both Products and Variants
 * It adds a product/variant in the collection,
 * loads the data from webservice and caches the data locally
 * if caching is enabled for both Products and Variants
 * @constructor 
 */

 Core.ProductManager_Class=function() {
    /**
     * The collection of the products to be cached (visited previously by the user)
     */
    this.ProductCollection=new Array();
    /**
     * The collection of Variants Cached (visited previously by the user)
     */
    this.VariantCollection=new Array();
    /**
     * 0 build shade table 
     * 1 Skin Care
     */
    this.Action=0; 
    
    this.Code="";

    /**
     * Adds a product to the internal product collection
     * @param {object} ProductObject The product object
     */
    this.AddProduct= function (ProductObject) {
        var exist=false;
        if (this.ProductCollection!=null) {
            for (var i=0; i<this.ProductCollection.length; i++) {
                if (this.ProductCollection[i].ProductCode==ProductObject.ProductCode) {
                    this.ProductCollection[i]=ProductObject;
                    exist=true;
                    break;
                }
            }

            if(exist==false) {
                this.ProductCollection[this.ProductCollection.length]=ProductObject;
            }
        }
    }

    /**
     * Retrieve a product to the internal product collection
     * @param {string} ProductCode The product code of the product to retrieve from the ProductCollection
     */
    this.GetProduct=function (ProductCode) {
        for (var i=0;i<this.ProductCollection.length;i++) {
            if (this.ProductCollection[i].ProductCode==ProductCode) {
               // if (this.ProductCollection[i].Loaded==true) { //make sure the product is loaded
                  return this.ProductCollection[i];
               // }
            }
        }
    }

    /**
     * This method below checks if a copy exist on the Memory, if it does, no need to call web service
     * @param {string} ProductCode The product code of the product to retrieve
     */
    this.LoadProduct=function (ProductCode) {
        _ProductBubble_Class.LockCoordinates();
        _ProductBubble_Class.HideShades();

        if (ENABLE_PRODUCT_CACHING) {
            var _Product=this.GetProduct(ProductCode)
            if ((_Product==null ) || (typeof(_Product)=='undefined') || (_Product.Loaded==false)) {
                _Product=new Core.Product_Class();
                _Product.ProductCode=ProductCode;
                this.AddProduct(_Product);
                // var _WebServiceAPI=new  WebServiceAPI_Class();
                _WebServiceAPI.LoadProduct(ProductCode,true,this.OnRequestComplete);
            }
            else {
                this.DoBranching(_Product);
            }
        }
        else {
            _WebServiceAPI.LoadProduct(ProductCode,true,this.OnRequestComplete);
        }
    }



    /**
     * TODO
     * @param {string} ProductCode The product code of the product to retrieve
     */
    this.LoadProductThumbnails=function(ProductCode) {
        this.Action=0;
        this.LoadProduct(ProductCode);
    }

    /**
     * TODO
     * @param {string} ProductCode The product code of the product to retrieve
     */
    this.LoadSkinCareProduct=function(ProductCode) {
        this.Action=1;
        this.LoadProduct(ProductCode);
    }

    /**
     * TODO
     * @param {string} ProductCode The product code of the product to retrieve
     */
    this.LoadMakeupProduct=function(ProductCode) {
        this.Action=2;
        this.LoadProduct(ProductCode);
    }
     /**
     * Used to add a product to a customer's favorite list
     * @param {string} CustomerId The customer ID GUID
     * @param {int} FavoriteProductType The type of favorite list to retrieve
     * @param {string} RetailerCode The current retailer code
     * @param {string} ProductCode The product code to add to the customer's favorite list
     */
     this.AddProductToFavorites=function(FavoriteProductType, RetailerCode, ProductCode) {
        this.Code = ProductCode;
       _WebServiceAPI.AddToFavorites(CurrentCustomerID, this.ConvertTypeToInteger(FavoriteProductType), RetailerCode, ProductCode, this.AddProductToFavoritesOnComplete);
     }
     
    
    /**
     * This method is called after a web Service Call is Completed
     * @param {string} result The result object returned from the web service
     */
    this.OnRequestComplete= function (result) {
        DoDefault();
        if (result != null)    {
            if (ENABLE_PRODUCT_CACHING) {
                var _Product=_ProductManager.GetProduct(result.SKU);//later use the productid
                _Product.Result=result;
                _Product.Loaded=true;
                _ProductManager.AddProduct(_Product);
                //_ProductManager.DisplayShadeTable(_Product);
                _ProductManager.DoBranching(_Product);
            }
            else {
                var  _Product=new Core.Product_Class();
                _Product.ProductCode=result.SKU;
                _Product.Result=result;
                _ProductManager.DoBranching(_Product);
            }
        }
    }


    /**
     * TODO
     * @param {ProductBubble_Class} _Product The product bubble
     */
    this.DoBranching=function(_Product) {
        _ProductBubble_Class.IsMakeupProduct=true;

        switch(this.Action){
            case 0 :
                //this.DisplayShadeTable(_Product);
                 _ProductBubble_Class.Code=_Product.ProductCode;
                _ProductBubble_Class.DisplayShadeTable(_Product);
                break;
            case 1 :
                _ProductBubble_Class.IsMakeupProduct=false;
                _ProductBubble_Class.Code=_Product.ProductCode;
                _ProductBubble_Class.LoadProductRequestComplete(_Product.Result)
                break;
            case 2 :
                _ProductBubble_Class.IsMakeupProduct=true;
                _ProductBubble_Class.Code=_Product.ProductCode;
                _ProductBubble_Class.LoadProductRequestComplete(_Product.Result)
                break;
            default :
                //this.DisplayShadeTable(_Product);
                 _ProductBubble_Class.Code=_Product.ProductCode;
                _ProductBubble_Class.DisplayShadeTable(_Product);
                break;
        }
    }


    // Variant methods:

    /**
     * Adds a variant to the VariantCollection array
     * @param {object} VariantObject The variant object
     */
    this.AddVariant= function (VariantObject) {
        var exist=false;
        if (this.VariantCollection!=null) {
            for (var i=0;i<this.VariantCollection.length;i++) {
                if (this.VariantCollection[i].ProductCode==VariantObject.ProductCode) {
                    this.VariantCollection[i]=VariantObject;
                    exist=true;
                    break;
                }
            }
            if(exist==false) {
                this.VariantCollection[this.VariantCollection.length]=VariantObject;
            }
        }
    }

    /**
     * Retrieves a variant to the VariantCollection array
     * @param {string} VariantCode The variant code to find
     */
    this.GetVariant=function (VariantCode) {
        for (var i=0;i<this.VariantCollection.length;i++) {
            if (this.VariantCollection[i].ProductCode==VariantCode) {
                return this.VariantCollection[i];
            }
        }
    }

    /**
     * Retrieves the variant either from the web service or cache (if enabled) 
     * @param {string} VariantCode The variant code to find
     */
    this.LoadVariant=function (VariantCode) {
        if (ENABLE_VARIANT_CACHING) {
            var _Variant=this.GetVariant(VariantCode)
            if ((_Variant==null) || (typeof(_Variant)=='undefined') || (_Variant.Loaded=false)){
                _Variant=new Core.Product_Class();
                _Variant.ProductCode=VariantCode;
                this.AddVariant(_Variant);
                _WebServiceAPI.LoadProduct(VariantCode,false,this.VariantOnRequestComplete)
            }
            else {
                // this.DisplayShadeTable(_Product);
                this.DoVariantBranching(_Variant);
            }
        }
        else {
            _WebServiceAPI.LoadProduct(VariantCode,false,this.VariantOnRequestComplete)
        }
    }
           
    /**
     * Callback handler from LoadVariant
     * @param {object} result The resulting product object
     */
    this.VariantOnRequestComplete = function (result) {
        DoDefault();
        if (result != null) {
            if (ENABLE_VARIANT_CACHING) {
                var _Variant=_ProductManager.GetVariant(result.SKU);//later use the productid
                _Variant.Result=result;
                _Variant.Loaded=true;
                _ProductManager.AddVariant(_Variant);
                _ProductManager.DoVariantBranching(_Variant);
            }
            else {
                var  _Variant=new Core.Product_Class();
                _Variant.ProductCode=result.SKU;
                _Variant.Result=result;
                _ProductManager.DoVariantBranching(_Variant);
            }
        }
    }

    /**
     * Do variant branching
     * @param {object} _Variant The variant object
     */
    this.DoVariantBranching=function(_Variant) {
        _VariantBubble_Class.Code=_Variant.ProductCode;
        _VariantBubble_Class.PopulateData(_Variant.Result);
    }

    /**
     * Loads a shade in a bubble
     * @param {string} VariantCode Loads the variant for display
     */
    this.LoadMakeupVariant=function(VariantCode) {
        this.Action=0;
        this.LoadVariant(VariantCode);
    }
}
 /**
 * It registers the  ProductManager_Class using registerClass method of MS AJAX Library
 */
 if (IsTypeDefined) { Core.ProductManager_Class.registerClass('Core.ProductManager_Class'); }

/**
 * @class Topic_Class
 * 
 * 
 * 
 * 
 * 
 */
Core.Topic_Class=function () {
    /**
     * Topic Code which is prd_code in DB
     */    
    this.TopicCode="";

    /**
     *  The json object reurned via webservices
     */
    this.Result;

    /**
     * Topic Types
     */
    this.TopicType="";

    /**
     * it is set to true if loaded and set to false otherwise.
     */
    this.Loaded=false;
}
/**
 * It registers the Topic_Class using registerClass method of MS AJAX Library
 */
 if (IsTypeDefined) {Core.Topic_Class.registerClass('Core.Topic_Class'); }


/**
 * @class Core.TopicManager_Class
 *
 * 
 * 
 * 
 * @constructor 
 */

 Core.TopicManager_Class=function() {
   
 
   /**
     * Saves a topic to customer profile. OnCompleteFuncName is not passed or is it empty, the control is passed
     * on this.SaveTopicOnComplete otherwise the custom call back function will be called.
     * @param {string} TopicCode 
     * @param {string} TopicType 
     * @param {object} OnCompleteFuncName (optional)
     */
   this.SaveTopic=function(TopicCode,TopicType,OnCompleteFuncName) {
      if (typeof(OnCompleteFuncName)=='undefined' || (OnCompleteFuncName=="")) {
	   _WebServiceAPI.TopicCustomerRatingRecord(CurrentCustomerID, TopicType, TopicCode, 'tips', 5, 'n/a', this.SaveTopicOnComplete);
	
	  }
	  else {
	 
	   _WebServiceAPI.TopicCustomerRatingRecord(CurrentCustomerID, TopicType, TopicCode, 'tips', 5, 'n/a',OnCompleteFuncName);
	
	  }
	
	}

    this.GetTopicProductsCodes= function (TopicCode, TopicType,FilterLevel)  {
      // _WebServiceAPI.GetTopicProductsCodes(TopicCode,TopicType,this.GetTopicProductsCodesOnComplete);
       _WebServiceAPI.GetTopicProductsCodes(TopicCode,TopicType,(FilterLevel==1) ? this.GetTopicProductsCodesOnComplete: this.GetTopicParentProductsCodesOnComplete);
    
    }
    
    this.GetTopicProductsCodesOnComplete= function (result)  {
       
        DoDefault();
         if (result!=null) {
            _NavigatorManager.FilteredData=result;
            _NavigatorManager.DoFilterInitialization(VARIANT_LAYER_PARENT_CONTAINS);
         }
    }
    
   this.GetTopicParentProductsCodesOnComplete= function (result)  {
         DoDefault();
         if (result!=null) {
            _NavigatorManager.FilteredData=result;
            _NavigatorManager.DoMainFilterInitialization(MAIN_LAYER_PARENT_CONTAINS); 
         }
   
   }
    
   this.GetTopicProductsCodesByTopicList=function(TopicList,TopicType,FilterLevel){
         if (typeof(TopicList)=='undefined' || TopicList=="") {return false;}
         DoWait();
         try {
            _NavigatorManager.ClearFilter(); //clear prev filter
         }
         catch(e){
          //do nothing
         }
         if (TopicList.indexOf(',') ==-1){
                this.GetTopicProductsCodes(TopicList,TopicType,FilterLevel);
        }
        else {
              


                _WebServiceAPI.GetTopicProductsCodesByTopicList(TopicList,(FilterLevel=='1') ? this.GetTopicProductsCodesOnComplete: this.GetTopicParentProductsCodesOnComplete);
        }
   }

 
}

/**
 * It registers the  Core.TopicManager_Class using registerClass method of MS AJAX Library
 */
 if (IsTypeDefined) { Core.TopicManager_Class.registerClass('Core.TopicManager_Class'); }

/**
 * @class SignInBubble_Class
 * This class is responsible for managing the Ajax signin module
 */

Core.SignInBubble_Class=function() {
    this.PopupPath = POPUPPATHSIGNIN;
    this.PopupHeight = POPUPSIGNINHIEGHT;
    this.PopupWidth = POPUPSIGNINWIDTH;
    this.TopicType = "";
    this.newWindow = "";

    /**
     * Shows the Sign in bubble from the Favorites 
     */    
    this.ShowBubbleFromFavoritesBubble=function(objCode){
        
        if (this.newWindow && !this.newWindow.closed)	{
		    this.newWindow.close();
	    }	
		
	    var winl = (screen.width - this.PopupWidth) / 2;
	    var wint = (screen.height - this.PopupHeight) / 2;
	    if (this.TopicType == ""){
	        this.newWindow = open(this.PopupPath + "?objCode=" + objCode, 'FavoritePopup', ("toolbar=no,location=no,directories=no,status=yes,menubar=no,scrollbars=no,resizable=no,copyhistory=no,top=" + wint + ",left=" + winl + ",width=" + this.PopupWidth + ",height=" + this.PopupHeight + "\""));
	    }else{
	        this.newWindow = open(this.PopupPath + "?objCode=" + objCode + "&TopicType=" + this.TopicType, 'FavoritePopup', ("toolbar=no,location=no,directories=no,status=yes,menubar=no,scrollbars=no,resizable=no,copyhistory=no,top=" + wint + ",left=" + winl + ",width=" + this.PopupWidth + ",height=" + this.PopupHeight + "\""));
	    }
	    this.newWindow.focus();
    }

    /**
     * Shows the Sign in bubble from the Favorites 
     */    
    this.ShowBubble=function(){    
        if (this.newWindow && !this.newWindow.closed)	{
		    this.newWindow.close();
	    }	
		
	    var winl = (screen.width - this.PopupWidth) / 2;
	    var wint = (screen.height - this.PopupHeight) / 2;
    
        this.newWindow = open(this.PopupPath, 'SigninPopup', ("toolbar=no,location=no,directories=no,status=yes,menubar=no,scrollbars=no,resizable=no,copyhistory=no,top=" + wint + ",left=" + winl + ",width=" + this.PopupWidth + ",height=" + this.PopupHeight + "\""));

	    this.newWindow.focus();    
    
    }
    
}
/**
* It registers the  SignInBubble_Class using registerClass method of MS AJAX Library
*/
if (IsTypeDefined) { Core.SignInBubble_Class.registerClass('Core.SignInBubble_Class'); }

/**
 * @class DhtmlPaginator
 * Paginator Class is used to dynamically handle the paging Next, Previous based on properties set for this object.
 * The values set are default, but they should be reset based on where it gets used
 * @constructor 
 */
Core.DhtmlPaginator=function () {
    /**
     * Part of substring of the main layer we are interested into applying paging
     */
    this.KeywordLayerContain='Category:Product:List'; //'
    /**
     * tag name
     */
    this.TagName='div';
    /**
     * size (number of elemnts displayed in one page)
     */
    this.PageSize=5;
    /**
     * total pages within a layer/product/category
     */
    this.TotalPages=0;
    /**
     *  array where results will be saved
     */
    this.NavigateArray=new Array();
    /**
     * current page where the user is navigating
     */
    this.CurrentPage=0;
    /**
     * the layer id of the parent
     */
    this.ParentID='';
    /**
     * if true the buttons will be managed autimatically
     */
    this.SetNavigationLabels=true;
    /**
     * The id of next button on the header
     */
    this.NextButtonID="nextpage";
    /**
     * The id of next button on the footer
     */
    this.NextButtonID_Footer="nextpage_footer";
    /**
     * the id of previous on the header
     */
    this.PreviousID="Previous";
    
    /**
     * the id of previous on the header
     */
    this.PreviousID_Footer="Previous_Footer";
    /**
     * the layer where total number of pages will be displayed(optional)
     */
    this.DisplayPageNumberID="currentpageof";
     /**
     * the layer where total number of pages will be displayed(optional)on the footer
     */
    this.DisplayPageNumberID_Footer="currentpageof_footer";
    
    /**
     *  if GeneratePageNumbers=true, the page numbers will be generated
     */
    this.GeneratePageNumbers=false;
     /**
     *  This layer holds all other buttons like next, prev, 1,2,3, view all etc.. and it will
     * be marked as hidden if there is only one page.
     */
    this.MainPaginatorLayerID="AJAX_PAGINATOR_LAYER";
    this.MainPaginatorLayerID_FOOTER="AJAX_PAGINATOR_LAYER_FOOTER";
     /**
     * Layer id where the numbers will be displayedon the header
     */
    this.PageNumberLayerID="Ajax_Page_Numbers"
    
    /**
     * Layer id where the numbers will be displayedon the footer
     */
    this.PageNumberLayerID_Footer="Ajax_Page_Numbers_Footer";
     /**
     * html for links opening tag for numbers
     */
     this.PageNumberOpeningTag=CORE_AJAX_PAGING_NUMBERS_STYLESHEET;
    
     /**
     * html for closing tags for numbers
     */
     this.PageNumberClosingTag=CORE_AJAX_PAGING_NUMBERS_CLOSING_TAG;
     
     /**
     * html for opening tag for current page
     */
     this.CurrentPageOpeningTag=CORE_AJAX_CURRENT_PAGE_STYLESHEET;
    
     /**
     * html for closing tag for current page
     */
     this.CurrentPageClosingTag=CORE_AJAX_CURRENT_PAGE_CLOSING_TAG;
   /**
     * Saves current to be shown
     */
    this.CurrentItemsToShow=new Array();
    /**
     *  Saves current to be Hidden
     */
    this.CurrentItemsToHide=new Array;
    
    /**
     *  all variants
     */
    this.AllVariantsBtnID="ajax_all_variants";
     /**
     * Text to be displayed on view all btn
     */
    this.ViewAllLabel="View All";
      
    /**
     *  Saves Filtered Data 
     */
    this.FilteredData=null;
    this.IsFilterOn=false;
    
    this.showBegin = 0;
    this.showEnd = 0;
    this.nextPage = 0;
    this.prevPage = 0;
    this.PageNextButton = CORE_AJAX_NEXT_BUTTON;
    this.PagePrevButton = CORE_AJAX_PREV_BUTTON;
    
    /**
     *  Generates page numbers for both header and footer
     *  if the GeneratePageNumbers is set to true and at least one layer for header or footer exist
     *
     */
    this.DoGeneratePageNumbers=function(){
     if(this.GeneratePageNumbers==false) return;
      var sb = new StringBuilder();
       if (this.TotalPages>=1) {
           if (this.TotalPages>1) {
               if (this.CurrentPage==-1) {
                  sb.append(this.CurrentPageOpeningTag + this.ViewAllLabel +this.CurrentPageClosingTag+ "&nbsp;");
       
               }
               else {
                  sb.append("<a " + " onclick=\"_NavigatorManager.DoPageByIndex('" + this.ParentID + "',0)\" style=\"cursor:pointer\";>" + this.PageNumberOpeningTag + this.ViewAllLabel + this.PageNumberClosingTag+ "</a>&nbsp;");
             }
           }
     
          var pageNumbersObj_Header=$get(this.PageNumberLayerID);
          if (pageNumbersObj_Header!=null) {
                  pageNumbersObj_Header.innerHTML=sb.toString();
           }
           
           var pageNumbersObj_Footer=$get(this.PageNumberLayerID_Footer);
           if (pageNumbersObj_Footer!=null) {
                 pageNumbersObj_Footer.innerHTML=sb.toString();
           }
       }
       
    }
    /**
     * Initializes the object
     */
    this.Initialize=function() {
        var list;
         this.NavigateArray=new Array();
        if (this.ParentID!='') {
        //alert(typeof($));
            var parentObj=$get(this.ParentID);
            // if (parentObj==null || typeof(parentObj)='undefined') return;
            list=parentObj.getElementsByTagName(this.TagName);
        }
        else {
            list = document.body.getElementsByTagName(this.TagName);
            //var list = document.body.getElementsByTagName(this.TagName);
        }

        for (var i = 0; i < list.length ; i++) {
            if (list[i].id.indexOf(this.KeywordLayerContain) !=-1) {
                //this.NavigateArray[this.NavigateArray.length]=list[i].id;
                this.NavigateArray[this.NavigateArray.length]=list[i];
            }
        }

        if ((this.NavigateArray !=null) && (this.PageSize>0)) {
            this.TotalPages=Math.ceil(parseInt(this.NavigateArray.length));
        }
        this.CurrentPage=0;
        
    }
    
    this.InitializeFilter=function() {
        this.HideAll(); //hide previous page!
         var list;
         this.NavigateArray=new Array();
        if (this.ParentID!='') {
             var parentObj=$get(this.ParentID);
             list=parentObj.getElementsByTagName(this.TagName);
        }
        else {
            list = document.body.getElementsByTagName(this.TagName);
        }
     
        for (var i = 0; i < list.length ; i++) {
            for (var j = 0; j < this.FilteredData.length ; j++) {
                 if (list[i].id.indexOf(this.FilteredData[j]) !=-1) {           //make sure productcode is part of
                      if(list[i].id.indexOf(this.KeywordLayerContain) !=-1){    //make sure it has the contain layer id
                         this.NavigateArray[this.NavigateArray.length]=list[i];
                       }
                  }
            }
        }

        if ((this.NavigateArray !=null) && (this.PageSize>0)) {
            this.TotalPages=Math.ceil(parseInt(this.NavigateArray.length)/parseInt(this.PageSize));
        }
        this.CurrentPage=0;
        this.DoNext();
        
    }


    /**
     * hides all pages
     */
    this.HideAll=function(){
        if (this.NavigateArray  !=null) {
            for (var i=0;i<this.NavigateArray.length;i++) {
                if (typeof(this.NavigateArray[i])=='object'){
                    this.NavigateArray[i].style.display='none';
                }
                else {
                    var divid=this.NavigateArray[i];
                    var oDiv = document.getElementById(divid);
                    oDiv.style.display='none';
                }
            }
        }
    }

    /**
     * shows all pages
     */
    this.ShowAll=function(){
        if (this.NavigateArray !=null ) {
            for (var i=0;i<this.NavigateArray.length;i++) {
                if (typeof(this.NavigateArray[i])=='object'){
                    // this.NavigateArray[i].style.display='block';
                    this.NavigateArray[i].style.display='';
                }
                else {
                    var divid=this.NavigateArray[i];
                    var oDiv = document.getElementById(divid);
                    oDiv.style.display='block';
                }
            }
        }
    }
    
    /*
     * this method supports navigating to a particular page by index
    */
    this.DoPageByIndex=function(index) {
        this.CurrentPage=parseInt(index)-1;
        if (this.CurrentPage>=0) {
             this.DoNext();
        }
        else {
           this.DoGeneratePageNumbers();
           this.EraseFooterLabel();
           this.ShowAll();
        }
    }
    
    this.EraseFooterLabel=function() {
             //display page x of y on a label for the current page on the footer
            var tempObj=$get(this.DisplayPageNumberID);
            if (tempObj!=null) {
                tempObj.innerHTML="";
            }
            //display page x of y on a label for the current page on the footer
            var tempObj_Footer=$get(this.DisplayPageNumberID_Footer);
             if (tempObj_Footer!=null) {
                tempObj_Footer.innerHTML="";
            }
    
    
    }
    /**
     * naviates to the next page
     */
    this.DoNext=function() {
        if (this.CurrentPage>=this.TotalPages) return false;
        if (this.CurrentPage<=this.TotalPages)  this.HideAll();
        if (this.CurrentPage<=0) this.CurrentPage=0;

        this.CurrentPage=this.CurrentPage+1;
        var startI=(this.CurrentPage-1) * this.PageSize;
        var endI=this.CurrentPage * this.PageSize;

        this.SetLabels();
        this.DoGeneratePageNumbers();
        this.CurrentItemsToShow=new Array();
        for (var i=startI;i<endI;i++) {
            if (i<this.NavigateArray.length) {
                 this.CurrentItemsToShow[ this.CurrentItemsToShow.length]=this.NavigateArray[i]
                if (typeof(this.NavigateArray[i])=='object'){
                    // this.NavigateArray[i].style.display='block';
                    this.NavigateArray[i].style.display='';
                }
                else {
                    var divid=this.NavigateArray[i];
                    var oDiv = document.getElementById(divid);
                    oDiv.style.display='block';
                }
            }
        }
    }

 
      /**
     * naviates to the next page in a slide
     */
    this.DoNextSlide=function() {
        if (this.CurrentPage>=this.TotalPages) return false;
        if (this.CurrentPage<=0) this.CurrentPage=0;
        this.CurrentPage=this.CurrentPage+1;
        var startI=(this.CurrentPage-1) * this.PageSize;
        var endI=this.CurrentPage * this.PageSize;
        this.SetLabels();
        this.DoGeneratePageNumbers();
        //initialize array
        this.CurrentItemsToHide=new Array();
        //copy array
        for (var i = 0; i < this.CurrentItemsToShow.length; i++)   {
            this.CurrentItemsToHide[this.CurrentItemsToHide.length]=this.CurrentItemsToShow[i];

        }
        //initialize array
        this.CurrentItemsToShow=new Array();
        for (var i=startI;i<endI;i++) {
             if (i<this.NavigateArray.length) {
                 this.CurrentItemsToShow[ this.CurrentItemsToShow.length]=this.NavigateArray[i];
             }
        }
        //initialize array
        CurrentItemsToShow=new Array();
        //initialize array
        CurrentItemsToHide=new Array();
         //copy array to global variable
        for (var i = 0; i < this.CurrentItemsToShow.length; i++)   {

            CurrentItemsToShow[CurrentItemsToShow.length]=this.CurrentItemsToShow[i];

        }
         //copy array to global variable
        for (var i = 0; i < this.CurrentItemsToHide.length; i++)   {

            CurrentItemsToHide[CurrentItemsToHide.length]=this.CurrentItemsToHide[i];

        }
       
       //initialize index of item to be shown first
       ToShowIndex=0;
       //initialize index of item to be hidden first
       ToHideIndex=0;
       DoCoreSlideNext();
    }
    /**
     * navigates to Previous page
     */
    this.DoPrev=function() {
        if (this.CurrentPage<=1) return false;
        if (this.CurrentPage<=this.TotalPages)  this.HideAll();
        if (this.CurrentPage==this.TotalPages) this.CurrentPage=this.TotalPages;

        this.CurrentPage=this.CurrentPage-1;

        var startI=(this.CurrentPage-1) * this.PageSize;
        var endI=this.CurrentPage * this.PageSize;

        this.SetLabels();
        this.DoGeneratePageNumbers();
        for (var i=startI;i<endI;i++) {
            if (i<this.NavigateArray.length) {
                if (typeof(this.NavigateArray[i])=='object') {
                    this.NavigateArray[i].style.display='';
                }
                else {
                    var divid=this.NavigateArray[i];
                    var oDiv = document.getElementById(divid);
                    oDiv.style.display='block';
                }
            }
        }
    }

    /**
     * navigates to Previous page in a slide
     */
    this.DoPrevSlide=function() {
        if (this.CurrentPage<=1) return false;
        if (this.CurrentPage==this.TotalPages) this.CurrentPage=this.TotalPages;

        this.CurrentPage=this.CurrentPage-1;

        var startI=(this.CurrentPage-1) * this.PageSize;
        var endI=this.CurrentPage * this.PageSize;

        this.SetLabels();
        this.DoGeneratePageNumbers();
        //initialize
        this.CurrentItemsToHide=new Array();
        //copy current shown to array of to be hidden
        for (var i = 0; i < this.CurrentItemsToShow.length; i++)   {
            this.CurrentItemsToHide[this.CurrentItemsToHide.length]=this.CurrentItemsToShow[i];

        }
         //initialize
        this.CurrentItemsToShow=new Array();
        
        for (var i=startI;i<endI;i++) {
            if (i<this.NavigateArray.length) {
                //save the reference for further processing in a slide
                this.CurrentItemsToShow[ this.CurrentItemsToShow.length]=this.NavigateArray[i];
             }
        }
        //initialize
         CurrentItemsToShow=new Array();
         //initialize
         CurrentItemsToHide=new Array();
          //copy array to global variable
         for (var i = 0; i < this.CurrentItemsToShow.length; i++)   {

            CurrentItemsToShow[CurrentItemsToShow.length]=this.CurrentItemsToShow[i];

          }
         
         //copy array to global variable
         for (var i = 0; i < this.CurrentItemsToHide.length; i++)   {

            CurrentItemsToHide[CurrentItemsToHide.length]=this.CurrentItemsToHide[i];

        }
        //set initial index for items to be shown
         ToShowIndex=CurrentItemsToShow.length - 1;
         //set initial index for items to be hidden
         ToHideIndex=CurrentItemsToHide.length -1;
         //call the slide function
         DoCoreSlidePrev();
    }
    
     /**
     * This function hides the main layer of paginator if there is less or equal one page and shows otherwise
     * 
     * 
     */
    this.ManagePaginatorMainLayers=function() {
         var temp_objMainPaginatorLayerID=$get( this.MainPaginatorLayerID );
            
         var temp_objMainPaginatorLayerID_FOOTER=$get( this.MainPaginatorLayerID_FOOTER );
         
          if (temp_objMainPaginatorLayerID!=null) {
                if (this.TotalPages>1 && this.TotalPages > this.PageSize) {
                    temp_objMainPaginatorLayerID.style.visibility="visible";
                }else{
                    temp_objMainPaginatorLayerID.style.visibility="hidden";  
                }
          }
          
           if (temp_objMainPaginatorLayerID_FOOTER!=null) {
                if (this.TotalPages>1 && this.TotalPages > this.PageSize ) {
                    temp_objMainPaginatorLayerID_FOOTER.style.visibility="visible";
                }else{
                    temp_objMainPaginatorLayerID_FOOTER.style.visibility="hidden";  
                }
          }
    
    }
    /**
     * This function manages the next, previous buttons both on header and footer,
     * it also manages the Off btns. They are all optional and the code handles the run time error if any
     * of them is missing
     */
     
    this.SetLabels=function(){        
         //all variants btn
         var tempobj_AllVariantsBtnID=$get(this.AllVariantsBtnID);
        
          this.ManagePaginatorMainLayers();
         if (this.SetNavigationLabels) {
             
            //handle all shades btn
              if (tempobj_AllVariantsBtnID!=null) {
                  if (this.TotalPages>1) {
                        tempobj_AllVariantsBtnID.style.visibility="visible";
                        tempobj_AllVariantsBtnID.style.display="";
                }
                else {
                        tempobj_AllVariantsBtnID.style.visibility="hidden";  
                }
            }
                       
            //display page x of y on a label for the current page
            var tempObj=$get(this.DisplayPageNumberID);
           
            // Beginning Number
            if (this.CurrentPage == 1){
                this.showBegin = this.CurrentPage;
            }else if (this.showBegin + this.PageSize > this.TotalPages){
                this.showBegin = this.TotalPages;
            }else{
                this.showBegin = this.showBegin + this.PageSize;
            } 

            // End Number
            if (this.CurrentPage == 1){
                this.showEnd = this.PageSize;
            }else if (this.showEnd + this.PageSize > this.TotalPages){
                this.showEnd = this.TotalPages;
            }else{
                this.showEnd = this.showEnd + this.PageSize;
            } 
            
            if (this.CurrentPage != this.TotalPages){
                this.nextPage = this.CurrentPage + 1;
                this.prevPage = this.CurrentPage - 1;
            }
            // Header
            if (tempObj!=null) {
                tempObj.innerHTML="<a " + " onclick=\"_NavigatorManager.DoPageByIndex('" + this.ParentID + "'," + this.prevPage + ")\" style=\"cursor:pointer\";>" +  this.PagePrevButton + this.PageNumberClosingTag+ "</a>&nbsp;" + PAGE_PAGExOFy + this.showBegin + " - " + this.showEnd + OFF_PAGExOFy + this.TotalPages + DISPLAY_PAGExOFy + "<a " + " onclick=\"_NavigatorManager.DoPageByIndex('" + this.ParentID + "'," + this.nextPage + ")\" style=\"cursor:pointer\";>" +  this.PageNextButton + this.PageNumberClosingTag+ "</a>&nbsp;&nbsp;";
                //tempObj.innerHTML=PAGE_PAGExOFy + this.CurrentPage + OFF_PAGExOFy + this.TotalPages + DISPLAY_PAGExOFy;
            }
            
            //Footer
            var tempObj_Footer=$get(this.DisplayPageNumberID_Footer);
            if (tempObj_Footer!=null) {              
                tempObj_Footer.innerHTML="<a " + " onclick=\"_NavigatorManager.DoPageByIndex('" + this.ParentID + "'," + this.prevPage + ")\" style=\"cursor:pointer\";>" +  this.PagePrevButton + this.PageNumberClosingTag+ "</a>&nbsp;" + PAGE_PAGExOFy + this.showBegin + " - " + this.showEnd + OFF_PAGExOFy + this.TotalPages + DISPLAY_PAGExOFy + "<a " + " onclick=\"_NavigatorManager.DoPageByIndex('" + this.ParentID + "'," + this.nextPage + ")\" style=\"cursor:pointer\";>" +  this.PageNextButton + this.PageNumberClosingTag+ "</a>&nbsp;&nbsp;";
                //tempObj_Footer.innerHTML=PAGE_PAGExOFy + this.CurrentPage + OFF_PAGExOFy + this.TotalPages + DISPLAY_PAGExOFy;;
            }
            
            // if there are no "Next" Pages
            if(this.showEnd == this.TotalPages){
                // Header 
                if (tempObj!=null) {
                    tempObj.innerHTML="<a " + " onclick=\"_NavigatorManager.DoPageByIndex('" + this.ParentID + "'," + this.prevPage + ")\" style=\"cursor:pointer\";>" +  this.PagePrevButton + this.PageNumberClosingTag+ "</a>&nbsp;" + PAGE_PAGExOFy + this.showBegin + " - " + this.showEnd + OFF_PAGExOFy + this.TotalPages + DISPLAY_PAGExOFy;
                }
                // Footer
                if (tempObj_Footer!=null) {              
                    tempObj_Footer.innerHTML="<a " + " onclick=\"_NavigatorManager.DoPageByIndex('" + this.ParentID + "'," + this.prevPage + ")\" style=\"cursor:pointer\";>" +  this.PagePrevButton + this.PageNumberClosingTag+ "</a>&nbsp;" + PAGE_PAGExOFy + this.showBegin + " - " + this.showEnd + OFF_PAGExOFy + this.TotalPages + DISPLAY_PAGExOFy;
                }
            }
            // if there are no "Prev" Pages
            if(this.CurrentPage == 1){
                // Header 
                if (tempObj!=null) {
                    tempObj.innerHTML=PAGE_PAGExOFy + this.showBegin + " - " + this.showEnd + OFF_PAGExOFy + this.TotalPages + DISPLAY_PAGExOFy + "<a " + " onclick=\"_NavigatorManager.DoPageByIndex('" + this.ParentID + "'," + this.nextPage + ")\" style=\"cursor:pointer\";>" +  this.PageNextButton + this.PageNumberClosingTag+ "</a>&nbsp;&nbsp;";
                }
                // Footer
                if (tempObj_Footer!=null) {              
                    tempObj_Footer.innerHTML=PAGE_PAGExOFy + this.showBegin + " - " + this.showEnd + OFF_PAGExOFy + this.TotalPages + DISPLAY_PAGExOFy + "<a " + " onclick=\"_NavigatorManager.DoPageByIndex('" + this.ParentID + "'," + this.nextPage + ")\" style=\"cursor:pointer\";>" +  this.PageNextButton + this.PageNumberClosingTag+ "</a>&nbsp;&nbsp;";
                }
            }            
            
        }
    }
   
 }
/**
 * It registers the  DhtmlPaginator using registerClass method of MS AJAX Library
 */
 if (IsTypeDefined) { Core.DhtmlPaginator.registerClass('Core.DhtmlPaginator'); }

 /* End of Paginator Class */

/**
 * @class NavigatorManager
 * NavigatorManager  Class is used to dynamically iterate the DHTML Object and add next/prev buttons based
 * the values that are passed on the Initialize method
 * It Also keep the reference of such DHTML Object for the sake of bookmarking/navigations
 * Here is an example how I used this class and initialized it on topic page
 *       var _NavigatorManager=new NavigatorManager();
 *       _NavigatorManager.Initialize('Topic:Product:List','div','Topic_Product','td',5,false);
 * @constructor 
 */

 Core.NavigatorManager=function () {
    /**
     * collection of navigators
     */
    this._NavigatorCollection=new Array();
    this.FilteredData;
    
     this.DoMainFilterInitialization=function(ParentLayerContains) {
        var productCodesArray=new Array();
        var lastProductCodeFethched=""
        this.FilteredData.sort();
         for (var i=0;i<this.FilteredData.length;i++) {
            var currentRecord_Array=this.FilteredData[i].split(":"); 
            if (currentRecord_Array[1]!="" && currentRecord_Array[1]!=lastProductCodeFethched){
                lastProductCodeFethched=currentRecord_Array[1];
                productCodesArray[productCodesArray.length]=currentRecord_Array[1];
            }
            // productCodesArray[productCodesArray.length]=currentRecord_Array[1];
         }
         if (productCodesArray.length>0) {
              var currentNavigator=this.GetNavigator(ParentLayerContains);
               currentNavigator.IsFilterOn=true;
               currentNavigator.FilteredData=productCodesArray;
               currentNavigator.InitializeFilter();
         }
     }
    
    this.DoFilterInitialization=function(ParentLayerContains) {
        var currentPrdCode="";
        var currentParentPrdCode="";
        var currentNavigator=null;
        var variantsByProduct=new Array();
        var allDistinctFilteredProducts=new Array();
        var noMatchIDs=new Array();
        this.FilteredData.sort();
        for (var i=0;i<this.FilteredData.length;i++) {
            var currentRecord_Array=this.FilteredData[i].split(":"); 
                if (currentRecord_Array[0]!=currentParentPrdCode) {
                    if (currentNavigator!=null) { 
                        currentNavigator.FilteredData=variantsByProduct ;
                        currentNavigator.InitializeFilter();
                        
                     }
                     
                 variantsByProduct=new Array();
                 currentParentPrdCode=currentRecord_Array[0];
                 allDistinctFilteredProducts[allDistinctFilteredProducts.length]=currentRecord_Array[0];
                 // var tempParentID="Category:Product:List:" + currentParentPrdCode;
                 var tempParentID=ParentLayerContains + currentParentPrdCode;
                 currentNavigator=this.GetNavigator(tempParentID);
                 if (currentNavigator!=null || typeof(currentNavigator)!='undefined') {
                   
                       currentNavigator.FilteredData=new Array();;
                       currentNavigator.IsFilterOn=true;
                 }
              }
              if (currentRecord_Array[1]!=currentPrdCode) { //array is sorted and this condition is placed to remove any duplicate!
                 currentPrdCode=currentRecord_Array[1];
                 variantsByProduct[variantsByProduct.length]=currentPrdCode;
                
              }
        }
      
        //hide the variants of those who does not have a match
        for (var i=0;i<this._NavigatorCollection.length;i++) {
        
             var blnExist=false;
              var tempObj=this.GetNavigator(this._NavigatorCollection[i].ParentID);
           
              if ( tempObj.ParentID.indexOf(ParentLayerContains)!=-1 ){
                          for (var j=0;j<allDistinctFilteredProducts.length;j++) {
                            var tempNavigatorID=ParentLayerContains + allDistinctFilteredProducts[j];
                              if (tempObj.ParentID==tempNavigatorID) {
                                         blnExist=true;
                                        break;
                               }
                   
                           }
                // alert(tempObj.ParentID);
                  if (blnExist==false) {
                       noMatchIDs[noMatchIDs.length]=tempObj.ParentID;
                      tempObj.IsFilterOn=true; //but no match
                      tempObj.HideAll();
                      tempObj.TotalPages=0;
                 }
              }
            
         }
         //
         var FilteredParent=new Array(); //removed the products that come from database but has no match on the page.
         for (var i=0;i<allDistinctFilteredProducts.length;i++) {
                for (var j=0;j<noMatchIDs.length;j++)  {
                   if ( noMatchIDs[j].indexOf(allDistinctFilteredProducts[i])!=-1 ) {
                     allDistinctFilteredProducts[i]="";
                     
                   }
                }
          }
          //
          for (var i=0;i<allDistinctFilteredProducts.length;i++) {
              if (allDistinctFilteredProducts[i]!="") {
                FilteredParent[FilteredParent.length]=":" + allDistinctFilteredProducts[i];
              }
          }       
          //
          if (allDistinctFilteredProducts.length>0) {
           this.FilteredData=FilteredParent;
           this.DoMainFilterInitialization(MAIN_LAYER_PARENT_CONTAINS);
          }
      
    }
    
    //
    this.ClearFilter=function() {
      for (var i=0;i<this._NavigatorCollection.length;i++) {
            if (this._NavigatorCollection[i].IsFilterOn==true) {
                    this._NavigatorCollection[i].Initialize();
                    this._NavigatorCollection[i].DoNext();
          
           }
       }
    }
    /**
     * adds a navigator in the collection
     * @param {object} NavigatorObject TODO
     */
    this.AddNavigator= function (NavigatorObject) {
        var exist=false;
        if (this._NavigatorCollection!=null) {
            for (var i=0;i<this._NavigatorCollection.length;i++) {
                if (this._NavigatorCollection[i].ParentID==NavigatorObject.ParentID) {
                    this.NavigatorObject[i]=NavigatorObject;
                    exist=true;
                    break;
                }
            }
            if(exist==false) {
                this._NavigatorCollection[this._NavigatorCollection.length]=NavigatorObject;
            }
        }
    }

    /**
     * returns an elemnt within a collection based on parentid which has to be unique
     * @param {string} ParentID where the object is contained
     */
    this.GetNavigator=function (ParentID) {
        for (var i=0;i<this._NavigatorCollection.length;i++) {
            if (this._NavigatorCollection[i].ParentID==ParentID) {
                return this._NavigatorCollection[i];
            }
        }
    }
    
    this.DoPageByIndex=function(ParentID,index) {
       var CurrentNavigator=this.GetNavigator(ParentID);
       CurrentNavigator.DoPageByIndex(index);
    }
    /**
     * naviates to the next page
     * @param {string} ParentID 
     * @param {object} NextObject 
     */
    this.DoNext=function(ParentID,NextObject,DoSlide) {
        var CurrentNavigator=this.GetNavigator(ParentID);
        CurrentNavigator.NextButtonID=NextObject.id;
        if (DoSlide) {
                CurrentNavigator.DoNextSlide();
        }
        else {
           CurrentNavigator.DoNext();
        }
    }
    
    /**
     * naviates to the next page from the footer
     * @param {string} ParentID 
     * @param {object} NextFooterObject 
     */
    this.DoNextFromFooter=function(ParentID,NextFooterObject) {
        var CurrentNavigator=this.GetNavigator(ParentID);
        CurrentNavigator.NextButtonID_Footer=NextFooterObject.id;
        CurrentNavigator.DoNext();
    }
    /**
     * Shows all pages
     * @param {string} ParentID 
     */
    this.ShowAll=function(ParentID) {
        var CurrentNavigator=this.GetNavigator(ParentID);
        CurrentNavigator.ShowAll();
    }

    /**
     * Navigates to previous page
     * @param {string} ParentID for prev button
     * @param {object} PreviousObject 
     */
    this.DoPrev=function(ParentID,PreviousObject,DoSlide) {
        var CurrentNavigator=this.GetNavigator(ParentID);
        CurrentNavigator.PreviousID=PreviousObject.id;
        if(DoSlide) {
          CurrentNavigator.DoPrevSlide();
        }
        else {
        CurrentNavigator.DoPrev();
        }
    }
    
      /**
     * Navigates to previous page from the footer
     * @param {string} ParentID of the whole container for pages
     * @param {object} PreviousFooterObject
     */
    this.DoPrevFromFooter=function(ParentID,PreviousFooterObject) {
        var CurrentNavigator=this.GetNavigator(ParentID);
        CurrentNavigator.PreviousID_Footer=PreviousFooterObject.id;
        CurrentNavigator.DoPrev();
    }
    /**
     * This is a very important method
     * which first retrievs from document object all the tags with name ParenTagName like "div", span", "td", "tr" etc....
     * Then it iterates via such object and searches only those that have as part of the ID the substring
     * ParentContains which could be like Topic:Product:List
     * If an object meets that criteria, then we are intersted from objects within that parent
     * that has their tags as ChildTagName and contains on their ID the value ChildContains.
     * @param {string} ParentContains Substring of DHTML Object we are interested. <b>Importnat, try to keep such value unique based on what we need to process</b>
     * @param {string} ParenTagName Tag name of parents like div, span, td, tr etc...
     * @param {string} ChildContains Substring of DHTML Object we are interested. <b>Importnat, try to keep such value unique based on what we need to process</b>
     * @param {string} ChildTagName Tag name of parents like div, span, td, tr etc...
     * @param {int} PageSize How manay elements of childcontain wanted to be visible at a certain time
     * @param {bool} BoolNavigationBtnsWanted It determines if we want to manage the buttons next and prev 
     * @param {bool} BoolGeneratePageNumbers if set to true, generates the page numbers like 1,2,3,4 etc..
      */
    this.Initialize=function(ParentContains, ParenTagName, ChildContains, ChildTagName, PageSize, BoolNavigationBtnsWanted,AssumeNavigationBtns,BoolGeneratePageNumbers) {
        var list = document.body.getElementsByTagName(ParenTagName);
        for (var i = 0; i < list.length ; i++) {
            if (list[i].id.indexOf(ParentContains) !=-1) {
                var _TempNavigator= new Core.DhtmlPaginator();
                _TempNavigator.PageSize=PageSize;
                _TempNavigator.SetNavigationLabels=BoolNavigationBtnsWanted;
                _TempNavigator.KeywordLayerContain=ChildContains; // //'
                _TempNavigator.TagName=ChildTagName;
                _TempNavigator.ParentID=list[i].id;
                //navigation buttons
                if(AssumeNavigationBtns!=null) {
                    if (AssumeNavigationBtns) {
                         _TempNavigator.NextButtonID="Next_" + list[i].id.replace(ParentContains,'');
                         _TempNavigator.PreviousID="Prev_" + list[i].id.replace(ParentContains,'');
                         //
                         _TempNavigator.AllVariantsBtnID="ajax_all_variants_" + list[i].id.replace(ParentContains,'');
                         //
                         _TempNavigator.NextButtonID_Footer=_TempNavigator.NextButtonID_Footer + "_" +list[i].id.replace(ParentContains,'');
                         _TempNavigator.PreviousID_Footer=_TempNavigator.PreviousID_Footer + "_" +list[i].id.replace(ParentContains,'');
                         _TempNavigator.DisplayPageNumberID=_TempNavigator.DisplayPageNumberID + "_" +list[i].id.replace(ParentContains,'');
                         _TempNavigator.DisplayPageNumberID_Footer=_TempNavigator.DisplayPageNumberID_Footer + "_" +list[i].id.replace(ParentContains,'');
                        //
                        _TempNavigator.SetNavigationLabels=true;
                    }
                 }
                   
                _TempNavigator.GeneratePageNumbers=BoolGeneratePageNumbers;
                _TempNavigator.Initialize();
                _TempNavigator.DoNext();
                this.AddNavigator( _TempNavigator);
            }
        }
    }
}
 /**
 * It registers the  Core.NavigatorManager using registerClass method of MS AJAX Library
 */
 if (IsTypeDefined) { Core.NavigatorManager.registerClass('Core.NavigatorManager'); }


/* End of Navaigator Manager Class */


/**
 * @class StringBuilder
 * Models a simple string builder class
 * @param {string} value The value to append to the array
 * @constructor
 */
function StringBuilder(value) {
    this.strings = new Array("");
    this.append(value);
}

/**
 * Appends the given value to the end of this instance.
 */
StringBuilder.prototype.append = function (value) {
    if (value) {
        this.strings.push(value);
    }
}

/**
 * Clears the string buffer
 */
StringBuilder.prototype.clear = function () {
    this.strings.length = 1;
}

/**
 * Converts this instance to a String.
 */
StringBuilder.prototype.toString = function () {
    return this.strings.join("");
}

/* End of StringBuilder  Class */

/**
 * Stores object reference to those to be shown in a slide
 */
 var CurrentItemsToShow=null;
 /**
 * Stores object reference to those to be hidden in a slide
 */
 var CurrentItemsToHide=null;
 /**
 * Stores item index of current item  to be shown in a slide
 */
 var ToShowIndex=0;
 /**
 * Stores item index of current item  to be hidden in a slide
 */
 var ToHideIndex=0;
 /**
 * set time out speed
 */
 var CoreSlideSpeed=75;
 
 /**
 * Slides Next
 */
 function DoCoreSlideNext() {
    if (ToShowIndex<CurrentItemsToShow.length) {
       CurrentItemsToShow[ToShowIndex].style.display='';
       ToShowIndex++;
     }
    if (ToHideIndex<CurrentItemsToHide.length) {
            CurrentItemsToHide[ToHideIndex].style.display='none';
            ToHideIndex++;
    }
    if ((ToShowIndex<CurrentItemsToShow.length) ||(ToHideIndex<CurrentItemsToHide.length)) {
            setTimeout("DoCoreSlideNext()",CoreSlideSpeed);
     }
 
 }

 /**
 * Slides Prev
 */
 function DoCoreSlidePrev() {
   if (ToShowIndex>=0) {
       CurrentItemsToShow[ToShowIndex].style.display='';
       ToShowIndex--;
     }
    if (ToHideIndex>=0) {
            CurrentItemsToHide[ToHideIndex].style.display='none';
            ToHideIndex--;
    }
    if ((ToShowIndex>=0) ||(ToHideIndex>=0)) {
            setTimeout("DoCoreSlidePrev()",CoreSlideSpeed);
     }
 
 }
 
/**
 * OnResizeHandler
 */
function OnResizeHandler(){
    if (!IS_MODELPOPUP_VISIBLE) return;
    _CoreModalPopUp.ResizeHandler();
}


/**
 * OnScrollHandler 
 */
function OnScrollHandler(){
    if (!IS_MODELPOPUP_VISIBLE) return;
    _CoreModalPopUp.ScrollHandler();
}

/**
 * This function is executed whenever a web service raises a run time error
 * If JAVASCRIPT_DEBUG is set to true an alert will be displayed with the actual message.
 * @param {object} result The JSON object returned by web service
 */
function onError(result) {
    DoDefault();
    window.status = "Web Service Error";
    if (result != null) {
        var message = result.get_message();
        var stackTrace = result.get_stackTrace();
        var exceptionType = result.get_exceptionType();
        if (JAVASCRIPT_DEBUG) {
            alert(message + "..." + stackTrace + "...." + exceptionType );
        }
    }
}

/**
 * This function is executed whenever a web service is timed out
 * If JAVASCRIPT_DEBUG is set to true an alert will be displayed.
 * @param {object} result The JSON object returned by web service
 */ 
function onTimeout(result) {
            DoDefault();
           // window.status = "web service call timed out";
            if (JAVASCRIPT_DEBUG) {
                        alert('web service call timed out. Please try again');
            }
}


/**
 * This function returns the customer ID that is assigned to a user
 * If Customer ID is missing and If JAVASCRIPT_DEBUG is set to true an alert
 * will be displayed with the actual message.
 */
function GetCurrentCustomerID() {
    if (CurrentCustomerID== null ||   typeof(CurrentCustomerID)=='undefined') {
        if (JAVASCRIPT_DEBUG)
                 alert('Customer ID is missing');
         return '';
    }
  return CurrentCustomerID;
}

/**
 * Some preliminary work for Mouse coordinates and browser type
 */
var tempX = 0;
var tempY = 0;

var IE = document.all?true:false;
if (!IE) document.captureEvents(Event.MOUSEMOVE)


/**
 * Attaching getMouseXY function onmousemove  event
 */
document.onmousemove = getMouseXY;

/**
 * Attaching HideQuick function onmouseup event
 */
document.onmouseup = HideQuick;

/**
 * This function is used onmouseup event to hide the quick shop bubble
 */
function HideQuick(){
    _QuickShop_Class.Hide();
}


/**
 * This function stores in 2 global variable the mouse x coordinate and y Coordinate
 * @param {object} e Event object
 */
function getMouseXY(e) {
        if (IE) { // grab the x-y pos.s if browser is IE
            //if  (document.readyState != 'complete') return;
            if (!document) return;
            if(!document.body) return;
            tempX = parseInt(event.clientX) + parseInt(document.body.scrollLeft);
            tempY = parseInt(event.clientY) + parseInt(document.body.scrollTop);
        }
        else {  // grab the x-y pos.s if browser is NS
                tempX = e.pageX;
                tempY = e.pageY;
        }
        if (tempX < 0){tempX = 0;}
        if (tempY < 0){tempY = 0;}
        return true;
}

/**
 * Returns the temporary coordinate X of the Mouse
 */
function GetMouseCoordinateX() {
   return tempX;
}

/**
 * Returns the temporary coordinate Y of the Mouse
 */
function GetMouseCoordinateY() {
   return tempY;
}

/* End Mouse Coordinates */

/**
 * This function returns the Value attribute of a selected elemnt in a drop down.
 * @param {string} DropDownObjectID The ID of a drop down
 */
function GetSelectedValue(DropDownObjectID) {
        var x=document.getElementById(DropDownObjectID)
        //return (x.options[x.selectedIndex].text)
        return (x.options[x.selectedIndex].value)
}

/**
 * This function returns the text attribute of a selected element in a drop down.
 * @param {string} name DropDownObjectID The ID of a drop down
 */
function GetSelectedText(DropDownObjectID) {
        var x=document.getElementById(DropDownObjectID)
        return (x.options[x.selectedIndex].text)
}

/**
 * This function generataes the Option of a drop down based on JASON formatted Object Variants
 * Important Note: I am not using this function because I found a thread on the web
 * that this method raises IE error memory can not be referenced. Instead I am using a classic way
 * of building it via innerHTML of a DHTML element like div, span, etc....
 * I am currently using function "GenerateDropDownVariants"
 * @param {object} Variants JSON Serilized Object that Comes via web services Results
 * @param {string} ObjectToAppend The ID of a drop down to generate the options
 */
function BuildDropDownVariants(Variants,ObjectToAppend)
{
    if (Variants !=null )
    {
        for(i=0; i<Variants.length; i++)
        {
            var  option = new Option(Variants[i].Name + " - $ " + Variants[i].MainPrice ,Variants[i].SKU);
            ObjectToAppend.options[i] =option;
        }
    }
}

/**
 * This function builds the Drop Down. Be aware that I am using the javascrpt string builder class instead of
 * string concatinations.
 * @param {object} Variants JSON Serilized Object that Comes via web services Results
 * @param {string} DropDownID The ID of a drop down to generate the options
 */
function GenerateDropDownVariants(Variants,DropDownID,HasUniquePrices)      
{
    var sb = new StringBuilder();
    sb.append("");
    if (Variants != null ) {
        sb.append("<select id=\"");
        sb.append(DropDownID);
        sb.append("\" class=\"Ablack11pxB\">");
        for(i=0; i<Variants.length; i++)  {
            sb.append("<option value=\"");
            sb.append(Variants[i].SKU);
            sb.append("\">");
            if (HasUniquePrices==true) { //all vars same price
              sb.append(Variants[i].Name); 
           
            }
            else {//different variants different prices
              sb.append(Variants[i].Name   + " - $ " + Variants[i].MainPrice );
            }
            sb.append("</option>");
        }
        sb.append("</select>")
    }
    //alert(sb.toString());
    return sb.toString();
}

/**
 * This function set selects a particular option of a drop down
 * @param {string} dropDownID The ID of a drop down
 * @param {string} valueToSelect Value to compare in order to select it
 */
function SetDropDownItemSelected(dropDownID,valueToSelect) {
    var options=document.getElementById(dropDownID)

    if (options!=null) {
        for (var i=0; i< options.length; i++) {
            if (options[i].value==valueToSelect) {
                options.selectedIndex=i;
                break;
            }
        }
    }
}

/**
 * This Function Determines the absolute coordinate X (Left) of any DHTML Object
 * @param {object} obj Obj is any DHTML Object for which we need to determine the absolute Coordinate X (Left)
 */
function findPosX(obj){
    var curleft = 0;

    if (obj.offsetParent){
        while(1){
            curleft += obj.offsetLeft;
            if (!obj.offsetParent)
            {
                break;
            }
            obj = obj.offsetParent;
        }
    }
    else if(obj.x){ curleft+=obj.x }

    return curleft;
}

/**
 * This Function Determines the absolute coordinate Y (Top) of any DHTML Object
 * @param {object} obj Obj is any DHTML Object for which we need to determine the absolute Coordinate Y (Top)
 */
function findPosY(obj){
    var curtop = 0;

    if (obj.offsetParent){
        while(1) {
            curtop += obj.offsetTop;
            if (!obj.offsetParent)
            {
                break;
            }
            obj = obj.offsetParent;
        }
    }
    else if(obj.y) { curtop+=obj.y }

    return curtop;
}

/**
 * This Function is used when on top of any DHTMl Object will be placed another DHTMl Object
 * It is used when I display the QuickShop Layer on top of the Product Image.
 * @param {object} RelativeObject This is any dhtml object, on our case it is a product Image
 * @param {object} ObjectToShow This is the Quick Shop DHTML Layer
 * @param {int} plusTop This will be an integer which will tell us the Top Position of the ObjectToShow
 * @param {int} plusLeft This will be an integer which will tell us the Left Position of the ObjectToShow
 */
function PositionLayerByRelativeObject(RelativeObject,ObjectToShow,plusTop,plusLeft) {
    var _xcoordinate=parseInt(findPosX(RelativeObject));
    var _ycoordinate=parseInt(findPosY(RelativeObject));

    if (!isNaN(plusLeft)){
        _xcoordinate=parseInt(_xcoordinate) + parseInt(plusLeft);
    }
    if (!isNaN(plusTop)){
        _ycoordinate=parseInt(_ycoordinate) + parseInt(plusTop);
    }

    ObjectToShow.style.visibility='visible';
    ObjectToShow.style.position='absolute';
    ObjectToShow.style.top=_ycoordinate + 'px';
    ObjectToShow.style.left=_xcoordinate + 'px';
}


/**
 * DoWait 
 */
function DoWait() {
    window.status = "";
    document.body.style.cursor='wait';
    TogglePleaseWait('visible')
}


/** 
 * DoDefault 
 */
function DoDefault() {
     setTimeout("DoDefaultAfterTimeout()", 500);
}
function DoDefaultAfterTimeout() {
     document.body.style.cursor='default';
     TogglePleaseWait('hidden');
}

function TogglePleaseWait(_Visibility) {
    var _pleaseWaitObject=$get(CORE_AJAX_PLEASEWAIT_DHTMLOBJECT_ID);
    if (_pleaseWaitObject!=null) {
        _pleaseWaitObject.style.visibility=_Visibility;
        if(CORE_AJAX_LOAD_PLEASEWAIT_ASMODAL) {
            _CoreModalPopUp._PopupControlID=CORE_AJAX_PLEASEWAIT_DHTMLOBJECT_ID;
            if (_Visibility=='visible') {
                _CoreModalPopUp.ShowModal();
            }else{
                _CoreModalPopUp.Hide();
            }
        }
    }
}

/**
 * IsAjaxLibraryLoaded is a boolean indicating wether the AJAX JavaScript
 * libraries have been loaded
 */
var IsAjaxLibraryLoaded=false;

/**
 * Fires when Atlas is loaded
 */
function AjaxOnload() {
       IsAjaxLibraryLoaded=true;
}

/** 
 * Determines if ATLAS has been loaded
 */
function IsAjaxLoaded() {
   return IsAjaxLibraryLoaded;
}


function pageLoad() {
  IsAjaxLibraryLoaded=true;
}

/* ...... Functions below needs to be revisited ......  */

function MM_findObj(n, d) { //v4.01
        var p,i,x;  if(!d) d=document; if((p=n.indexOf("?"))>0&&parent.frames.length) {
        d=parent.frames[n.substring(p+1)].document; n=n.substring(0,p);}
        if(!(x=d[n])&&d.all) x=d.all[n]; for (i=0;!x&&i<d.forms.length;i++) x=d.forms[i][n];
        for(i=0;!x&&d.layers&&i<d.layers.length;i++) x=MM_findObj(n,d.layers[i].document);
        if(!x && d.getElementById) x=d.getElementById(n); return x;
    }


function MM_showHideLayers() { //v3.0
  var i,p,v,obj,args=MM_showHideLayers.arguments;
  for (i=0; i<(args.length-2); i+=3)
	if ((obj=MM_findObj(args[i]))!=null)
	{
		v=args[i+2];
		if (obj.style)
		{
			obj=obj.style; v=(v=='show')?'visible':(v='hide')?'hidden':v;
		}
		obj.visibility=v;
	}
	//If there's a popup...
	//alert(args[3]);
	if(args[3] != null)
	{
		var layer = MM_findObj(args[0]);
		var popuptxt = MM_findObj(args[3]);
		var oBo = cBB (popuptxt);
		var oBp = cBB (layer);
		var left=0;
		var top=0;
		left=parseInt(oBo.l) + parseInt(popuptxt.offsetWidth) - 50;
		top=parseInt(oBo.t) - parseInt(layer.offsetHeight) + 15;
		if (isNaN(parseInt(left))) return false;
		if (isNaN(parseInt(top))) return false;
		layer.style.left = left + 'px';//40
    	layer.style.top = top +'px';
	}
}

function bx(x,y,w,h)
{
	this.l=x;
	this.r=x+w;
	this.t=y;
	this.b=y+h;
}

function cBB(o)
{
	var b=new bx(0,0,0,0);
	if(!o) return b;
	var x=0,y=0,p=o;
	while(p)
		{
		x+=p.offsetLeft;
		y+=p.offsetTop;
		p=p.offsetParent;
		}
	b.l=x;
	b.t=y;
	b.r=x+o.offsetWidth;
	b.b=y+o.offsetHeight;
	return b;
}
 
function GetRelativePath(path) {
       var rel_path=path;
       var path_array=path.split("/");
       if (path_array[path_array.length-1].indexOf(".") != -1){
         rel_path=rel_path.replace(path_array[path_array.length-1],"")
       }
       return rel_path
    }
