﻿//TODO: add claims and Log4Js.Loggers
//---------------------------------------------------------------------------------
/**
 * Enhance system class: Function
 *  - is done here untill it will enter the infra client-tools.
 */
Function.prototype.getArgNamesArray = function(){
	try{
		return /function[^\(]*\(([^\)]*)\)/.exec(this.toString())[1].replace(/\s*/g,"").split(",");
	}catch(ex){
		return [];
	}
}
//---------------------------------------------------------------------------------

//---------------------------------------------------------------------------------
/**
 * Enhance system class: Array
 *  - is done here untill it will enter the infra client-tools.
 */

/**
 * @param {number} iStart
 * @param {number} iCount
 *
 * @type Array
 */
Array.prototype.cut = function(iStart, iCount)
{
	var iEnd = undefined;
	if(iStart==undefined) iStart = 0;
	iEnd = (iCount==undefined)? this.length : iStart + iCount;
	return this.slice(iStart, iEnd);
}
/**
 * @param {number} iPage
 * @param {number} iItemsInPage
 *
 * @type Array
 */
Array.prototype.page = function(iPage, iItemsInPage)
{
	return this.cut( iPage * iItemsInPage, iItemsInPage );
}
//---------------------------------------------------------------------------------

//=================================================================================

/**
 * @namespace GameCatalog
 *
 * Classes:
 * @see GameCatalog.Game
 * @see GameCatalog.Tag
 * 
 * API:
 * @see: GameCatalog.addGame
 * @see: GameCatalog.addTag
 * @see: GameCatalog.TagSkuLinks
 * @see: GameCatalog.SkuTagLinks
 */
if(window.GameCatalog == null) 
	GameCatalog = {};
	
	// Constants
GameCatalog.PRODUCT_CODE_VARNAME = "code";
GameCatalog.LANGUAGE_VARNAME = "lc";
GameCatalog.CHANNEL_VARNAME = "channel";
GameCatalog.BILLING_CNTRY_VARNAME = "BillingCountry";
GameCatalog.LOBBY_VARNAME = "lobby";

// Prperties
GameCatalog.language = "";
GameCatalog.channelCode = -1;
GameCatalog.baseBuyURL = "";
GameCatalog.baseGamePageURL = "";
GameCatalog.baseLobbyURL = "";
GameCatalog.billingCountry = "";


GameCatalog.millisPerDay = 24 * 60 * 60 * 1000;

//--- Class: GameCatalog.TagSkuLinks ---------------------------
//TBD: replace with Class.createArrayDecendent();
//	   currently, the Class.create() mechanizm does not allow inheritance from 
//	   system objects. It has to be done manually, by defining 
//	   constructor functions directly.
//		TBD is untill infra will overcome this
/**
 * @class GameCatalog.TagSkuLinks
 */
GameCatalog.TagSkuLinks = function()
{
	this.initialize();

	var e,a = new Array()
	for (e in this) a[e] = this[e];
	for (e = 0; e < arguments.length; e++)	a[e] = arguments[e];

	return a;
}
/**
 * @constructor
 */
GameCatalog.TagSkuLinks.prototype.initialize = function()
{
	this.dictionary = {}
}
/**
 * @param {number} iStart
 * @param {number} iCount
 * @param {boolean(optional)} isForceSort
 *
 * @type Array
 */
GameCatalog.TagSkuLinks.prototype.byWeight = function(iStart, iCount, isForceSort)
{ 
	if(!this._byWeight || isForceSort)
	{
		this._byWeight = this.concat().sort(	
											function(a,b)
											{
												return b.weight - a.weight;
											}
										  );
	}
	return this._byWeight.cut(iStart, iCount);
}
/**
 * @param {string} sSkuProp
 * @param {boolean(optional)} isDescSort
 * @param {number(optional)} iStart
 * @param {number(optional)} iCount
 * @param {boolean(optional)} isForceSort
 *
 * @type Array
 */
GameCatalog.TagSkuLinks.prototype.bySkuProperty = function(sSkuProp, isDescSort, iStart, iCount, isForceSort)
{
	if(!this["_sku_" + sSkuProp] || isForceSort){
	    var orderVar = -1;
	    if(isDescSort)
	        orderVar = 1;
		this["_sku_" + sSkuProp] = this.concat().sort(
										function(a,b){
											if (b.sku[sSkuProp] == a.sku[sSkuProp]) return 0;
											return (b.sku[sSkuProp] > a.sku[sSkuProp]) ? orderVar : ( orderVar*(-1) ) ;
										}
									 );
	}
	return this["_sku_" + sSkuProp].cut(iStart, iCount);
}
//--- End Class: GameCatalog.TagSkuLinks ---------------------------

