String.prototype.trim = function() { return this.replace(/^\s+|\s+$/, ''); };

/////////////////////////////////////////////////////
//	EWType enum

function EWType()
{
	EWType.TString = "string";
	EWType.TInt = "number";
	EWType.TObject = "object";
	EWType.TBool = "boolean";
	EWType.TFunction = "function";
}

/////////////////////////////////////////////////////
//	WReflection class

function WReflection()
{
};

WReflection.IsInstance = function(obj)
{
	var typeOfObj = (typeof  obj);
	var stringOfObj = "";
	try
	{
		stringOfObj = String(obj);
	}
	catch(ex)
	{
		//	this case has happened only with IE6 when testing an initialized HTTP Request object
		return true;
	}
	return typeOfObj != "undefined" && typeOfObj != "unknown" && stringOfObj != "null";
};

WReflection.HasProperties = function(obj)
{
	for (var prop in obj)
		return true;
	return false;
};

/////////////////////////////////////////////////////
//	WBrowserCaps class

function WBrowserCaps()
{
};

WBrowserCaps.SetOpacity = function(element, value)
{
	var currentStyle = element.currentStyle;
	if ((WReflection.IsInstance(currentStyle) && !currentStyle.hasLayout) || (!WReflection.IsInstance(currentStyle) && element.style.zoom == "normal"))
		element.style.zoom = String(1);
	element.style.MozOpacity = String(value);
	var filter = String(element.style.filter);
	if (WReflection.IsInstance(filter))
		filter = WBrowserCaps.stripFilterAlpha(filter);
	else
		filter = "";
	if (value < 0.00001)
		value = 0.00001;
	WBrowserCaps.InternalSetOpacityStyle(element, value, filter);
};

WBrowserCaps.InternalSetOpacityStyle = function(element, value, filter)
{
	//	don't know a better way to go around the bug of dissapearing images, located in transparent layers...
	//	to reporoduce the bug, set isWebKit to false and try the lightbox with safari or chrome
	var isWebKit = new RegExp(" AppleWebKit/").test(navigator.userAgent);
	var next = null;
	var parent = null;
	if (isWebKit)
	{
		next = element.nextSibling;
		parent = element.parentNode;
		parent.removeChild(element);
	}
	if (value != 1)
	{
		element.style.opacity = String(value);
		element.style.KhtmlOpacity = String(value);
		element.style.filter = filter + "alpha(opacity=" + (value * 100) + ")";
	}
	else
	{
		element.style.opacity = "";
		element.style.KhtmlOpacity = "";
		element.style.filter = filter;
	}
	if (isWebKit)
	{
		if (next == null)
			parent.appendChild(element);
		else
			parent.insertBefore(element, next);
	}
};

WBrowserCaps.stripFilterAlpha = function(filter)
{
	var r = new RegExp("alpha\\([^\\)]*\\)", "gi");
	return filter.replace(r, "");
};

WBrowserCaps.AdjustPixelLengthString = function(lengthString)
{
	var regex = new RegExp("\\W*px\\W*$", "gi");
	if (lengthString.search(regex) != -1)
		return lengthString;
	return lengthString + "px";
};

WBrowserCaps.ToPixelLength = function(lengthValue)
{
	if ((typeof  lengthValue) == EWType.TString)
		return WBrowserCaps.AdjustPixelLengthString(lengthValue );
	return WBrowserCaps.AdjustPixelLengthString(  String(  parseInt(lengthValue )));
};

WBrowserCaps.ToPercentLength = function(lengthValue)
{
	return   String(  parseFloat(lengthValue )) + "%";
};

WBrowserCaps.FromPixelLength = function(lengthValue)
{
	return   parseInt(NTools.ReplaceString(  String(lengthValue).toLowerCase(), "px", ""));
};

WBrowserCaps.GetOffset = function(element)
{
	var result = new Object();
	result.offsetLeft = WBrowserCaps.findPageX(element);
	result.offsetTop = WBrowserCaps.findPageY(element);
	return result;
};

WBrowserCaps.GetPageOffsetFromEvent = function(eventObject, eventTarget)
{
	var result = new Object();
	if (!WReflection.IsInstance(eventObject))
		return result;
	if (WReflection.IsInstance(eventObject.pageX))
	{
		result.offsetLeft = eventObject.pageX;
		result.offsetTop = eventObject.pageY;
	}
	else
	{
		result.offsetLeft =   document.body.scrollLeft + eventObject.clientX;
		result.offsetTop =   document.body.scrollTop + eventObject.clientY;
	}
	return result;
};

