//-=-=-=-=-=- Enhances on Object -=-=-=-=-=-
Object.clone = function(obj)
{
	return this.extend( {} , obj);
}
/**
 *
 *Object.extend
 */
Object.extend(Element,{
setText:function(e,sText){
var tag=e.tagName.toUpperCase();
switch(tag){
case "INPUT":
case "TEXTAREA":
e.value=sText;
break;
case "SELECT":
e.value=sText;
break;
default:
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);}}}}});
Serialize=function(obj){
if(!obj)return 'null';
var str='';
var psik='';
for(each in obj){
str+=psik;psik=",";
str+=each+":"
switch(typeof(obj[each])){
case 'function':
break;
case 'object':
str+=Serialize(obj[each]);
break;
case 'string':
str+='"'+obj[each].replace(/\"/,"\"") + '"';
break;
default:
str+=obj[each];}}
return "{"+str+"}";}
Function.prototype.insert=function(sCodeLine){
var a=this.toString().split("{");
a[1]="\n\t"+sCodeLine+a[1];
return(eval("a = "+a.join("{")));}
Glossary={_terms:{},addPair:function addPair(key,value){this._terms[key]=value;},term:function term(key){return this._terms[key];}};
Glossary.addPair('{JAST_REQUEST_TIMEOUT_DEF_MSG}','Problems connecting to the server.');
Glossary.addPair('{JAST_REQUEST_REFUSED_DEF_MSG}','Server failes the request');
function ask(){
var s='';
while(s!="STOP"){
s=prompt('To close - enter "STOP"',s);
if(s=="STOP")return;
alert(eval(s));}}
function CreateHiddenInput(sName,sValue){
var input=document.createElement("input");
input.setAttribute("type","hidden");
input.setAttribute("name",sName);
input.setAttribute("value",sValue);
return input;}

//-=-=-=-=-=- /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;
}

/**
 *
 */
Class.enhancePrototype = function(fClass, oInterface)
{
	return Object.extend( fClass.prototype, oInterface );
}

/**
 *
 */
Class.enhanceSingleton = function(oSingleton, oInterface)
{
	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 -=-=-=-=-=-

// --- Enhance String.prototype -----------------------------------
/**
 * 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)
{
	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, oDataSource, parentData) {
    
    var sTemplate, placehoder, attribute, replacment;
    sTemplate = this.toString();

    for (placehoder in oMapping) {
        if (placehoder != 'toJSONString')//TODO: jsonParser adds to any object the 'toJSONString' as first child.
        {
            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;
            }
            //alert(attribute)
            switch (typeof (attribute)) {
                case 'function':
                    try {//debugger;
                        //replacement = attribute(oDataSource, log);
                        replacement = attribute(oDataSource, parentData);
                    } catch (ex) {
                        //log.error("String.bindTemplate - Error in mapping-handler for " + placehoder + " : " + attribute.toString() );
                        throw ex;
                    }
                    break;

                case 'string':
                    replacement = oDataSource[attribute];
                    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;
}
// --- /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;    
}

// --- /Enhance Number.prototype -----------------------------------

if(!window.Const) Const = {};
Object.extend(	Const,	
				{	UNSET_STRING: "-UNSET-STRING-"
				,	UNSET_NUMBER: NaN	
				}
			 );			 
/* === TC Namesapce ============================================================ */
if(!window["TC"])
	window.TC = {};


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 ... */)
{
	
	//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)
{
	var oEvent = this[sEventName];
	
	if(oEvent === undefined || oEvent === null)
	{
		this[sEventName] = fHandler;
		return;
	}
	
	switch( typeof( oEvent ) )
	{
		case 'function':
			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"
										, noDataFound	: "noDataFound"
										};
/**
 * @constructor
 *
 * @param {string} sTemplateString
 *
 * @param {Log4Js.Logger(optional)} oLog
 *
 * @param {object(optional)} oParseTags
 *
 */
TC.Controls.Repeater.prototype.initialize = function( sTemplateString , sInnerTemplate, oLog, oParseTags)
{
	this.templateString = sTemplateString;
    
    //OrenT addition
    if(sInnerTemplate)
		this.innerTemplate = sInnerTemplate;
	else
		this.innerTemplate = null;
    
	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.dispatch("onLoad");
}
/**
 *
 *
 */
TC.Controls.Repeater.prototype.dataBind = function(oMapping, oDataSource, oParentDataSource)
{//debugger
    //if(oParentDataSource) this.parentDataSource = oParentDataSource;
	if( oDataSource ) this.dataSource = oDataSource;
	if( oMapping ) this.bindMapping = oMapping;
	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
					, dataLength        : oDataSource.length 
					, parentDataSrc     : oParentDataSource
					, data              : oDataSource
					, dataItem		    : oDataSource[i]
					, template		    : ((this.templates.alternateItem && iIndex % 2) ? this.templates.alternateItem : this.templates.item)					
					, allTemplates      : this.templates
					, innerTemplate     : this.innerTemplate
					, mapping		    : Object.clone( this.bindMapping )
					, itemSettings      : (this.bindMapping.settings!=null? this.bindMapping.settings:null)
					, skipItem		    : (this.bindMapping.settings && this.bindMapping.settings.skip? this.bindMapping.settings.skip:false)
					}
		this.dispatch("onItemDataBound", item);
		if (true == item.skipItem)
			continue;
		
		arrBoundItems[arrBoundItems.length] = item.template.bindTemplate(item.mapping, item.dataItem, item.parentDataSrc);//item.parentDataSrc so we can approach to the parent object properties while the chld is rendering
	}
	
	this.content =  {header   : this.templates.header
					,seperator: this.templates.seperator
					,footer   : this.templates.footer
					,items    : arrBoundItems
					,noData   : this.templates.noDataFound
					,toString :	function()
								{
									return this.header 
										 + ( (this.items.length)?
											 this.items.join(this.seperator) : this.noData 
										   )
										 + this.footer;
		  						}
					};
					
	this.dispatch("onContentChange",this.content);
					
	if(0 == this.content.items.length)
	{
		this.dispatch("onNoDataFound");
	}
}
/**
 *
 *
 */
TC.Controls.Repeater.prototype.render = function(oTargetElement, oMapping, oDataSource){
	if(!this.content)	this.dataBind(oMapping, oDataSource);
	this.targetElement = oTargetElement;

	this.dispatch("onRender");
	
	var strHTML = this.content.toString();
	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,"");
	}
}