//--- Class: GameCatalog.SkuTagLinks -------------------------------
//TBD: replace with Class.createArrayDecendent();
//	   currently, the Class.create() mechanizm does not allow inheritance from 
//	   system objects. It has to be done manually, by defining 
//	   constructor functions directly.
//		TBD is untill infra will overcome this
GameCatalog.SkuTagLinks = function()
{
	this.initialize();

	var e,a = new Array()
	for (e in this)a[e] = this[e];
	for (e = 0; e < arguments.length; e++)	a[e] = arguments[e];

	return a;
}
/**
 * @constructor
 */
GameCatalog.SkuTagLinks.prototype.initialize = GameCatalog.TagSkuLinks.prototype.initialize;
/**
 * @param {number} iStart
 * @param {number} iCount
 * @param {boolean(optional)} isForceSort
 *
 * @type Array
 */
GameCatalog.SkuTagLinks.prototype.byWeight = GameCatalog.TagSkuLinks.prototype.byWeight;
/**
 * @param {string} sTagProp
 * @param {boolean(optional)} isDescSort
 * @param {number(optional)} iStart
 * @param {number(optional)} iCount
 * @param {boolean(optional)} isForceSort
 *
 * @type Array
 */
GameCatalog.SkuTagLinks.prototype.byTagProperty = function(sTagProp, isDescSort, iStart, iCount, isForceSort)
{
	if(!this["_tag_" + sTagProp] || isForceSort){
	    //if(typeof(sTagProp) == 'object') arguments = arguments[0];
		var orderVar = -1;
	    if(isDescSort)
	        orderVar = 1;
		var arr = this.concat().sort(
										function(a,b){
											if (b.tag[sTagProp] == a.tag[sTagProp]) return 0;
											return (b.tag[sTagProp] > a.tag[sTagProp])? orderVar : ( orderVar*(-1) ) ;
										}
									 );
		this["_tag_" + sTagProp] = arr;
	}
	return this["_tag_" + sTagProp].cut(iStart, iCount);
}
//--- End Class: GameCatalog.SkuTagLinks ---------------------------



//---- Class: GameCatalog.Category ---------------------------------
/**
 * @class GameCatelog.Category
 */
GameCatalog.Category = Class.create();
/**
 * @constructor
 */
GameCatalog.Category.prototype.initialize = function(code,name,internalName,categoryURL)
{
	var params = this.initialize.getArgNamesArray();
	for(var i=0; i < params.length; i++)
		if(arguments[i] !== undefined) this[params[i]] = arguments[i];
	
	this.games = {};
	this.games.All = [];
	this.games.All.bySkuProperty = GameCatalog.Game.All.bySkuProperty
}
GameCatalog.Category.All = [];
GameCatalog.Category.All.byCategoryProperty = function(sPropName,iStart, iCount, isForceSort){
	if(!this[0] || undefined === this[0][sPropName] ) 
		return this;

	if(!this["_" + sPropName] || isForceSort )
	{
		this["_" + sPropName] = this.concat().sort(
													function(a,b)
													{
														if (a[sPropName] == b[sPropName]) return 0;
														return (a[sPropName] < b[sPropName])?-1:1;
													}
												  );
	}

	return this["_" + sPropName].cut(iStart, iCount);
}
GameCatalog.Category.ByCode = {};
//---- End Class: GameCatalog.Category ---------------------------

//---- Class: GameCatalog.Game -----------------------------------
/**
 * @class GameCatalog.Game
 */
GameCatalog.Game = Class.create();
/**
 * @static
 * All Games array
 * @type Array
 */
GameCatalog.Game.All = [];

/**
 * @param {string} sPropName
 * @param {number} iStart
 * @param {number} iCount
 * @param {boolean(optional)} isForceSort
 *
 * @type Array
 */
GameCatalog.Game.All.bySkuProperty = GameCatalog.Category.All.byCategoryProperty;
/**
 * @static
 * All Games dictionary by Sky
 * @type Object
 */
