/* === TMP FIXES ON PRODUCT UTILS === */
//-=-=-=-=-=- Enhances on Object -=-=-=-=-=-
Object.clone = function(obj)
{
	return this.extend( {} , obj);
}
/**
 * @param {variant} value
 * @returns pseodo-JSON serialization of the variant
 * @type string
 */
Object.serialize = function(value)
{	
	var arrObjs = [];
	// ser is defined here so it could see arrObjs, 
	// and make sure there is no endless recursion, 
	// or objects that are serialized twice in a same tree
	function ser(v){
		switch(typeof(v))
		{
			case 'NaN'		:	return "NaN";
			case 'undefined':	return "undefined";
			case 'boolean'	:	return (v).toString();
			case 'number'	:	return (isFinite(v))? (v).toString() : "\"Infinity\"" ;
			case 'string'	:	return "\"" + v.replace(/\"/g ,"\\\"") + "\"";
			case 'function'	:	return "{function}";
		}
		// handle objects
		if(v == null)			return "null";
		if(v instanceof Date)	return "new Date(" + v.getTime() + ")"; 
		if(v instanceof Array)
		{
			var i, arr = [];

			if (  GameCatalog.TagSkuLinks 
			   && v.byWeight == GameCatalog.TagSkuLinks.prototype.byWeight 
 			   )
			  return "[GameCatalog.TagSkuLinks,length: " + v.length + "]";

			if (  GameCatalog.SkuTagLinks
			   && v.byWeight == GameCatalog.SkuTagLinks.prototype.byWeight )
			  return "[GameCatalog.SkuTagLinks,length: " + v.length + "]";
			
			for(i = 0; i < v.length; i++)
				arr[arr.length] = ser(v[i]);
				
			return "[" + arr.toString() + "]";
		}
		
		//serialize an unknown object
		// - prevent recursive serialization
		if ( arrObjs.indexOf(v) != -1 )
		{
			return "\"*ref" + (  (v.id)? "-id:" + v.id : (  (v.name) ? "-name:" + v.name : ":" + v.toString()  )   ) + "\"";
		}
		arrObjs[arrObjs.length] = v;


		//handle html-dom-nodes
		if( v.parentNode && v.attributes && (v.children || v.childNodes) && v.tagName)
		{
			var i, e =  { tagName	: v.tagName
						, parent	: v.parentNode.tagName 
						, innerHTML : "\"" + v.innerHTML.replace(/"/g,"\\\"").replace(/</g, "&lt;") + "\""
						}; 
			for(i = 0; i < v.attributes.length; i++)
				if(v.attributes[i].value && v.attributes[i].value != "null")
					e[v.attributes[i].name] = v.attributes[i].value;
					
			return ser(e);
		}

		// - do the serializing...
		var each, arr  = [];
		// Note: the for-each could throw for activeX objects and such
		try
		{
			for(each in v)
			{
				if(null !== v[each])
					arr[arr.length] = each + ":" + ser(v[each]);
			}
			return "{" + arr.toString() + "}";
			
		}catch(ex){
			return "\"-error in serializing: " + ex.message + "-\""
		}
	}

	return ser(value);
}

/**
 * copies properties to destination from source only when they are totally undefined on the destination.
 *
 * @param {object} destination
 *
 * @param {object} source
 */
Object.safeExtend = function(destination, source) {
  for (property in source) {
	if(undefined === destination[property])
		destination[property] = source[property];
  }
  return destination;
}

//-=-=-=-=-=- /Enhances on Object -=-=-=-=-=-
//-=-=-=-=-=- Enhances on Class -=-=-=-=-=-
/**
 * Creates a constructor function.
 * When provided a parent - it createa a subclass of the provided parent,
 * or throws an error.
 * 
 * @param {string|function(optional)} parent
 *  The parent class name in string, or a reference to the parent class constructor
 */
// - fix: allow it to accept (parent) and link inheritance.
Class.create = function(parent)
{
    var fConstr = function()
    {
		var arrCtors = [];
		var fConstructor = this.constructor;
		do
		{
			//fConstructor could be a system class that doesn't implement initialize
			if('function' == typeof(fConstructor.prototype.initialize))
				arrCtors[arrCtors.length] = fConstructor.prototype.initialize;
			fConstructor = fConstructor.parentConstructor;
		}
		while(typeof(fConstructor) == 'function');

		for(var i = arrCtors.length; i-- > 0; ) 
		{
			arrCtors[i].apply(this, arguments);
		}
    }

	if(parent)
	{ 
		return Class.linkInheritance(parent, fConstr);
	}

	return fConstr;
}
/**
 * @param {function|object|string} parent
 *  A parent class, an instance of it, or a string representing its class name
 *
 * @param {function} subclass
 *  The subclass function
 */
