﻿
Type.registerNamespace("CodeEffects.Tools.AutoFill");
CodeEffects.Tools.AutoFill.Entry = function()
{
	this.id = "";
	this.value = "";
	this.entries = [];
};
CodeEffects.Tools.AutoFill.Events = function()
{
	this.onSearch = null;
	this.onIdSelected = null;
	this.onCriteriaTooShort = null;
};
CodeEffects.Tools.AutoFill.Control = function(txt,events,minChars,maxVisible,cssClass)
{
	var
		ATTR_ID = "attrCodeEffectsAutoFillElId",
		ATTR_VALUE = "attrCodeEffectsAutoFillElValue",
		ATTR_INDEX = "attrCodeEffectsAutoFillIndex";
	var INTERVAL = 400;
	var appended = false,scrolled = false,loading = false;
	var click = null,timer = null,selectedRow,bounds = Sys.UI.DomElement.getBounds;
	var defined = CodeEffects.Core.defined,getHeight = CodeEffects.Core.getElementHeight,highlight = CodeEffects.Core.highlight,dim = CodeEffects.Core.dim;
	var container = document.createElement("TABLE");
	container.id = "tblCodeEffectsAutoFillCon"+txt.id;
	container.cellSpacing = 0;
	container.cellPadding = 2;
	container.border = 0;
	var div = document.createElement("DIV");
	div.id = "divCodeEffectsAutoFillCon"+txt.id;
	div.style.position = "absolute";
	div.style.zIndex = 8896;
	div.style.padding = "2px";
	div.style.overflow = "auto";
	div.style.backgroundColor = "#fff";
	if(defined(cssClass))div.className = cssClass;
	div.appendChild(container);
	div.style.display = "none";
	txt.onkeydown = function(e){return selector(e);}

	this.getTextBox = function(){return txt;}
	this.fill = function(entries)
	{
		clearTimer();
		if(!appended)
		{
			document.body.appendChild(div);
			appended = true;
		}
		clearContainer();
		selectedRow = -1;
		if(entries.length == 0)
		{
			clear();
			loading = false;
			return;
		}
		div.style.display = "";
		div.style.width = container.style.width = "";
		var ie = CodeEffects.Core.ie();
		if(!ie)div.style.height = "";
		var row,cell;
		for(var i in entries)
		{
			row = container.insertRow(-1);
			row.id = "trCodeEffectsAutoFillEntry"+i;
			row.setAttribute(ATTR_ID,!defined(entries[i].id) || entries[i].id.length == 0 ? "true" : entries[i].id);
			row.setAttribute(ATTR_VALUE,entries[i].value);
			row.setAttribute(ATTR_INDEX,i);
			row.onclick = function(e)
			{
				setValue(this.getAttribute(ATTR_VALUE),this.getAttribute(ATTR_ID));
				clear();
			}
			row.onmouseover = function(e)
			{
				selectedRow = parseInt(this.getAttribute(ATTR_INDEX));
				dimContainer();
				highlight(this);
			}
			row.onmouseout = function(e){dim(this);}
			for(var j in entries[i].entries)
			{
				cell = row.insertCell(-1);
				cell.id = "tdAutoFillEntryCell"+i+j;
				cell.style.cursor = "default";
				cell.style.whiteSpace = "nowrap";
				cell.style.fontSize = "11px";
				cell.innerHTML = entries[i].entries[j];
			}
		}
		if(container.rows.length > 0)
		{
			var b = bounds(txt);
			var scroll = entries.length > maxVisible;
			var ch = getHeight(container.rows[0].cells[0]);
			var dh = ch * (scroll ? maxVisible : entries.length);
			div.style.height = dh + "px";
			// Vlad: "+12" to make sure the div always has some space below it
			if(CodeEffects.Core.getWindowDimensions().height > (b.y - CodeEffects.Core.getScrollHeight()) + b.height + dh + 12)div.style.top = b.y + b.height + "px";
			else div.style.top = b.y - 6 - dh + "px"; // "-6" is a gap compensation in all browsers (of freaking unknown nature)
			div.style.left = b.x + "px";
			var c = bounds(container);
			var sc = CodeEffects.Core.getScrollBarWidth();
			var off = (container.cellPadding) * entries[0].entries.length + 1;
			if(c.width + off < b.width)
			{
				// Vlad: shorter than txt
				if(scroll)
				{
					container.style.width = b.width - off + "px";
					div.style.width = b.width + sc - off + "px";
				}
				else div.style.width = container.style.width = b.width - off + "px";
			}
			else
			{
				// Vlad: longer than txt
				if(scroll)div.style.width = sc + c.width + "px";
				else div.style.width = c.width + "px";
			}
			div.scrollTop = container.rows[0].offsetTop;
			click = typeof(document.onclick)=="function" ? document.onclick : null;
			document.onclick = function(e){check(e);}
		}
		else
		{
			if(defined(click))document.onclick = function(e){try{click(e);}catch(eee){}}
			else document.onclick = null;
			div.style.display = "none";
		}
		loading = false;
	}
	var selector = function(e)
	{
		clearTimer();
		var k = CodeEffects.Core.getKey(e);
		if(((txt.value.length > 0 && txt.value.length < minChars) || (k == 8 && txt.value.length == minChars)) && defined(events.onCriteriaTooShort))events.onCriteriaTooShort();
		var ret = true,up = true;
		if(container.rows.length > 0)
		{
			switch(k)
			{
				case 13:
					scrolled = true;
					if(selectedRow > -1)
						setValue(
							container.rows[selectedRow].getAttribute(ATTR_VALUE),
							container.rows[selectedRow].getAttribute(ATTR_ID));
					clear();
					ret = up = false;
					break;
				case 8:	case 27: case 46:
					scrolled = true;
					clear();
					up = false;
					break;
				case 40:
					scrolled = true;
					var r = getHeight(container.rows[0].cells[0]);
					var go1 = (div.scrollTop + (r * (maxVisible-1))) - (selectedRow * r) < r;
					selectedRow++;
					if(selectedRow > container.rows.length-1)selectedRow = container.rows.length-1;
					if(go1)div.scrollTop = container.rows[selectedRow-maxVisible+1].offsetTop;
					handleDiv();
					ret = up = false;
					break;
				case 38:
					// Vlad: the next line makes sure that in the beginning the first row sets as current
					// no matter which arrow is down and where the div is (above the txt or below)
					if(selectedRow == -1)selectedRow = 0;
					if(selectedRow >= 0)
					{
						scrolled = true;
						var go2 = container.rows[selectedRow].offsetTop - div.scrollTop < getHeight(container.rows[0].cells[0]);
						selectedRow--;
						if(selectedRow < 0)selectedRow = 0;
						if(go2)div.scrollTop = container.rows[selectedRow].offsetTop;
						handleDiv();
						ret = false;
					}
					up = false;
					break;
				case 35: case 36: case 37: case 39:
					scrolled = true;
					up = false;
					break;
			}
		}
		else
		{
			switch(k)
			{
				case 8:	case 27: case 35: case 36: case 37:	case 39: case 46:
					up = false;
					break;
			}
		}
		if(up)txt.onkeyup = function(e){setTimer();}
		else txt.onkeyup = null;
		return ret;
	}
	var setValue = function(val,id)
	{
		txt.value = val;
		if(typeof(txt.onchange) == "function")txt.onchange();
		if(defined(events.onIdSelected))events.onIdSelected(id);
	}
	var handleDiv = function()
	{
		dimContainer();
		highlight(container.rows[selectedRow]);
	}
	var setTimer = function()
	{
		clearTimer();
		if(scrolled)
		{
			scrolled = loading = false;
			return;
		}
		scrolled = false;
		if(txt.value.length < minChars)
		{
			clear();
			if(defined(events.onCriteriaTooShort))events.onCriteriaTooShort();
		}
		else timer = window.setInterval(load,INTERVAL);
	}
	var clearTimer = function()
	{
		window.clearInterval(timer);
		timer = null;
	}
	var load = function()
	{
		if(loading)return;
		loading = true;
		events.onSearch(txt.value);
	}
	var clear = function()
	{
		clearTimer();
		clearContainer();
		div.style.display = "none";
		loading = false;
		if(defined(click))document.onclick = function(e){try{click(e);}catch(eee){}}
		else document.onclick = null;
	}
	var check = function(ev)
	{
		ev = ev || window.event;
		ev.cancelBubble = true;
		var t = ev.target || ev.srcElement;
		var p = CodeEffects.Core.getParentByAttribute(t,ATTR_ID);
		if(!defined(p) || t.id != txt.id)clear();
	}
	var clearContainer = function(){for(var i=container.rows.length-1;i>-1;i--)container.deleteRow(i);}
	var dimContainer = function(){for(var i=0;i<container.rows.length;i++)dim(container.rows[i]);}
};
CodeEffects.Tools.DragAndDrop = function()
{
	function Space()
	{
		this.name = "unknownName";
		this.onStart = null;
		this.onDrag = null;
		this.onDrop = null;
		this.draggingElementId = "";
		this.targetAttr = "";
		this.top = 0;
		this.left = 0;
		this.padding = 0;
	}

	var SPACE_NAME_ATTRIBUTE = "dragCodeEffectsCurrentSpaceName",MOVE_COPY_ATTRIBUTE = "dragCodeEffectsCopyObject";
	var mouseOffset = null,dragObject = null;
	var isMouseDown = false,mouseState = false;
	var spaces = [],md = null,mu = null,mm = null;
	var getEl,bounds,defined,par,coords;

	this.init = function()
	{
		md = typeof(document.onmousedown)=="function"?document.onmousedown:null;
		mu = typeof(document.onmouseup)=="function"?document.onmouseup:null;
		mm = typeof(document.onmousemove)=="function"?document.onmousemove:null;
		document.onmousemove = function(e){return mouseMove(e);}
		document.onmouseup = function(e){return mouseUp(e);}
		document.onmousedown = function(e){return mouseDown(e);}
		getEl = $get,bounds = Sys.UI.DomElement.getBounds,par = CodeEffects.Core.getParentByAttribute;
		defined = CodeEffects.Core.defined,coords = CodeEffects.Core.getCoordinates;
	}
	this.dispose = function()
	{
		if(defined(mm))document.onmousemove = function(e){mm(e);}
		else document.onmousemove = null;
		if(defined(mu))document.onmouseup = function(e){mu(e);}
		else document.onmouseup = null;
		if(defined(md))document.onmousedown = function(e){md(e);}
		else document.onmousedown = null;
	}
	this.addSpace = function(name,startCallback,dragCallback,dropCallback,targetAttribute,padding)
	{
		var space = new Space();
		space.name = name;
		if(defined(padding))space.padding = padding;
		space.onStart = startCallback;
		space.onDrag = dragCallback;
		space.onDrop = dropCallback;
		if(defined(targetAttribute))space.targetAttr = targetAttribute;
		spaces.push(space);
	}
	this.addSpaceLimits = function(name,top,left)
	{
		var s = getSpaceByName(name);
		s.top = top;
		s.left = left;
	}
	this.removeSpace = function(name)
	{
		for(var i in spaces)
			if(spaces[i].name == name)
			{
				spaces.splice(i,1);
				return;
			}
	}
	this.addDraggableElement = function(spaceName,triggerElement,draggableElement,moveCopy)
	{
		moveCopy = defined(moveCopy) ? moveCopy : true;
		var s = getSpaceByName(spaceName);
		if(!defined(s))throw "No space with such name exists.";
		if(triggerElement.id == draggableElement.id)draggableElement = triggerElement;
		triggerElement.onmousedown = function(ev)
		{
			ev = ev || window.event;
			mouseOffset = getMouseOffset(this,ev);
			s.draggingElementId = draggableElement.id;
			if(moveCopy)
			{
				dragObject = draggableElement.cloneNode(true);
				dragObject.id = draggableElement.id + "Drag";
				dragObject.style.cursor = "default";
				dragObject.style.display = "none";
				dragObject.style.opacity = 0.6;
				dragObject.style.MozOpacity = 0.6;
				dragObject.style.zIndex = 6001;
				dragObject.style.filter = "alpha(opacity=60)";
				if(defined(s.targetAttr) && s.targetAttr != "")dragObject.removeAttribute(s.targetAttr);
				document.body.appendChild(dragObject);
				dragObject.style.height = bounds(draggableElement).height + "px";
				dragObject.style.width = bounds(draggableElement).width + "px";
			}
			else dragObject = draggableElement;
			dragObject.setAttribute(SPACE_NAME_ATTRIBUTE,s.name);
			dragObject.setAttribute(MOVE_COPY_ATTRIBUTE,moveCopy?"true":"false");
		}
	}
	this.removeDraggableElement = function(spaceName,triggerElement,draggableElement)
	{
		var s = getSpaceByName(spaceName);
		if(!defined(s))throw "No space with such name exists.";
		if(triggerElement.id == draggableElement.id)draggableElement = triggerElement;
		triggerElement.onmousedown = null;
	}
	var mouseMove = function(ev)
	{
		ev = ev || window.event;
		var target = ev.target || ev.srcElement;
		if(isMouseDown && defined(dragObject))
		{
			if(ev.stopPropagation)ev.stopPropagation();
			else ev.cancelBubble = true;
			var currentMousePosition = coords(ev);
			var s = getSpaceByName(dragObject.getAttribute(SPACE_NAME_ATTRIBUTE));
			if(s.top > 0)dragObject.style.top = s.top+"px";// VLAD: limiting here (if set)
			else
			{
				if(dragObject.getAttribute(MOVE_COPY_ATTRIBUTE) == "true")dragObject.style.top = (currentMousePosition.y)+"px";
				else dragObject.style.top = (currentMousePosition.y - mouseOffset.y - s.padding)+"px";
			}
			if(s.left > 0)dragObject.style.left = s.left+"px";// VLAD: limiting again (if set)
			else dragObject.style.left = (currentMousePosition.x - mouseOffset.x - s.padding)+"px";
			var d = target;
			if(defined(s.targetAttr) && s.targetAttr.length > 0)d = par(target,s.targetAttr);
			if(isMouseDown != mouseState)
			{
				dragObject.style.position = "absolute";// VLAD: this has to be set here, not in initialization part
				if(defined(s.onStart))s.onStart(getEl(s.draggingElementId),dragObject);
				dragObject.style.display = "block";
			}
			if(((defined(d) && d.id != "") || dragObject.getAttribute(MOVE_COPY_ATTRIBUTE) == "true") && defined(s.onDrag))
				s.onDrag(d,currentMousePosition);
			mouseState = isMouseDown;
			return false;
		}
		else return true;
	}
	var mouseDown = function(ev)
	{
		if(defined(dragObject))
		{
			mouseState = false;
			isMouseDown = true;
			return false;
		}
		else return true;
	}
	var mouseUp = function(ev)
	{
		mouseState = isMouseDown = false;
		if(defined(dragObject))
		{
			var s = getSpaceByName(dragObject.getAttribute(SPACE_NAME_ATTRIBUTE));
			if(dragObject.getAttribute(MOVE_COPY_ATTRIBUTE) == "true")document.body.removeChild(dragObject);
			dragObject = null;
			if(defined(s.onDrop))s.onDrop();
			return false;
		}
		else return true;
	}
	var getSpaceByName = function(name)
	{
		for(var i in spaces)if(spaces[i].name == name)return spaces[i];
		return null;
	}
	var getMouseOffset = function(target,ev)
	{
		ev = ev || window.event;
		var docPos = bounds(target);
		var mousePos = coords(ev);
		return {x:mousePos.x - docPos.x, y:mousePos.y - docPos.y};
	}
};
CodeEffects.Tools.FileUploadContext = function()
{
	// There are 2 pages: frame container (host) and upload control container (uploader)
	var
		ATTR_START = "attrFileStartDel",
		ATTR_SUCCESS = "attrFileErrorDel",
		ATTR_ERROR = "attrFileSuccessDel";
	// The host calls this method
	this.Init = function(onStart,onSuccess,onError)
	{
		document[ATTR_START] = onStart;
		document[ATTR_SUCCESS] = onSuccess;
		document[ATTR_ERROR] = onError;
	}
	// The uploader calls this when it's about to begin to upload the file
	this.Started = function(){if(parent.document[ATTR_START])parent.document[ATTR_START]();}
	// The uploader calls this if the upload finishes successfuly
	this.Succeeded = function(file){parent.document[ATTR_SUCCESS](file);}
	// The uploader calls this if the upload errores
	this.Errored = function(message){parent.document[ATTR_ERROR](message);}
};