GameCatalog.Game.All.dictionary = {};
GameCatalog.Game.All.BySku = GameCatalog.Game.All.dictionary;
/**
 * @contstructor
 *
 * @param {number} sku
 * @param {string} name
 * @param {string} gamePageURL
 * @param {string} smallThumbnail
 * @param {string} categoryLocalizedName
 * @param {string} categoryCode
 * @param {boolean} isNew
 * @param {Date} publishDate
 * @param {string} lobbyURL
 */
GameCatalog.Game.prototype.initialize = function(sku, name, smallThumbnail, categoryCode, productCode, lobbyUID, isMultiPlayer, thumbnail16x16,  isNew, publishDate, thumbnail100x75, thumbnail179x135, thumbnail320x240, isLocalized, thumbnail130x75, downloadURL, oneThirdDesc, twoThirdsDesc, isOnline, isSupportingTokens, isEventSupporting, reportName )
{
	//support single array as a single parameter, or argument-list
	if(typeof(arguments[0]) == 'object') arguments = arguments[0];

	//init all data-properties declared in constructor
	var params = this.initialize.getArgNamesArray();
	for(var i=0; i < params.length; i++)
		if(arguments[i] !== undefined ) this[params[i]] = arguments[i];
	this['publishDate'] = new Date(this['publishDate'] * GameCatalog.millisPerDay); //'daysSince70'
	
	this['gamePageURL']=GameCatalog.Game.generateGamePageURL(this['productCode']);
	this['buyURL']=GameCatalog.Game.generateBuyURL(this['productCode']);
	this['lobbyURL']=GameCatalog.Game.generateLobbyURL(this['lobbyUID'], this['productCode']);
	this['categoryLocalizedName'] = GameCatalog.Category.ByCode[categoryCode].name
	
	
	
	//init tags collection
	this.tagLinks = new GameCatalog.SkuTagLinks();
}

/**
 * provides an array of most recent new games, sorted by the publish date in a descending order
 *
 * @param {number} count
 *
 * @type Array
 */
GameCatalog.Game.prototype.getRecentGames = function(count){
    var isNew = "isNew", pDate = "publishDate";
    var a = GameCatalog.Game.All.bySkuProperty(isNew).concat();
    var arr = [];
    for (var i = a.length-1; i >= 0; i--) {
        if(a[i].isNew == false)
            break;
        arr.push(a[i]);
    }
    arr = arr.sort  (   function(a,b)
						{
						    if (a[pDate] == b[pDate]) return 0;
							    return (a[pDate] > b[pDate])?-1:1;
						}
				    );
    return arr.cut(0, count);
}


/**
 * creates a link, adds it to the tags object, and returns it.
 */
GameCatalog.Game.addTag = function(oTag, dblWeight){
	if(this.tagLinks.dictionary[ oTag.internalName ])
		return this.tagLinks.dictionary[ oTag.internalName ];

	return this.addTagLink(	{ weight	: dblWeight
							, tag		: oTag 
							, sku		: this
							} 
						   );
}
/**
 * adds a tag to the tags object and returns it.
 */
GameCatalog.Game.prototype.addTagLink = function(oLink){
	if( !this.tagLinks.dictionary[ oLink.tag.internalName ] )
		this.tagLinks[ this.tagLinks.length ] =	
			this.tagLinks.dictionary[ oLink.tag.internalName ] = 
				oLink;

	if(!oLink.tag.skuLinks.dictionary[this.sku])
		oLink.tag.addSkuLink( oLink );

	return oLink;
}
//---- End Class: GameCatalog.Game  -----------------------------------



//---- Class: GameCatalog.Tag  ----------------------------------------
/**
 * @class GameCatalog.Tag
 */
GameCatalog.Tag = Class.create();

GameCatalog.Tag.keyProperty = "internalName";  //The key in the tags dictionary.
GameCatalog.Tag.propertyList = "name, count";  //default properties. May change with the server response.

/**
 * @constructor
 *
 * @param {string} internalName
 * @param {string} name
 * @param {number} count
 * @param {boolean} isFullyLoaded
 * @param {Date} publishDate
 */