// - new.
Class.linkInheritance = function(parent, subclass){
	if(typeof(parent)=='string')
		parent = eval(parent);
	Claim.check(	typeof(parent) == 'object' 
			   ||	typeof(parent) == 'function'
			   , "'parent' is a function or an object"
			   , "Class.linkInheritance(parent)")
	Claim.isFunction(subclass,"Class.linkInheritance(subclass)");

    //copy all static members
    subclass = Object.extend( subclass , parent );
	delete subclass.AsPrototype;

	//keep the parent constructor in parentConstructor
	subclass.parentConstructor = parent;

	//--THROWS FRIENDLY ERRORS WHEN MISUSED--
    subclass.prototype = Class.AsPrototype(parent);

	//override the 'constructor' attribute on the new prototype instance 
    //(originally it was the parent constructor)
    subclass.prototype.constructor = subclass ;

    return subclass;
}
/**
 * Mostly for internal use, but can be used to determine wether a class is inheritable.
 * When the provided parameter is not inheritable - it throws an error.
 *
 * @param {string|function|object} fClass
 *  A string evaluates to a class or a the class itselfs
 *
 * Function:
 *  if
 *		can be instantiated using a default constructor
 * 			OR
 * 		parent.AsPrototype() returns a valid instance
 * 			OR
 * 		parent === Object
 *	  creates an instance, and puts initialize_base on it.
 *
 * String:
 *  if	
 *		evaluates to a valid class name
 * 	carrSuperclasss recursively on evaluation's returned value
 *
 * Object: 
 *  creates a shellow copy, and puts initialize_base on it.
 */
// - new.
Class.AsPrototype = function(fClass){
	switch(typeof(fClass)){
		case 'string':
			if (  window[fClass] != null
			   && window[fClass] === eval(fClass) )
			{
				if( typeof(eval(fClass)) != 'function') throw new Error("'" + fClass + "' does not evaluates to a valid class");
				return Class.AsPrototype(eval(fClass));
			}
		case 'function':
			var oProto;
			if (fClass === Object) return {};

			if	(typeof(fClass.AsPrototype) == 'function')
			{
				oProto = fClass.AsPrototype();
				if (typeof(oProto) != 'object') throw new Error("provided class implements.AsPrototype() but it did not return an instance.");
			}
			else
			{
				try{
					oProto = new fClass();
				}
				catch(ex)
				{
					throw new Error("Class.AsPrototype(fClass) Failed to instantiate 'fClass' with default constructor. \n\nError message: " + ex.message );
				}
			}
			return oProto;

		case 'object':
			return Object.extend({}, fClass);

		default:
			throw new Error("A prototype can be extracted only from one of the followings: \n\t- an object instance \n\t- a valid constractor function \n\t- a string evaluates to ither one of the above");
	}
}

/**
 *
 */
Class.enhancePrototype = function(fClass, oInterface)
{
	Claim.check( typeof(fClass) == 'function' 
				, "Class.enhancePrototype(fClass,oInterface) - fClass"
				, "fClass must be a function"
				);
	Claim.check( oInterface && typeof(oInterface) == 'object'
				, "Class.enhancePrototype(fClass,oInterface) - oInterface"
				, "oInterface must be an object"
				);
				
	return Object.extend( fClass.prototype, oInterface );
}

/**
 *
 */
Class.enhanceSingleton = function(oSingleton, oInterface)
{
	Claim.check( oTargetClass && typeof(oTargetClass) == 'object' || typeof(oTargetClass) == 'function'
				, "Class.enhance(oSingleton)"
				, "oTargetClass must be a function"
				);
	Claim.check( oInterface && typeof(oInterface) == 'object'
				, "Class.enhancePrototype(fClass,oInterface) - oInterface"
				, "oInterface must be an object"
				);
				
	return Object.extend( oSingleton, oInterface );
}
Class.enhance = function(fClass /*, param1, param2, param3 ... */)
{
	var oInterface;
	for(var i = 1; i < arguments.length ; i++)
	{
		oInterface = arguments[i];
		try { fClass = this.enhanceSingleton(fClass, oInterface); } catch(ex) {}
		try { fClass.prototype = this.enhancePrototype(fClass, oInterface); } catch(ex) {}
	}
	return fClass;
}
//-=-=-=-=-=- /Enhances on Class -=-=-=-=-=-
//-=-=-=-=-=- Enhances on Element -=-=-=-=-=-
/**
 * sets the text of the provided element, according to its tag-name
 * input fields, text-area  - by .value
 * the rest - innerHMTL
 *
 * @param {Element} e - the DOM element ID
 * @param {string}	sText
 */
Element.setText = function(e,sText)
{
	var tag = e.tagName.toUpperCase();
	switch(tag)
	{
		case "INPUT":
		case "TEXTAREA":
			e.value = sText;
			break;
		case "SELECT":
			//TODO: - decide what to do if the sText doesnt match any value of the select element
			e.value = sText;
			break;
		default:/*DIV, SPAN, TD, A, H1-H5, and all the rest*/
			try{
				e.innerHTML = sText;
			}catch(ex){
				try{
					if(typeof e.innerText == 'undefined')
						e.textContent = sText;
					else
						e.innerText = sText;
				}catch(ex){
					this.log.error("Element.setText: failed to set to element the text: " + sText);
				}
			}
	}
}
/**
 * gets the text of the provided element, according to its tag-name
 * input fields, text-area  - by .value
 * the rest - innerHMTL
 *
 * @param {Element} oElement - the DOM element ID
 */