WBrowserCaps.findPageX = function(element)
{
	var initialObj = element;
	var curleft = 0;
	if (element.offsetParent != null)
	{
		while (true)
		{
			curleft += element.offsetLeft;
			if (element.offsetParent == null)
				break;
			element = element.offsetParent;
		}
	}
	else if (element["x"] != null)
		curleft += element.x;
	return curleft - WBrowserCaps.findScrollOffsetLeft(initialObj);
};

WBrowserCaps.findPageY = function(element)
{
	var initialObj = element;
	var curtop = 0;
	if (element.offsetParent != null)
	{
		while (true)
		{
			curtop += element.offsetTop;
			if (element.offsetParent == null)
				break;
			element = element.offsetParent;
		}
	}
	else if (element["y"] != null)
		curtop += element.y;
	return curtop - WBrowserCaps.findScrollOffsetTop(initialObj);
};

WBrowserCaps.findScrollOffsetLeft = function(element)
{
	var curoffset = 0;
	while (element.parentNode != null)
	{
		if (element.parentNode["scrollLeft"] != null)
			curoffset += element.parentNode.scrollLeft;
		element = element.parentNode;
	}
	return curoffset - WBrowserCaps.GetScrollLeft();
};

WBrowserCaps.findScrollOffsetTop = function(element)
{
	var curoffset = 0;
	while (element.parentNode != null)
	{
		if (element.parentNode["scrollTop"] != null)
		{
			var scrollTop = parseInt(element.parentNode.scrollTop)
			if(String(scrollTop) != "NaN")
			{
			    curoffset += scrollTop;
			}
		}
		element = element.parentNode;
	}
	return curoffset - WBrowserCaps.GetScrollTop();
};

WBrowserCaps.GetScrollLeft = function()
{
	if (  window["pageXOffset"] != null)
		return      window["pageXOffset"];
	else if (  document.documentElement["scrollLeft"] != null)
		return      document.documentElement["scrollLeft"];
	return 0;
};

WBrowserCaps.GetScrollTop = function()
{
	if (  window["pageYOffset"] != null)
		return      window["pageYOffset"];
	else if (  document.documentElement["scrollTop"] != null)
		return      document.documentElement["scrollTop"];
	return 0;
};

/////////////////////////////////////////////////////
//	WExponentAnimationStepCalculator class

function WExponentAnimationStepCalculator()
{
};

WExponentAnimationStepCalculator.prototype.GetStepValue = function(self, start, length, stepCount, stepIndex)
{            
	if (length < 0)
	{
		var b1 = start - 1;
		var a1 = stepCount / Math.log(-length + 1);
		return -Math.exp(stepIndex / a1) + b1;
	}
	var b = start - 1;
	var a = stepCount / Math.log(length + 1);
	return Math.exp(stepIndex / a) + b;
};

/////////////////////////////////////////////////////
//	WLogarithmicAnimationStepCalculator class

function WLogarithmicAnimationStepCalculator()
{
};

WLogarithmicAnimationStepCalculator.prototype.GetStepValue = function(self, start, length, stepCount, stepIndex)
{            
	var b = start;
	var a = Math.log(stepCount + 1) / length;
	return Math.log(stepIndex + 1) / a + b;
};

/////////////////////////////////////////////////////
//	WSineAnimationStepCalculator class

function WSineAnimationStepCalculator()
{
};

WSineAnimationStepCalculator.prototype.GetStepValue = function(self, start, length, stepCount, stepIndex)
{            
	var a = - Math.cos(Math.PI * stepIndex / stepCount);	//	[-1..1]
	var b = a / 2 + 0.5;	//	[0..1]
	return start + b * length;
};

/////////////////////////////////////////////////////
//	WCssClass class
function WCssClass(text)
{
	var self = this;
	self.mainClassName = null;
	self.mainClassSwitches = null;
	self.modifierClassNames = null;
	self.secondaryClassNames = null;
	self.Read(text);
};