GameCatalog.Tag.prototype.initialize = function(/*internalName, name, count, isFullyLoaded, publishDate*/)
{
	//support single array as a single parameter, or argument-list
	if(typeof(arguments[0]) == 'object') args = arguments[0];
	
	//init the 1st property (dictionary key)
	this[GameCatalog.Tag.keyProperty] = args[0];

	//init all data-properties declared in propertyList
	var prop = GameCatalog.Tag.propertyList.replace(/\s*/g,"").split(","); //this.initialize.getArgNamesArray();
	
	this.tagPageURL = GameCatalog.URLs.tagPageURL.replace(/TAG_INTERNAL_NAME/g, args[0]);
	
	for(var i=0 ; i < prop.length; i++)
		if(args[i+1] !== undefined)
		{
		    var val = args[i+1];
		    if(prop[i].indexOf('Date') != -1)    //'daysSince70'
		        val = new Date(val * GameCatalog.millisPerDay)
		    this[prop[i]] = val;
		}

	this.skuLinks = new GameCatalog.TagSkuLinks();
}
/**
 * adds the link to the skus array and dictionary collection.
 * the method keeps the array always sorted by weight
 */
GameCatalog.Tag.prototype.addSkuLink = function(oLink)
{
	if( !this.skuLinks.dictionary[ oLink.sku.sku ] )
		this.skuLinks.dictionary[ oLink.sku.sku ] = 
			this.skuLinks[	this.skuLinks.length ] = oLink;

	if(!oLink.sku.tagLinks.dictionary[this.internalName])
		oLink.sku.addTagLink( oLink );
}
/**
 * create a link between the tag and the sku by weight, 
 * and pefroms the linking using this.addSkuLink
 */
GameCatalog.Tag.prototype.addSku = function(sku, dblWeight){
	if(typeof(sku) == 'number') sku = GameCatalog.Game.All.dictionary[sku];
	if (!sku) return; //TODO: add Log4Js logging

	this.addSkuLink(	{	weight	:	dblWeight
						,	sku		:	sku
						,	tag		:	this
						}
					);
}
/**
 * adds skus with unlimited parameters array, 
 * while every 2 parameters is a sku and its link-weight.
 * @param {arguments} sku,weight pairs
 */
GameCatalog.Tag.prototype.addSkus = function(/*sku1,weight1, sku2,weight2, sku3,weight3, ... */)
{
	var i = 0;
	while( i < arguments.length){
		this.addSku(arguments[i++], arguments[i++]);
	}
}
/**
 * returns true when the Tag is loaded with all of its children
 * based on the children-count provided by the server, and the 
 * count of the initiated linkes on the client
 *
 * @type boolean
 */
GameCatalog.Tag.prototype.isFullyLoaded = function()
{
	return this.count == this.skuLinks.length;
}
/**
 * All Tags Array
 * @type Array
 */
GameCatalog.Tag.All = [];

/**
 * provides an array of all the tags on the client, sorted by the provided tag-property.
 *
 * @param {string} sProp
 * @param {boolean(optional)} isDescSort
 * @param {iStart(optional)} number
 * @param {iEnd(optional)} number
 * @param {boolean(optional)} isForceSort
 *
 * @type Array
 */
GameCatalog.Tag.All.byTagProperty = function(sProp, isDescSort, iStart, iCount, isForceSort)
{ 
	if(!this["_by_" + sProp] || isForceSort)
	{
	    var orderVar = -1;
	    if(isDescSort)
	        orderVar = 1;
		this["_by_" + sProp] = this.concat().sort(	
													function(a,b)
													{
														if((b[sProp] == a[sProp])) return 0;
														return (b[sProp] > a[sProp]) ? orderVar : ( orderVar*(-1) ) ;
													}
												  );
	}
	return this["_by_" + sProp].cut( iStart, iCount );
}
/**
 * All Tags collection by name
 * @type Object
 */
GameCatalog.Tag.All.dictionary = {}

//--- End Class: GameCatalog.Tag  -----------------------------------






GameCatalog.URLs =	{ gamePageURL: '/Deluxe.aspx?code=GAME_SKU&lc=en&channel=110167437'
					, gameImageBase: '/images/games/'
					, buyURL: 'http://Jeuxentelechargement-beta.jeu.orange.fr/Checkout.asp?code=CHECKOUT_SKU&channel=110167437&lc=fr&BillingCountry=FR'
					, lobbyURL: '/Lobby.aspx?lobby=LOBBY_ID&channel=110167437&lc=en'
					, categoryURL: '/Category.aspx?code=CATEGORY_CODE'
					, tagPageURL : '/Tag.aspx?tag=TAG_INTERNAL_NAME&ln=en'
					};

/**
 * @param {numbner} code
 * @param {string} name
 * @param {string} internalName
 *
 * @type GameCatalog.Category
 */