Element.getText = function(oElement)
{
	switch(oElement.tagName)
	{
		case "INPUT":
			if(oElement.type == "checkbox")
				return (oElement.checked)? oElement.value : "";
			//no break! deliberated case sliding!
		case "TEXTAREA":
		case "SELECT":
			strTemplate = oElement.value;
			break;
		default:/*DIV,SPAN,H1-6,TD,CETNER,B,I,U,and all the rest*/
			strTemplate = oElement.innerHTML;
	}
}
//-=-=-=-=-=- /Enhances on Element -=-=-=-=-=-
//-=-=-=-=-=- Enhances on Log4Js -=-=-=-=-=-
/**
 * Initiates a general cookie.
 * To be pasted in the address bar like this:
 *    Javascript:Log4Js.pop();
 *
 * @param {object(optional)} conf 
 * The configuration object. When not provided - initiates a default one for popup.
 */
// - new.
Log4Js.pop = function(conf){
    if(!conf || typeof(conf) != 'object')
	{
		conf =  { anchorsByName:  { "*"  : ["t1"]
                                  , Claim: ["t2"]
                                  }
                , targetByAnchor: { t1: new Log4Js.PopupTarget(Log4Js.ALL  ,"log4js-%U-%T",true)
                                  , t2: new Log4Js.PopupTarget(Log4Js.FATAL,"log4js-%U-%T",true)
                                  }
                };
    }
    Cookies.set("log4js.config", conf, {});
    this.fromConfig(conf);
}
/**
 * Adds a logging anchor by name
 *
 * @param {string} sClassName
 * The name of the logged element
 * 
 * @param {string} enLEVEL
 * The "enum" name of the warn level
 */
// - new.
Log4Js.add = function(sClassName, enLEVEL){
	Claim.isString(sClassName, "Log4Js.add(sClassName, enLEVEL) - sClassName must be a string");
	Claim.isString(enLEVEL, "Log4Js.add(sClassName, enLEVEL) - enLEVEL must Log Level ALL, DEBUG, WARN, ...");
	var iLevel = this[enLEVEL.toUpperCase()];
	Claim.isNumber(iLevel, "Log4Js.add(sClassName, enLEVEL) - Log4Js." + enLEVEL + " is not a valid warn-level");
	Claim.check(iLevel >= 0 && iLevel <=6, "0 <= iLevel <= 6", "Log4Js.add(sClassName, enLEVEL) - Log4Js[enLEVEL must be between 0 to 6");
	
	var conf = this.toConfig();
	conf.targetByAnchor.newAnchor = new Log4Js.PopupTarget(iLevel ,"log4js-%U-%T",true)
	conf.anchorsByName[sClassName] = ["newAnchor"];
	this.pop(conf);
}
/**
 * Removes an anchor by name
 *
 * @param {string} sClassName
 * The name of the logged element
 */
// - new.
Log4Js.clear = function(sClassName){
	Claim.isString(sClassName, "Log4Js.clear(sClassName) - sClassName must be a string");
	var conf = this.toConfig();
	delete conf.anchorsByName[sClassName];
	this.pop(conf);
}
/**
 * stops the logging by clearing the log4js configuration.
 * Done by setting the configuration to a single anchor - all, pointed to NONE.
 *
 */
// - new.
Log4Js.stop = function(){
    var conf =  { anchorsByName:  { "*"  : ["t1"]
                                  }
                , targetByAnchor: { t1: new Log4Js.PopupTarget(Log4Js.NONE  ,"log4js-%U-%T",true)
                                  }
                };
    Cookies.set("log4js.config", conf, {});
    this.fromConfig(conf);
}
//-=-=-=-=-=- /Enhances on Log4Js -=-=-=-=-=-
//-=-=-=-=-=- Enhances on Claim -=-=-=-=-=-
/**
 * Claims the provided object to be a function
 * Throws an error if its not
 *
 * @param {object} object
 * The tested object
 *
 * @param {string} comment
 * String comment for the Error and for the log
 */
 // - new.
Claim.isFunction = function(object, comment)
{{
    Claim.check(typeof(object) == 'function'
               ,"isFunction(" + Claim.valueType(object) + ")"
               ,comment)
}}
Claim.isLiveObject = function(object, comment)
{
	Claim.check(	null != object 
				&&	typeof(object) == 'object'
				, "isLiveObject(" + object + ")"
				, comment)
}
//-=-=-=-=-=- /Enhances on Claim -=-=-=-=-=-
//-=-=-=-=-=- Enhances on Cookies -=-=-=-=-=-
Cookies.pop = function(){
	var each, s = [];
	for(each in this.rawByName){
		s[s.length] = each 
		s[s.length] = ":"
		s[s.length] = this.rawByName[each]
		s[s.length] = "\n"
	}
	alert(unescape(s.join("")));
}
//-=-=-=-=-=- /Enhances on Cookies -=-=-=-=-=-
/* === /TMP FIXES ON PRODUCT UTILS === */