WCssClass.prototype.Read = function(text)
{
	var self = this;
	self.mainClassName = "";
	self.mainClassSwitches = new Array();
	self.modifierClassNames = new Array();
	self.secondaryClassNames = new Array();
	var tokens = text.split(new RegExp("\\s"));
	var length = tokens.length;
	for (var i = 0; i < length; i++)
	{
		var token = tokens[i] ;
		if (token.trim() == "")
			continue;
		if (token.charAt(0) == "_")
		{
			self.modifierClassNames[self.modifierClassNames.length] = token;
			continue;
		}
		if (self.mainClassName != "")
		{
			self.secondaryClassNames[self.secondaryClassNames.length] = token;
			continue;
		}
		var subTokens = token.split("_");
		self.mainClassName = subTokens[0] ;
		var length2 = subTokens.length;
		for (var j = 1; j < length2; j++)
			self.mainClassSwitches[self.mainClassSwitches.length] = subTokens[j];
	}
	self.mainClassSwitches.sort();
};

//	Switches are alphabetically ordered "_"-prefixed postfixes of the first (main) class name in the css class list
//	e.g. "mainClassName_switch1_switch2_switch3 className className"
WCssClass.prototype.HasSwitch = function(text)
{
	var self = this;
	var length = self.mainClassSwitches.length;
	for (var i = 0; i < length; i++)
	{
		if (self.mainClassSwitches[i] == text)
			return true;
	}
	return false;
};

WCssClass.prototype.SetSwitch = function(text)
{
	var self = this;
	var length = self.mainClassSwitches.length;
	for (var i = 0; i < length; i++)
	{
		if (self.mainClassSwitches[i] == text)
			return;
	}
	self.mainClassSwitches[self.mainClassSwitches.length] = text;
	self.mainClassSwitches.sort();
};

WCssClass.prototype.RemoveSwitch = function(text)
{
	var self = this;
	var old = self.mainClassSwitches;
	self.mainClassSwitches = new Array();
	var length = old.length;
	for (var i = 0; i < length; i++)
	{
		if (old[i] == text)
			continue;
		self.mainClassSwitches[self.mainClassSwitches.length] = old[i];
	}
};

//	Switches are alphabetically ordered "_"-prefixed class names, appended after the first (main) class name
//	e.g. "mainClassName _modifier1 _modifier2"
WCssClass.prototype.HasModifier = function(text)
{
	if(text.length > 0 && text[0] == '_')
	{
		text = text.substr(1, text.length - 1);
	}
	
	var self = this;
	var length = self.modifierClassNames.length;
	for (var i = 0; i < length; i++)
	{
		if (self.modifierClassNames[i] == text)
			return true;
	}
	return false;
};

WCssClass.prototype.SetModifier = function(text)
{
	if(text.length > 0 && text[0] == '_')
	{
		text = text.substr(1, text.length - 1);
	}
	
	var self = this;
	var length = self.modifierClassNames.length;
	for (var i = 0; i < length; i++)
	{
		if (self.modifierClassNames[i] == text)
			return;
	}
	self.modifierClassNames[self.modifierClassNames.length] = text;
};

WCssClass.prototype.RemoveModifier = function(text)
{
	if(text.length > 0 && text[0] == '_')
	{
		text = text.substr(1, text.length - 1);
	}
	
	var self = this;
	var old = self.modifierClassNames;
	self.modifierClassNames = new Array();
	var length = old.length;
	for (var i = 0; i < length; i++)
	{
		if (old[i] == text)
			continue;
		self.modifierClassNames[self.modifierClassNames.length] = old[i];
	}
};

WCssClass.prototype.ToString = function()
{            
	var self = this;
	var result = self.mainClassName;
	var length = 0;
	var i = 0;
	length = self.mainClassSwitches.length;
	for (i = 0; i < length; i++)
	{
		result += "_" + self.mainClassSwitches[i];
	}
	length = self.secondaryClassNames.length;
	for (i = 0; i < length; i++)
	{
		result += " " + self.secondaryClassNames[i];
	}
	length = self.modifierClassNames.length;
	if (length != 0)
	{
		result += " ";
		for (i = 0; i < length; i++)
		{
			var modifierName = self.modifierClassNames[i];
			if(modifierName.length > 0 && modifierName[0] != '_')
			{
				modifierName = '_' + modifierName;
			}
			
			result += " " + modifierName;
		}
	}
	return result;
};

/////////////////////////////////////////////////////
//	WPath class
function WPath(text)
{
	var self = this;
	self.protocol = null;
	self.parts = null;
	self.Read(text);
};