GameCatalog.addCategory = function(code,name,internalName)
{
	var categoryURL = GameCatalog.URLs.categoryURL.replace(/CATEGORY_CODE/g, code);
	var category = new GameCatalog.Category( code, name, internalName, categoryURL);
	
	GameCatalog.Category.ByCode[ code ] = 
		GameCatalog.Category.All[ GameCatalog.Category.All.length ] = 
			category;
	return category;
}
GameCatalog.addGame = function(sku, name, smallThumbnail, categoryCode, productCode, lobbyUID, isMultiPlayer, thumbnail16x16, isNew, publishDate, thumbnail100x75, thumbnail179x135, thumbnail320x240, isLocalized, thumbnail130x75,  downloadURL, oneThirdDesc, twoThirdsDesc, isOnline, isSupportingTokens, isEventSupporting, reportName )

{
	var newGame = new GameCatalog.Game(sku, name, smallThumbnail, categoryCode, productCode, lobbyUID, isMultiPlayer, thumbnail16x16, isNew, publishDate, thumbnail100x75, thumbnail179x135, thumbnail320x240, isLocalized, thumbnail130x75,  downloadURL, oneThirdDesc, twoThirdsDesc, isOnline, isSupportingTokens, isEventSupporting, reportName )
	
    GameCatalog.Game.All[GameCatalog.Game.All.length] = newGame;
	GameCatalog.Game.All.BySku[newGame.sku] = newGame;
    
    return newGame;
}

/**
 * @param {string} internalName
 * @param {string} same
 * @param {string} images
 * @param {string} shortDesc
 * @param {string} desc
 *
 * @type GameCatalog.Tag
 */
GameCatalog.addTag = function(/*internalName,...*/){
    
	var tag = this.Tag.All.dictionary[arguments[0]];
	if (  tag )  return tag;

	var newTag = new this.Tag(arguments/*internalName,... */);
    

	this.Tag.All[this.Tag.All.length] = newTag;
	this.Tag.All.dictionary[arguments[0]] = newTag; //arguments[0] is the key in the dictionary (tag's internalName)

	return newTag;
	
}
// Supposedly a static function which generates the GamePage URL
// params:  
//          --productCode : The product code
GameCatalog.Game.generateGamePageURL = function(productCode)
{
    var gamePageURLBuilder = new Array();
    gamePageURLBuilder = gamePageURLBuilder.concat(GameCatalog.baseGamePageURL, "?", 
    GameCatalog.PRODUCT_CODE_VARNAME, "=", productCode, "&", 
    GameCatalog.LANGUAGE_VARNAME, "=", GameCatalog.language, "&", 
    GameCatalog.CHANNEL_VARNAME, "=", GameCatalog.channelCode);
    
    return gamePageURLBuilder.join("");
}

// Supposedly a static function which generates the Checkout Page URL
// params:  
//          --productCode   : The product code
GameCatalog.Game.generateBuyURL = function(productCode)
{
    var buyURLBuilder = new Array();
    buyURLBuilder = buyURLBuilder.concat(GameCatalog.baseBuyURL, "?", 
            GameCatalog.PRODUCT_CODE_VARNAME, "=", productCode, "&", 
            GameCatalog.CHANNEL_VARNAME, "=", GameCatalog.channelCode, "&", 
            GameCatalog.LANGUAGE_VARNAME, "=", GameCatalog.language, "&", 
            GameCatalog.BILLING_CNTRY_VARNAME, "=", GameCatalog.billingCountry);
            
    return buyURLBuilder.join("");
}

// Supposedly a static function which generates the lobby URL
// params:  
//          --lobbyUID    : The product code
GameCatalog.Game.generateLobbyURL = function(lobbyUID, productCode)
{
    if (lobbyUID != "")
    {
        var lobbyURLBuilder = new Array();
        lobbyURLBuilder = lobbyURLBuilder.concat(GameCatalog.baseLobbyURL, "?", 
                GameCatalog.LOBBY_VARNAME, "=", lobbyUID, "&", 
                GameCatalog.PRODUCT_CODE_VARNAME, "=", productCode, "&",
                GameCatalog.CHANNEL_VARNAME, "=", GameCatalog.channelCode, "&", 
                GameCatalog.LANGUAGE_VARNAME, "=", GameCatalog.language);
            
        return lobbyURLBuilder.join("");
    }
    
    return "";
}