// --- Enhance String.prototype -----------------------------------
/**
 * An empty string constant
 */
String.empty = String.Empty = "";
/**
 * Populates a template: replaces all provided place-holders in a string, with values.
 *
 * @param {object} oMapping
 * A hash in which every key represents a place-holder in the string to be replaced with its correlating value
 */
String.prototype.populateTemplate = function(oMapping)
{
	Claim.isObject(oMapping, "String.populateTemplate(..,oMapping,..)");

	var sTemplate, placehoder, replacement;

	sTemplate = String(this);

	for(placeholder in oMapping)
	{
		replacement = oMapping[placeholder];
		sTemplate = sTemplate.replace(new RegExp(placeholder,"g"), replacement);
	}
	return sTemplate;
}
String.prototype.beutifySerialization = function()
{
	var out = []
	  , indent = ""
	  , i
	  , arr = this.split("");
	  
	for(i = 0; i < arr.length; i++){
		switch(arr[i]){
			case "{":
				indent += "\t";
				out[out.length] = "\n" + indent;
				out[out.length] = arr[i] + "\t";
				break;
			case "}":
				out[out.length] = "\n" + indent;
				out[out.length] = arr[i] + "\t";
				indent = indent.substr(1);
				break;
			case "[":
				indent += "\t";
				out[out.length] = "\n" + indent;
				out[out.length] = arr[i] + "\t";
				break;
			case "]":
				out[out.length] = "\n" + indent;
				out[out.length] = arr[i] + "\t";
				indent = indent.substr(1);
				break;
			case ",":
				out[out.length] = "\n" + indent;
				out[out.length] = arr[i] + "\t";
				break;
			default:
				out[out.length] = arr[i];
		}
	}	
	return out.join("");	
}
/**
 * Binds a template: replaces all indicated placeholders with data. 
 * Data comes from data-properties on the oDataSource, 
 * and the mapping between placeholders in the string and the data-properties 
 * is provided in the oMapping parameter.
 *
 * @param {object} oMapping
 * A hash, in which every key is a placeholder in the string, 
 * and its correlating value can be:
 * - A string representing a data-property on the data-srource in oDataSource
 * - A function that returns value as a function of the oDataSource
 * - Any other value will be casted to string to return the value, and the returned value will be used, regardles to the data-source.
 *
 * @param {object} oDataSource
 * A data-object by which to bind the template
 *
 * @param {object(optional)} oLog
 * When provided - the logging of this execution is emitted to the provided instance.
 * Otherwise - to a casual instance, named "String.bindTemplate".
 */
String.prototype.bindTemplate = function(oMapping, oData, oLog)
{
	Claim.isObject(oMapping, "String.bindTemplate(..,oMapping,..)");
	Claim.isObject(oData , "String.bindTemplate(..,oData)");

	var oDataSource = ('object' == typeof(oData.dataItem))? oData.dataItem : oData;

	var sTemplate, placehoder, attribute, replacment;
	var log = (oLog && oLog instanceof Log4Js.Logger)? oLog : new Log4Js.Logger("String.bindTemplate");
	
	sTemplate = this.toString();
	
	for(placehoder in oMapping)
	{
		if( this.indexOf(placehoder) == -1){
			log.debug("in bindTemplate(...) - placeholder '" + placehoder + "' is not found in bound template");
			continue;
		}

		attribute = oMapping[placehoder];
		if(undefined == attribute || null == attribute){
			log.warn("in bindTemplate(...) oMapping dictionary specifies a placeholder without providing its data-attribute name: " + placehoder);
			continue;
		}
		
		switch(typeof(attribute))
		{
			case 'function':
				try
				{
					replacement = attribute(oDataSource, log);
				}catch(ex){
					log.error("String.bindTemplate - Error in mapping-handler for " + placehoder + " : " + attribute.toString() );
					throw ex;
				}
				break;
				
			case 'string':
				replacement = oDataSource[attribute];
				if('function' == typeof(replacement))
				{
					replacement = replacement.apply(oDataSource);
				}
				else if(null == replacement)
				{
					if(oData != oDataSource && null != oData[attribute])
					{
						replacement = oData[attribute];	
						if('function' == typeof(replacement))
						{
							replacement = replacement.apply(oData)
						}
						
					}
					
					if(null == replacement)
					{
					log.warn("in bindTemplate(...) oMapping dictionary specifies a property that does not exist on the provided oDataSource. Placehoder: " + placehoder +", using the name of the attribute: " + attribute);
					replacement = attribute;
				}

				}
				break;
			
			default:
				replacement = String(attribute);
			
		}
		
		//replacment = replacment.replace(/\$/g,"");
		sTemplate = sTemplate.replace(new RegExp(placehoder,"g"), replacement);
	}
	return sTemplate;
}
/**
 * returns the string without spaces in the start or at the end.
 */
String.prototype.trim = function(){
	var iStart = -1, iEnd = this.length;
	while (this.charAt(++iStart) == ' ');
	while (this.charAt(--iEnd) == ' ');
	if (iStart == iEnd && this.charAt(iStart) != ' ' ) return this.substr(iStart,1);
	return this.substring(iStart, iEnd + 1);
}