WPath.prototype.Read = function(text)
{
	var self = this;
	
	var protocolTokens = text.split(new RegExp("\//", "gi"));
	var partsText;
	if(protocolTokens.length == 2)
	{
	    self.protocol = protocolTokens[0];
	    partsText = protocolTokens[1];
	}
	else
	{
	    self.protocol = "";
	    partsText = protocolTokens[0];
	}
	
	self.parts = new Array();
	var tokens = partsText.split(new RegExp("\/", "gi"));
	var length = tokens.length;
	for (var i = 0; i < length; i++)
	{
		self.parts[self.parts.length] = tokens[i];
	}
};

WPath.prototype.GetPartIndex = function(partName)
{
	var self = this;

	var length = self.parts.length;
	for (var i = 0; i < length; i++)
	{
		var tokens = self.parts[i].split(new RegExp("_", "gi"));
		var partBaseName = tokens[0];
		if(partBaseName == partName)
		{
			return i;
		}
	}
	
	return -1;
};

WPath.prototype.HasSwitch = function(folderName, text)
{
	var self = this;
	
	var partIndex = self.GetPartIndex(folderName);
	if(partIndex == -1)
	{
		alert("pass 1: partIndex == -1; " + folderName);
	}
	var cssClass = new WCssClass(self.parts[partIndex]);
	
	return cssClass.HasSwitch(text);
};

WPath.prototype.SetSwitch = function(folderName, text)
{
	var self = this;
	
	var partIndex = self.GetPartIndex(folderName);
	if(partIndex == -1)
	{
		alert("pass 2: partIndex == -1; " + folderName);
	}
	var cssClass = new WCssClass(self.parts[partIndex]);
	
	cssClass.SetSwitch(text);
	self.parts[partIndex] = cssClass.ToString();
};

WPath.prototype.RemoveSwitch = function(folderName, text)
{
	var self = this;
	
	var partIndex = self.GetPartIndex(folderName);
	if(partIndex == -1)
	{
		alert("pass 3: partIndex == -1; " + folderName);
	}
	var cssClass = new WCssClass(self.parts[partIndex]);
	
	cssClass.RemoveSwitch(text);
	self.parts[partIndex] = cssClass.ToString();
};

WPath.prototype.ToString = function()
{            
	var self = this;
	
	var result = self.parts[0];
	var length = 0;
	var i = 0;
	length = self.parts.length;
	for (i = 1; i < length; i++)
	{
		result += "/" + self.parts[i];
	}
	return self.protocol + "//" + result;
};

/////////////////////////////////////////////////////
//	WDomAutomationTools class
function WDomAutomationTools()
{
}

WDomAutomationTools.SelectElementByRole = function(rootElement, role, tagNames)
{
	return WDomAutomationTools.SelectElementByAttribute(rootElement, "ws", "role", role, tagNames);
};

WDomAutomationTools.SelectElementsByRole = function(rootElement, role, tagNames)
{
	return WDomAutomationTools.SelectElementsByAttribute(rootElement, "ws", "role", role, tagNames);
};

WDomAutomationTools.GetMetadata = function(element, prefix)
{
	var result = new Object();
	var length = element.attributes.length;
	for (var i = 0; i < length; i++)
	{
		var attribute = element.attributes[i];
		var tokens = attribute.name.split(new RegExp(":", "gi"));
		if(tokens.length > 1 && tokens[0] == prefix)
		{
			result[tokens[1]] = attribute.value;
		}
	}
	
	return result;
};

WDomAutomationTools.SelectElementByAttribute = function(rootElement, prefix, name, value, tagNames)
{
	var attributeName = prefix + ":" + name;
	value = value.toLowerCase();
	var length2 = tagNames.length;
	for (var j = 0; j < length2; j++)
	{
		var tagName = tagNames[j];
		var elements = rootElement.getElementsByTagName(tagName);
		var length = elements.length;
		for (var i = 0; i < length; i++)
		{
			var element = elements[i];
			if (String(element.getAttribute(attributeName)).toLowerCase() == value)
				return element;
		}
	}
	return null;
};

WDomAutomationTools.SelectElementsByAttribute = function(rootElement, prefix, name, value, tagNames)
{
	var Attribute = prefix + ":" + name;
	value = value.toLowerCase();
	var result = new Array();
	var length2 = tagNames.length;
	for (var j = 0; j < length2; j++)
	{
		var tagName = tagNames[j] ;
		var elements = rootElement.getElementsByTagName(tagName);
		var length = elements.length;
		for (var i = 0; i < length; i++)
		{
			var element = elements[i] ;
			if (String(element.getAttribute(Attribute)).toLowerCase() == value)
				result[result.length] = element;
		}
	}
	return result;
};