/**
 * returns the current string padded on the left with the provided padding char to the specified length
 * @param {string} c - the padding char
 * @param {number} iLength - the length the padded string should reach
 */
String.prototype.leftPad = function(c,iLength)
{
	s = this.toString();
	while(s.length < iLength) s = c + s;
	return s;
}
/**
 * @param {String} substr The string to search
 */
String.prototype.contains = function(substr)
{
	if(substr === undefined || substr === null) return false;
	return this.indexOf(substr) != -1;
}
// --- /Enhance String.prototype -----------------------------------

// --- Enhance Number.prototype -----------------------------------
//TODO: handle formatting of decimals. (0.34874873)
/**
 * returns the formatted string swith comas.
 **/
Number.milleSeperator = ",";
//Number.fragmentsSeperator = ".";
Number.prototype.format = function()
{
	var iNumber = this;
    var sFormatted = "", psik = ""; 
    var s3Digits, i3Digits;
    while (iNumber > 0)
    {
        i3Digits = iNumber % 1000;

		s3Digits = String(i3Digits)

		iNumber = Math.floor(iNumber / 1000);
		if (iNumber > 0) 
		{		
			if(i3Digits < 100) 
			{
				s3Digits = "0" + s3Digits;
				if(i3Digits < 10) 
				{
					s3Digits = "0" + s3Digits;
				}
			}
		}
        
        sFormatted = s3Digits + psik + sFormatted;
        psik = Number.milleSeperator;

    }
    
    return (sFormatted.length)? sFormatted: "0";    
}

/**
 * returns the current number padded on the left with the provided padding char to the specified length
 * @param {string} c - the padding char
 * @param {number} iLength - the length the padded string should reach
 * @param {number} iBase - the count base to format by it to string 
 */
Number.prototype.leftPad = function(c, iLength, iBase)
{
	if(iBase === undefined) return this.toString().leftPad(c,iLength);
	
	iBase == parseInt(iBase);
	if(!iBase || iBase == NaN || iBase < 2) iBase == 10;
	
	return this.toString( iBase ).leftPad(c,iLength);
}
// --- /Enhance Number.prototype -----------------------------------

// --- Enhance Array.prototype------------------------------------------------------------
/**
 * gets a part of the array of a maximum size.<br>
 * <a target="_blank" href="/Js/units/reference/_Infra/Array.htm#cut">see Ref-Impl</a>
 * @returns a slice of the array, starting in the provided iStart, and of maximum iCount elements.
 *
 * @param {number} iStart    index to start from 
 * @param {number} iCount    maximum elements to fetch
 * 
 * @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);
}
// --- /Enhance Array.prototype------------------------------------------------------------

if(!window.Const) Const = {};
Object.extend(	Const,	
				{	UNSET_STRING: "-UNSET-STRING-"
				,	UNSET_NUMBER: NaN	
				,	UNSET_OBJECT: undefined 
				}
			 );



/* === TC Namesapce ============================================================ */
if(!window["TC"])
	window.TC = {};

/**
 * Synonym for accessing the catalog by-sky hash
 */
TC.SKUs = GameCatalog.Game.All.BySku;

/**
 * Synonym for accessing the catalog all-games-on-client array
 */
TC.SKUs.All = GameCatalog.Game.All;


/**
 * Expects a data-object, with a property named "sku".
 * If such sku exists in the catalog - it copies all game properties 
 * from the catalog game instance to the provided object.
 *
 * @param {object} oTarget
 * The data-object to extend
 *
 * @param {number(optional)} sku
 * When no property "sku" defined on parameter oTarget - used as the sku to search by 
 *
 * @returns the enhanced object, or null when the sku does not exist in the catalog
 */
TC.SKUs.extendDataFromSKU = function(oTarget, sku)
{
	if(oTarget.sku) sku = oTarget.sku;
	Claim.isNumber(parseInt(sku), 'TC.SKUs.extendDataFromSKU(...) - the sku of the game to enhance from should be provided ither as a property "sku" on the provided oTarget, or as a second parameter');
	
	var oGame = this[sku];
	if ( !oGame )
		return null;

	return Object.extend( oTarget, oGame );
}	



/**
 * Synonym for accessing the catalog tags by internal-name hash
 */
if( GameCatalog.Tag ) TC.Tags = GameCatalog.Tag.All;



// --- TC.OnlinePlayers -----------------------------------
/**
 *
 */
TC.OnlinePlayers = {}
/**
 *
 */
TC.OnlinePlayers.log = new Log4Js.Logger("TC.OnlinePlayers");
/*
* Defaults settings of the behavious of this component. For customization override
* the required property in the projectal phase
*/	
TC.OnlinePlayers.settings = { onlinePlayersUnavailable: "N/A"
							};
/**
 *
 */
TC.OnlinePlayers.writeCommunity = function()
{
	this.prv_writeOnlineNumber(PresenceCatalog);
}
/**
 *
 */
TC.OnlinePlayers.writeByCategory = function(categoryCode){
	var oByCat;
	try
	{
		oByCat = PresenceCatalog.Rooms.All.ByCategory[categoryCode];
	}
	catch(ex)
	{
		this.log.error("Exception in access to PresenceCatalog.Rooms.All.ByCategory[" + categoryCode + "]: " + ex.message);
	}
	this.prv_writeOnlineNumber(oByCat);
	
}
/**
 *
 */
TC.OnlinePlayers.writeBySku = function(skuCode)
{
	var oBySku;
	try
	{
		oBySku = PresenceCatalog.Lobbies.All.BySku[skuCode];
	}
	catch(ex)
	{
		this.log.error("Exception in access to PresenceCatalog.Lobbies.All.BySku[" + skuCode +" ]: " + ex.message);
	}

	this.prv_writeOnlineNumber(oBySku);
	
}
/**
 *
 */
TC.OnlinePlayers.prv_writeOnlineNumber = function(oDataObject)
{
	var sOut = this.settings.onlinePlayersUnavailable
	if(oDataObject && null != oDataObject.NumberOfPlayers)
	{
		sOut = oDataObject.NumberOfPlayers;
		this.log.info("Number Of ActivePlayers: " + sOut);
	}
	else
	{
		this.log.info("Number Of ActivePlayers not found. oDataObject:"  + Object.serialize(oDataObject) );
	}
	
	document.write(sOut);
}
TC.OnlinePlayers.writeByRoom = function(roomGuid)
{{
	var oByRoom;
	try
	{
		oByRoom = PresenceCatalog.Rooms.All.ByRoom[roomGuid];
	}
	catch(ex)
	{
		this.log.error("Exception in access to PresenceCatalog.Rooms.All.ByRoom[" + roomGuid + "]: " + ex.message);
	}
	this.prv_writeOnlineNumber(oByRoom);
}}
//----------------------------------------------------------------------------
TC.Omniture = {}
TC.Omniture.trackRemoteUrl = Const.UNSET_STRING;
//----------------------------------------------------------------------------


/**
 * @requires Class => from prototype
 * @requires Log4Net.Logger => from common
 * @requires Object.serialize => currenly a projectile cross-project enhancement (attached).
 * @interface
 * Interface-implementation to enhance classes with event dispathching mechanism.
 * The mechanism allows a single handler that returns a value, or an event stack.
 * The mechanism has an error capturing mechanism that directs them to log.
 *
 * @CodeSampleStart
 * //Usage:
 * MyEventingClass = Class.create();
 * MyEventingClass.prototype = Object.extend(MyEventingClass.prototype, IEventDispatcher);
 *
 * MyEventingClass.doSomethingThreeTimes = function(i)
 * {
 *	   i = (i)?i:0;
 
 *     this.dispatch("onSomething",i);
 *     this.dispatch("onSomething",i + 1, i);
 *     this.r = this.dispatch("onSomething",i + 2, i + 1, i);
 *	   this.dispatch("onFinish", this.r);
 * }
 * //example 1:
 * obj = new MyEventingClass();
 * obj.onSomething = function(){
 *	  alert(arguments.toString());
 *    return arguments[2];
 * }
 * obj.onFinish = function(result){
 *    if(0 == result % 2 )
 *		this.r += 1;
 *
 *	  alert("finishing with : "  + this.r);
 * }
 * obj.doSomethingThreeTimes( 23 );
 *
 * //example 2:
 * obj = new MyEventingClass();
 * obj.attachEvent("onSomething", function(){ alert("handler 1: " + arguments.toString());} );
 * obj.attachEvent("onSomething", function(){ alert("handler 2: " + arguments.toString());} );
 *
 * obj.doSomethingThreeTimes( 23 );
 * @CodeSampleEnd
 */

IEventDispatcher = {};

/**
 * Accept the event name as the first parameter, and dispatches it with the rest of the arguments stack.
 * Check for a registered event handler. 
 * A handler could be a simple handler, or a handlers-stack.
 * When the event has a single handler – it can return value.
 *
 * Execution flow:
 * When no event handler is found - nothing is done, and null is returned.
 * When event handler is found -
 * 1 - convert all arguments without the event name to a new array
 * 2 - execute the handler with all the arguments on the new array
 * 3 - when an event returns a value - it returns it.
 *
 * Throws: when the execution of the handler throws, what the handler thew.
 *
 * When the dispatched object features a Log4Js.Logger, 
 * the following log entries are written on the objects logger:
 *   - [info] no event handler is found
 *	 - [info] success of the dispathed event, 
 *	 - [error] error on execution of the event handler, 
 *
 * TODO: allow the event be not only a hanler but a handlers array too
 *
 * @param {string} sEventName
 * The name of the hadler-reference property
 *
 * @param {*} arguments[1],arguments[2],arguments[3]...
 * The arguments for the event handler
 */
IEventDispatcher.dispatch = function(sEventName/*, param1, param2, param3 ... */)
{
	Claim.isString(sEventName, "IEventDispatcher.dispatch(sEventName, ...) - sEventName must be a string"  );
	
	//check for a registered event handler
	var fEventHandler  = this[sEventName];
	var isHandlerStack =	'object' == typeof( fEventHandler ) 
						&&	fEventHandler.constructor == Array;
	
	
	if	(  'function' != typeof( fEventHandler ) && !isHandlerStack )
	{
		if(this.log instanceof Log4Js.Logger) this.log.info("Dispatch: Event " + sEventName + " is not implemented.");
		return;
	}

	//when event handler is found - convert all arguments without the event name to a new array
	var args = [];
	for(var i=1; i < arguments.length; i++) 
	{
		args[i-1] = arguments[i];
	}

	// if the found handler is an event-stack - dispatch all of them, and there is no returned value.		
	if ( isHandlerStack )
	{
		this.log.info("detected handlers stack for event: " + sEventName);
		for(var i = 0; i < fEventHandler.length; i++)
		{
			this.dispatchHandler(sEventName, fEventHandler[i], args);			
		}
		return;
	}

	// if the found handler is a single function-reference - dispatch it, and there is no returned value.
	return this.dispatchHandler(sEventName, fEventHandler, args);			
}
/**
 * @private
 * applies the provided handler on the current instance, with the provided argument-stack
 * Errors and exceptions buble up, however, before that, if the current instance has a this.log as Log4Js.Logger - they are written to that log.
 *
 * @param {function} fEventHandler
 * The function-reference to apply on the current instance
 *
 * @param {object} args
 * The arguments stack of the function * 
 */
IEventDispatcher.dispatchHandler = function(sEventName, fEventHandler, args)
{
	// execute the handler with all the rest of the arguments
	try
	{
		var retVal = fEventHandler.apply(this, args );
		if(this.log instanceof Log4Js.Logger) this.log.info("after event " +sEventName+ ": " + Object.serialize(args) + ". returned value: " + retVal);
		return retVal;
	}
	catch(ex)
	{
		if(this.log instanceof Log4Js.Logger) this.log.error("event " + sEventName + " failed:" + Object.serialize(ex) );
		if(this.ignoreEventErrors == true) return;
		throw ex;
	}	
}

/**
 * attaches the hanlder to the named event, using an event stack.
 * The IEventDispatcher.dispatch knows to recognize this, and 
 * applies the event stack by its registration order (LIFO).
 * 
 * @param {string} sEventName
 * The name of the event
 *
 * @param {function} fHandler
 * The handler function
 */
IEventDispatcher.attachEvent = function(sEventName, fHandler)
{
	Claim.isString(sEventName, "IEventDispatcher.attachEvent(sEventName,..) - sEventName is expected to be a string representing the event name");
	Claim.isFunction(fHandler, "IEventDispatcher.attachEvent(...,fHandler) - fHandler is expected to be the event handler function");
	var oEvent = this[sEventName];
	
	if(oEvent === undefined || oEvent === null)
	{
		this[sEventName] = fHandler;
		return;
	}
	
	switch( typeof( oEvent ) )
	{
		case 'function':
			oEvent = this[sEventName] = [ this[sEventName] ];
			/* !!no break!! deliberate case sliding. */
		case 'object':
			if (oEvent instanceof Array)
			{
				this[sEventName][this[sEventName].length] = fHandler;
				return;
			}
		
		default: //string, boolean, number, objects, and so on...
			sEventName += " is not an event, but: " + Object.serialize( oEvent ); 
			this.log.error(sEventName);
			throw new Error(sEventName);
	}
}

/**
 * @namespace TC.Controls
 *
 */
TC.Controls = {}
/**
 * @private
 * @returns a RegExp instance to execute a search of a simple containing tag in an HTML string
 *
 * @param {string} sTagName
 * The name of the simple containinig tag to find
 */
TC.Controls.tagRegExpFinder = function(sTagName)
{
	return new RegExp( "\<" + sTagName + "\>([\\w\\W]*)\<\/" + sTagName + "\>" , "gi" );
}
/**
 * @returns the HTML contained by the specified tag.
 * The tag has to be simple, means - with no attributes or spaces between its tringular braces.
 *
 * @param {string} sHTMLString
 * The HTML string to be searched in
 *
 * @param {string} sInnerTag
 * The tag containing the text to extract from the big HTML string
 */
TC.Controls.getInnerTag = function(sHTMLString, sInnerTag)
{
	try
	{
		return this.tagRegExpFinder(sInnerTag).exec( sHTMLString )[1];
	}
	catch(ex)
	{
		return null;
	}
}
/**
 * @class TC.Controls.Repeater
 * 
 *
 */
TC.Controls.Repeater = Class.create();
TC.Controls.Repeater = Class.enhance(TC.Controls.Repeater, IEventDispatcher);
/**
 * mapping of tag-names to template elements
 *
 */
TC.Controls.Repeater.defaultParseTags =	{ header		: "header"
										, item			: "item"
										, alternateItem : "alternate"	
										, seperator		: "seperator"
										, footer		: "footer"
										, noData		: "noData"
										};
/**
 * @constructor
 *
 * @param {string} sTemplateString
 *
 * @param {Log4Js.Logger(optional)} oLog
 *
 * @param {object(optional)} oParseTags
 *
 */
TC.Controls.Repeater.prototype.initialize = function( sTemplateString , oLog, oParseTags)
{
	this.log = (oLog && oLog instanceof Log4Js.Logger)? oLog : new Log4Js.Logger("Repeater");

	Claim.isString(sTemplateString, "sTemplateString is expected to be the template HTML string");
	this.templateString = sTemplateString;

	if(!oParseTags)
		oParseTags = Object.clone(this.constructor.defaultParseTags);
	else
		oParseTags = Object.extend( Object.clone(this.constructor.defaultParseTags), oParseTags);
	
	this.dispatch("onInit", oParseTags);
	
	this.templates = {};
	var each;
	for(each in oParseTags)
	{
		this.templates[each] = TC.Controls.getInnerTag( this.templateString, oParseTags[each] ) || "";
		this.log.debug( each + "-template:" + this.templates[each].replace(/</g, "&lt;"));
	}

	this.dispatch("onLoad");
}
/**
 *
 *
 */
TC.Controls.Repeater.prototype.dataBind = function(oMapping, oDataSource)
{
	if( oDataSource ) this.dataSource = oDataSource;
	if( oMapping ) this.bindMapping = oMapping;

	Claim.isLiveObject(this.bindMapping, "Mapping must be an object. Ither provide it as a first argument, or set the property: rpt.mapping");
	Claim.isArray( this.dataSource, "DataSource must be an array. Ither provide it as a second argument, or set the property: rpt.dataSource");
	var i, iIndex, arrBoundItems = [];
	
	this.dispatch("onDataBind", this.dataSource );
	
	for(i = 0; i < oDataSource.length; i++ )
	{
		iIndex = arrBoundItems.length;
		var item =  { dataItemIndex	: i
					, itemIndex		: iIndex
					, dataItem		: oDataSource[i]
					, template		: (this.templates.alternateItem && iIndex % 2) ? this.templates.alternateItem : this.templates.item
					, mapping		: Object.clone( this.bindMapping )
					, skipItem		: false
					}
		
		this.dispatch("onItemDataBound", item);
		if (true == item.skipItem)
			continue;
		
		arrBoundItems[arrBoundItems.length] = item.template.bindTemplate(item.mapping, item.dataItem);
	}
	
	this.content =  {header   : this.templates.header
					,seperator: this.templates.seperator
					,footer   : this.templates.footer
					,items    : arrBoundItems
					,noData   : this.templates.noData
					,toString :	function()
								{
									return this.header 
										 + ( (this.items.length)?
											 this.items.join(this.seperator) : this.noData 
										   )
										 + this.footer;
		  						}
					};

	if(0 == this.content.items.length)
	{
		this.dispatch("onNoDataFound");
	}
	
	this.dispatch("onDataBound", this.content);
	
	return this.content;
}
/**
 *
 *
 */
TC.Controls.Repeater.prototype.render = function(oTargetElement, oMapping, oDataSource){
	this.log.debug("Repeater - rendering");
	if(oTargetElement !== null) Claim.isObject(oTargetElement, "oTargetElement can be an HTML element or the document object, or null");
	
	if (  !this.content 
	   || oMapping && oDataSource ) 
		 this.content = this.dataBind(oMapping, oDataSource);
	
	this.targetElement = oTargetElement;

	this.dispatch("onRender", this.content);
	
	var strHTML = this.content.toString();
	if( oTargetElement)
	{
		if( oTargetElement.write === document.write )
		{
			oTargetElement.write( strHTML );
		}else{
			Element.setText( oTargetElement, strHTML );
		}
	}

	this.log.info("Repeater - render complete");
	return strHTML;	
}

/**
 * Adds the specified url to the favorites list of IE or to the bookmark of Mozilla/Firefox
 * @param {string} url
 * the url to add to the favorites list of the cross-browser
 * @param {string} displayName
 * the display text of the url
 */
TC.AddFavorite = function(url, displayName){
	
	if(window.external){/* IE */
		window.external.AddFavorite( url, displayName); 
	}else if(window.sidebar){ /* Mozilla */
		window.sidebar.addPanel(displayName,url,"");
	}
}


if(!window.UI) UI = {};
if(!UI.Avatar) UI.Avatar = {};
/**
 *
 * enum for avatar sizes
 */
UI.Avatar.Size = {};
UI.Avatar.Size.Studio		= {						  name:"Studio"};
UI.Avatar.Size.Size150x200	= {width:150, height:200, name:"Size150x200" };
UI.Avatar.Size.Size124x165	= {width:124, height:165, name:"Size124x165" }; 
UI.Avatar.Size.Size86x115	= {width:86 , height:115, name:"Size86x115"  };
UI.Avatar.Size.Size98x131	= {width:98 , height:131, name:"Size98x131"  };
UI.Avatar.Size.Size65x87	= {width:65 , height:87 , name:"Size65x87"   };
UI.Avatar.Size.Size24x24	= {width:24 , height:24 , name:"Size24x24"   };  
UI.Avatar.Size.Size48x48	= {width:48 , height:48 , name:"Size48x48"   };  
