/*
 * Control class
 * 	it defines a "control" which can be
 * 		text(a label)
 * 		image
 * 		group
 * 		....
 *
 * It controls and manages the underlying childs, creating them, and managing events for them (and/or passing events to them).
 * Each defined Control get added to Controls, a global class to keep track of every defined control.
 *
 * attributes, if not handeld by the main Control class will be sent over to the child control,
 * 	so the attributes may very well be child specific.
 *
 * extraParams is only used by specialObject. It will be ignored otherwise
 *
 * pageDimensions are the dimensions of the "drawing page"
 *
 * */
function Control( type, attributes , extraParams){// constructor for the main class
	if(this.name==null || !this.name )	{
		this.name='Control';
	}

	if(attributes==null)attributes={};

	if(!attributes.dontFocus){
		// clear previosly caputured focus
		var f=Controls.getGlobal('focus');
		if(f && !f.disableClickEvent){
			f.clearFocus();
		}
	}

	// internal variables, used pretty often (internally)
	this._heap=new Array();
	this.attributes={};
	this.initialize(attributes);

	// theese are pretty much static
	this.page=$('documentContainer');
	this.staticPage=$('documentContainer_statics');
	if(!this.staticPage)
		this.staticPage=this.page;

	this.pageDimensions=Element.getDimensions(this.page);

	this.page.style.left='0';
	this.page.style.right='0';
	this.page.style.position='relative';

	this.pagePosition={left:this.page.getStyle('left'),right:this.page.getStyle('right')};

	// 4percent is a normalized float [0..1]
	this.internalStatus={status:'loading',percent:0.0};

	this.settings={};
	this.settings.removeHndTimeout=6000; //seconds

	// the attributesContainer is the container where the attributes panels are dropped.
	this.attributesContainer=$('attributesContainer');

	this.type=type;
	this.version='1.0.0.0';

	this.autocancel=false;// if true, it will behave as a disabled control, and will call remove() on itself on th first ocasion

	//each control has its own event scheduler, used both by the child, and the parent Control to delay certain events.
	this.eventScheduler=new _eventScheduler();

	// keep this value. if dontCrate is true, then we can assume that the element is already created and we dont need to clone it.
	this.attributes._objectName=(attributes._objectName?attributes._objectName:type);
	this.attributes.dontCreate=attributes.dontCreate;
	this.attributes.useDefaults=!attributes._ignoreDefaults;
	this.attributes.type=type;

	switch(type){
		case 'text':
			this.child=new _control_text(this);
			if(!this.child) return false;

			this.child.initialize(attributes);
		break;
		case 'group':
			this.child=new _control_group(this);
			if(!this.child) return false;

			this.child.initialize(attributes);
		break;
		case 'image':
			this.child=new _control_image(this);
			if(!this.child) return false;

			this.child.initialize(attributes);
		break;
		case 'horizontalLine':
			this.child=new _control_horizontalLine(this);
			if(!this.child) return false;

			this.child.initialize(attributes);
		break;
		case 'verticalLine':
			this.child=new _control_verticalLine(this);
			if(!this.child) return false;

			this.child.initialize(attributes);
		break;
		case 'rectangle':
			this.child=new _control_rectangle(this);
			if(!this.child) return false;

			this.child.initialize(attributes);
		break;
		case 'newLine':
			this.child=new _control_newLine(this);
			if(!this.child) return false;

			this.child.initialize(attributes);
		break;
		case 'newPage':
			this.child=new _control_newPage(this);
			if(!this.child) return false;

			this.child.initialize(attributes);
		break;

		case 'specialObject':
			this.child=new _control_specialObject(this,extraParams);
			if(!this.child) return false;

			this.child.initialize(attributes);
		break;

		default:
		return false;
		break;
	}

	// the dild requested to be autodestroyed
	if(this.child.autodestroy) {
		if(this.autodestroy){ // if we defined a custom autodestroy function, then call it.
			this.autodestroy(type,this.attributes,attributes,extraParams);
		}

		this.destroy();
		return false;
	}

	if(attributes.preview)this.child.preview=$(attributes.preview);
	if(attributes.object)this.child.object=$(attributes.object);
	if(attributes.attributesSelector)this.child.attributesSelector=$(attributes.attributesSelector);

	// create the actual child, from now on this.child will be a valid initialized element, and it is attached to the DOM
	if(!this.attributes.dontCreate){
		this.child.create();
	}else{
		if(this.child.fastCreate)this.child.fastCreate();
			else this.masterMethods_fastCreate();

	}

	// install handlers for the child, and initialize the form
	for(var i in this.child.controls){
		//***  attach event handlers for the child, routed thru the parent class (thru THIS object)  ***//

		this.event_change_direct = this.onChange.bindAsEventListener(this,i,'direct');
		this.event_keyup_longdelay = this.event_keyUp.bindAsEventListener(this,i);

		this.event_focus = this.setFocus.bindAsEventListener(this,i);
		this.event_blur = this.scheduleClearFocus.bindAsEventListener(this,i);

		// change, and keyup will reflect the changes made in the attributes panel to the actual object
		Event.observe(this.child.controls[i],'change', this.event_change_direct);
		Event.observe(this.child.controls[i],'keyup', this.event_keyup_longdelay);

		// blur & focus are used to "focus" the controlled child, when editing his propreties
		Event.observe(this.child.controls[i],'focus', this.event_focus);
		Event.observe(this.child.controls[i],'blur' , this.event_blur);

		if(!this.attributes.dontCreate){
			// simulate an onchange, this will initialize the attribute control, and internally save the selected values.
			this.onChange(null,i,'queue');
		}
	}

	// create the Control object. It will attach global events and handlers
	this.create();

	if(!attributes.dontFocus){
		// when creating we do not have the focus, do we?
		this.clearFocus('fast');	// somehow IE generates an error when calling setFocus directly... this seems to be the only workaround.

		if(!attributes._hidePreview){
			eventScheduler.schedule('setFocus',this.setFocus.bind(this),0.5);
		}
	}

	if(!this.attributes.dontCreate){
		initTooltips(false,this.child.attributesSelector); // should this be called for every control, or for all controls in one place?
	}

	if(attributes._hidePreview){
		this.eventScheduler.cancel('updateObject');

		this.child.hidden=true;
		this.child.preview.hide();
	}

	return this;
}


// general initialiation function. Called by the contructor.
Control.prototype.initialize=function (attributes){
	return true;
}

//called when autodestroying. basically when the cild requested to be revoved
//	extraParams is only available when a specialObject is in effect
Control.prototype.destroy=function (){

	//***  remove event handlers for the child  ***//
	for(var i in this.child.controls){
		Event.stopObserving(this.child.controls[i],'change', this.event_change_direct);
		Event.stopObserving(this.child.controls[i],'keyup', this.event_keyup_longdelay);

		// blur & focus are used to "focus" the controlled child, when editing his propreties
		Event.stopObserving(this.child.controls[i],'focus', this.event_focus);
		Event.stopObserving(this.child.controls[i],'blur' , this.event_blur);
	}

	var object=this.child.preview;

	if(this._heap['events']){
		if(this._heap['events']['click'])		Event.stopObserving(object, 'click',	this._heap['events']['click']);
		if(this._heap['events']['mouseOver'])	Event.stopObserving(object, 'mouseover',this._heap['events']['mouseOver']);
		if(this._heap['events']['mouseOut'])	Event.stopObserving(object, 'mouseout',	this._heap['events']['mouseOut']);
	}

	this.status({status:'dying',percent:0.2});	// set the progress status

	if(this.child && this.child.destroy)	this.child.destroy();

	this.child=null;

	this.eventScheduler.destroy();
	this.eventScheduler=null;

	this.page=null;
	this.pagePosition=null;
	this.pageDimensions=null;
	this.attributesContainer=null;
	this.settings=null;

	Controls.setGlobal('focus',null);
	Controls.setGlobal('formFocus',null);
	this.status({status:'dead',percent:1});	// set the progress status
}


// create and attach the Control to the DOM. Also bind events.
Control.prototype.create=function (){
	// initialize event tables
	this.status({substatus:'create',percent:0.2});	// set the progress status

	this._heap['events']=new Array();
	this._heap['events']['click']=this._Click.bindAsEventListener(this);
	this._heap['events']['mouseOver']=this._mouseOver.bindAsEventListener(this);
	this._heap['events']['mouseOut']=this._mouseOut.bindAsEventListener(this);

	// global functions, but may get dinamically changed internally
	this._heap['global']=new Array();
	this._heap['global']['return_false']=return_false.bindAsEventListener(this);

	// setup inital reported coords
	// seems like initializing them breaks the inital coords for the group control
	this._heap['x']=this.attributes.X;
	this._heap['y']=this.attributes.Y;

	// intercept events on the child element
	var object=this.child.preview;
	Event.observe(object, 'click',		this._heap['events']['click']);
	Event.observe(object, 'mouseover',	this._heap['events']['mouseOver']);
	Event.observe(object, 'mouseout',	this._heap['events']['mouseOut']);


	this._heap['draggable']=null;

	// "steal" the attributes selector from the child.
	this.attributesSelector=this.child.attributesSelector;

	// add this Control to the global list of Controls
	Controls.add(this);

	if(!this.attributes.dontCreate){
		this.reposition({Xmm:this.child.attributes.Xmm,Ymm:this.child.attributes.Ymm});
	}

	this.status({substatus:'',percent:0.75});	// set the progress status

	// if we do not get idle in 20 seconds, then force it as idle...something is wrong with the children
	// 	in this case if he does not mark us as idle
	// this.eventScheduler.schedule('idle',function(){this.status({status:'idle',percent:1})}.bind(this),20);
}


// get/set status function
Control.prototype.status=function (newAttributes){
	if(newAttributes){
		if(newAttributes.status)
			this.internalStatus.status=newAttributes.status;

		if(newAttributes.substatus)
			this.internalStatus.substatus=newAttributes.substatus;

		// percent is a normalized float [0..1]
		if(newAttributes.percent)
			this.internalStatus.percent=newAttributes.percent;
	}

	if(this.internalStatus.status!='idle'){
		updatePageStatus({text:'Loading item(s)',status:'warning'});
	}

	return this.internalStatus;
}


// mouseOver event . Grab focus, prepare to be dragged.
Control.prototype._Click=function (event){
	// pressing ctrl will prevent events from occuring
	if(event.ctrlKey) return false;

	this.disableClickEvent=true;
	this.setFocus();
}


// mouseOver event . Grab focus, prepare to be dragged.
Control.prototype._mouseOver=function (event){
	var smartSelector=Controls.getGlobal('SmartSelector');
	if(smartSelector){
		smartSelector._SmartSelector_mouseOver(this);
		return false;
	}
}


// mouseOut event . Free the focus, someoneelse will be dragged.
Control.prototype._mouseOut=function (event){
	var smartSelector=Controls.getGlobal('SmartSelector');
	if(smartSelector){
		smartSelector._SmartSelector_mouseOut(this);
		return false;
	}

	// pressing ctrl will prevent events from occuring
	if(event.ctrlKey) return false;

	this.disableClickEvent=false;
	if(this._heap['draggable']!=null){
		// the scheduler is used because when dragging small elements, the mouseOut event occurs pretty often,
		// 	but very fast-linked with a mouseOver event(so basically we would release focus, just to grab it right back).
		// 	Now we wait some time before automatically releasing focus.

		this._heap['removeHndScheduled']=true;
		this.eventScheduler.schedule('removeHnd',this.clearFocus.bind(this),this.settings.removeHndTimeout);
	}
}


// called on a "real" mouseOver event. We grab the focus, the grid, and create the draggable control.
// we also notify the child that the drag has started, and grab his attributes.
Control.prototype.setFocus=function (event,who){
	var smartSelector=Controls.getGlobal('SmartSelector');
	if(smartSelector){
		smartSelector._SmartSelector_click(this);
		return false;
	}

	var f=Controls.getGlobal('focus');
	if(f && f!=this) f.clearFocus();

	Controls.setGlobal('focus',this);
	Controls.setGlobal('formFocus',who);

	this.scheduleClearFocus();

	// avoid setting focus on self:)
	if(f && f==this) return;

	if(this._heap['draggable']==null){
		if(this.child.getDimensions){
			this.child.getDimensions();
			grid.focus({
						dynamicContent_debug:'yes',
						dynamicContent:function(){return this.child.getDimensions()}.bind(this),
						offsetX:this.child.attributes.X,
						offsetY:this.child.attributes.Y
						});
		}

		var object=this.child.preview;

		if(this.child.attributes.fixed){
			this.child.attributes.orderIndex=(distanceToParent(this.child.preview)+1);
		}

		this.child.fillAttributes();

		this.highlight('draggable_ready',true);
		this.highlight('draggable_standby',false);
		this.child.startDrag();

		if(!this.child.attributes.fixed){
			this._heap['draggable']=  new Draggable(
				object,
				{
					 snap: function(x,y) {
			 			var ret=grid.onDrag(x,y,this.pageDimensions.width-this.child.objectDimensions.width,this.pageDimensions.height, this);
			 			// avoid changind coords when objects is already fixed...
			 			if(this.child.attributes.fixed) return [0,0];

			 			if(this.child.forceY)
			 				ret.y=this.child.forceY;

			 			if(this.child.forceX)
			 				ret.x=this.child.forceX;

					    this._heap['x']=ret.x;
					    this._heap['y']=ret.y;

					    this._heap['Xmm']=ret.Xmm;
					    this._heap['Ymm']=ret.Ymm;
					    return [ret.x,ret.y];
				    }.bind(this),
					onStart:this.onDragStart.bind(this),
					onEnd:this.onDragEnd.bind(this),
//					scroll:$('pageContainer')
				}
			);
		}else if(this.child.attributes.fixed){

			// manually call the onDragStart event, so the child can prepare also
			this.onDragStart();
		}

		$(this.child.attributesSelector).show();

		return true;
	}
	return false;
}


// called on a "real" mouseOut event. We release the focus, the grid, and the draggable control.
// we also notify the child that the drag has finished.
Control.prototype.clearFocus=function (param){
	// controls cannot lose focus while in "smartSelect" mode
	var smartSelector=Controls.getGlobal('SmartSelector');
	if( smartSelector ){
		return false;
	}

	if(this._heap){
		if(param!='fast'){
			this.child.endDrag();

			this.highlight('draggable_ready',false);
			this.highlight('draggable_standby',true);

			if(this._heap['draggable']){
				this._heap['draggable'].destroy();
				this._heap['draggable']=null;
			}

			this.eventScheduler.fireAll();

			if(typeof(variableEditor)!='undefined' && variableEditor!=null) {
				variableEditor.close(true);
			}
		}
	}

	this._heap['removeHndScheduled']=false;

	if(param!='fast'){
		closeColorPicker();
		hideMinibrowser();
		Controls.setGlobal('focus',null);
		Controls.setGlobal('formFocus',null);

		grid.unfocus();

		/*
		 * Due to a weird bug in DTM, i hide ALL attribute containers, because some selector kep reimaining visible when switching focus, or when clicking buttons
		 *
		 * One can either hide
		 * 	- just the current selector
		 * 			$(this.child.attributesSelector).hide();
		 * 	- hide all selectors
		 * 			$(this.attributesContainer).down("div").hide();
		 * 			$(this.attributesContainer).down("div").siblings().each(function (e){e.hide()});
		 * */

		$(this.attributesContainer).down("div").hide();
		$(this.attributesContainer).down("div").siblings().each(function (e){e.hide()});
	}

	if(this.child.attributes.fixed){
		// manually call the onDragEnd event, so the child can also release the focus
		this.onDragEnd();
	}

	Controls.setGlobal('targetInput',null);

	return true;
}


Control.prototype.scheduleClearFocus=function (event,who){

	// scheduleClearFocus is called when blurring() elements. When bluring try to simultate the onchange so that any kind of valiadations are done now.
	this.onChange(event,null,'shortdelay');

	this._heap['removeHndScheduled']=true;
	this.eventScheduler.schedule('removeHnd',this.clearFocus.bind(this),this.settings.removeHndTimeout);
}

/*
 * reposition the child into the page. Called during and after drag, and after the text attribute had changed.
 * params.x & y are ued by group controls to handle the childs movement
 *
 * params.Xmm & Ymm are used by child.updateObject, so tht we will not recalculate the Xmm & Ymm positioning, and instead use the internal one
 */
Control.prototype.reposition=function (params,updateChild){
	if(params==null)params={};

	var Xmm=(this._heap['Xmm']?this._heap['Xmm']:params.Xmm);
	var Ymm=(this._heap['Ymm']?this._heap['Ymm']:params.Ymm);

	var x=(params.x==null?mm2px(this.child.attributes.Xmm):params.x);
	var y=(params.y==null?mm2px(this.child.attributes.Ymm):params.y);

	if(!Xmm && !Ymm){	// if Xmm & Ymm are not set untill now, then calculate them
		Xmm=px2mm(x,true,2);
		Ymm=px2mm(y,true,2);
	}

	if(this.child.forceY) {
		this._heap['Ymm']=this.child.forceY;
		Ymm=this.child.forceY;
		y=this.child.forceY;
	}
	if(this.child.forceX) {
		this._heap['Xmm']=this.child.forceX;
		Xmm=this.child.forceX;
		x=this.child.forceX;
	}

	// make the real control repositioning
	this.child.preview.setStyle({'left':x+'px', 'top':y+'px'});

	this.child.attributes.Xmm=Xmm;
	this.child.attributes.Ymm=Ymm;
	if(this.child.controls.Xmm) $(this.child.controls.Xmm).value=Xmm;
	if(this.child.controls.Ymm) $(this.child.controls.Ymm).value=Ymm;

	this.child.attributes.X=x;
	this.child.attributes.Y=y;

	this._heap['x']=x;
	this._heap['y']=y;

	this._heap['Xmm']=null;
	this._heap['Ymm']=null;

	if(updateChild && this.child){
		if(this.child.controls.Xmm) $(this.child.controls.Xmm).value=Xmm;
		if(this.child.controls.Ymm) $(this.child.controls.Ymm).value=Ymm;

		this.onChange(null,'Xmm','delay');
		this.onChange(null,'Ymm','delay');
	}
}


// highlights the child(s) .
// Basicallly adds "cls" to the child attributes.
// If toggle is not specified, then the class will be automatically toggled
Control.prototype.highlight=function(cls,toggle){
	var elements=this.child.preview;

	if(toggle==null){
		$(elements).toggleClassName(cls);
	}else{
		if(toggle){
			$(elements).addClassName(cls);
		}else{
			$(elements).removeClassName(cls);
		}
	}
}


// an attribute was changed, send the event to the child after a delay(so not all changes are immediatly reflected.
// attribute: the attribute name from the child propreties.(automatically determined during the event)
// action: direct: will propagate the event to the child
// delay, shortdelay will wait a period before propagating
Control.prototype.onChange=function (event,attribute,action){
	if(this._heap['removeHndScheduled']){
		//reschedule
		this.eventScheduler.schedule('removeHnd',this.clearFocus.bind(this),this.settings.removeHndTimeout);
	}

	switch(action){
		case 'direct':
			// this item was altered
			Controls.setGlobal('pageChanged',2);
			$('button_fastSaveDocument').setStyle({'fontWeight':'bold'});

			this.child.onChange(event,attribute);

			// flush queue was requested
			if(attribute==null && this._heap['onChange_queue']){
				for(var i in this._heap['onChange_queue']){
					if(this._heap['onChange_queue'][i]){
						this.child.onChange(event,i,true);
					}
				}

				// queue is flushed now. Mark it as 'empty'
				this._heap['onChange_queue']=null;
			}
		break;
		case 'queue':
			if(this._heap['onChange_queue']==null)this._heap['onChange_queue']={};
			this._heap['onChange_queue'][attribute]=(this._heap['onChange_queue'][attribute]?false:true);
			this.eventScheduler.schedule('onChange',function(){this.onChange(null,null,'direct');}.bind(this),0.5);
		break;
		case 'shortdelay':
			this.eventScheduler.schedule('onChange',function(){this.onChange(null,attribute,'direct');}.bind(this),0.25);
		break;
		case 'longdelay':
			this.eventScheduler.schedule('onChange',function(){this.onChange(null,attribute,'direct');}.bind(this),0.75);
		break;

		default:
		case 'delay':
			this.eventScheduler.schedule('onChange',function(){this.onChange(null,attribute,'direct');}.bind(this),0.5);
		break;
	}
}


// internally called when real dragging starts.
// we disable the posibility to select text from the document during the drag.
Control.prototype.onDragStart=function (){
	Controls.setGlobal('pageChanged',2);
	$('button_fastSaveDocument').setStyle({'fontWeight':'bold'});

	this.child.startDrag(true);
	this.dragging=true;
	window.document.body.onselectstart=this._heap['global']['return_false'];

	this.eventScheduler.cancel('removeHnd');
	this._heap['removeHndScheduled']=false;
}


// internally called when real dragging ends.
// we restore settings like they were before calling .onDragStart()
Control.prototype.onDragEnd=function (){
	this.child.endDrag(true);
	this.dragging=false;
	window.document.body.onselectstart=null;

	this._heap['removeHndScheduled']=true;
	this.eventScheduler.schedule('removeHnd',this.clearFocus.bind(this),this.settings.removeHndTimeout);
}


// used by "group" controls, to display a short description of this control. Defaults to the object ID
Control.prototype.getDescription=function (){
	if(this.child.getDescription)
		return this.child.getDescription();

	return this.child.object.identify();
}


// used by the zoom facility to notify when the page changed its settings, and we should recalculate our internal data
Control.prototype.onPageChanged=function (){
	if(this.child.onPageChanged)
		this.child.onPageChanged();

	this.pageDimensions=Element.getDimensions(this.page);

	return true;
}


// used by the snap/zoom facility to notify when the page changed its settings, and we should recalculate our internal data
Control.prototype.onSnapChanged=function (params){
	if(this.child.onSnapChanged)
		this.child.onSnapChanged(params);

	return true;
}


// callback for the childs... ease-of-use, so i do not reapeat the same code for every child... but i also need to let every child override the default filling mode when needed
Control.prototype._updateAttribtues=function (attributes, controls){
	if(attributes.Xmm!=null && attributes.Ymm!=null && this.pageDimensions && this.child && this.child.objectDimensions){
		var ret=grid.onDrag(
					mm2px(attributes.Xmm),
					mm2px(attributes.Ymm),
					this.pageDimensions.width-this.child.objectDimensions.width,
					this.pageDimensions.height-this.child.objectDimensions.height);

		if(ret.Xmm!=null && ret.Ymm!=null){
			attributes.Xmm = ret.Xmm;
			attributes.Ymm = ret.Ymm;
		}
	}


	var changed=false;
	for(var i in attributes){
		if(controls[i] && $F(controls[i])!=attributes[i]){
			if($(controls[i]).type==null)$(controls[i]).type=$(controls[i]).nodeName;

			switch($(controls[i]).type){
				case 'text':
					$(controls[i]).value=attributes[i];
				break;
				case 'textarea':
					$(controls[i]).value=attributes[i];
				break;
				case 'checkbox':
					$(controls[i]).checked=attributes[i];
				break;
				case 'select-one':
					$(controls[i]).value=attributes[i];
				break;
				// status-boxes
				case 'DIV':
					$(controls[i]).update(attributes[i]);
				break;
				default:
					$(controls[i]).value=attributes[i];
				break
			}
			changed=true;
		}
	}
	return changed;
}


Control.prototype.event_keyUp=function (event,who){
	if(who=='Xmm' || who=='Ymm') {
		this.eventScheduler.cancel('child.onDrag');
		this.onChange(null,who,'longdelay');

		this._heap['Xmm']=null;
		this._heap['Ymm']=null;
	}
}

// the masterMethods are used instead of th children methods, if the chold does notprovide them

// FAST create the control, the attributeSelector, and attach them to the DOM
Control.prototype.masterMethods_fastCreate=function (){
	// standard initializing
	this.child.controls=this.child.getAttributesControls();
	this.child.fillAttributes();

	// get the dimensions, and save them
	this.child.getDimensions();
}


/************************************************************************************/
// global functions used by the Control class
return_false=function (){
	return false;
}

/*
 * Calculate the distance between this element and the distance from it to the parent node
 *
 * Used by lots of Controls
 * */
function distanceToParent(node){
	return $(node).previousSiblings().length;
}

/*
 * Used by 4borders controls...
 * This function works for linear-mode setting
 * */
function changePreviewBorders_linear(control,name,element){
	value=$F(element);
	$N(control+'['+name+'_top]').checked=value;
	$N(control+'['+name+'_bottom]').checked=value;
	$N(control+'['+name+'_left]').checked=value;
	$N(control+'['+name+'_right]').checked=value;

	setPreviewBorder($(element).up('table'),'top',value);
	setPreviewBorder($(element).up('table'),'bottom',value);
	setPreviewBorder($(element).up('table'),'left',value);
	setPreviewBorder($(element).up('table'),'right',value);

	notifyChangedElement(name+'_top','queue');
	notifyChangedElement(name+'_bottom','queue');
	notifyChangedElement(name+'_left','queue');
	notifyChangedElement(name+'_right','queue');
}

/*
 * Used by 4borders controls...
 * This function works for linear-mode setting
 * */
function changePreviewBorders(control,name,element){
	value=$F(element);
	$N(control+'['+name+'][top]').checked=value;
	$N(control+'['+name+'][bottom]').checked=value;
	$N(control+'['+name+'][left]').checked=value;
	$N(control+'['+name+'][right]').checked=value;

	setPreviewBorder($(element).up('table'),'top',value);
	setPreviewBorder($(element).up('table'),'bottom',value);
	setPreviewBorder($(element).up('table'),'left',value);
	setPreviewBorder($(element).up('table'),'right',value);

	notifyChangedElement(name+'_top','queue');
	notifyChangedElement(name+'_bottom','queue');
	notifyChangedElement(name+'_left','queue');
	notifyChangedElement(name+'_right','queue');
}

/*
 * Sets the preview controls border..
 * used by the "border" control (selector.4borders_linear.tpl)
 * */
function setPreviewBorder(control, direction, active){
	if(control){
		var border='';
		switch(direction){
			case 'top':
				border='borderTop';
			break;
			case 'bottom':
				border='borderBottom';
			break;
			case 'left':
				border='borderLeft';
			break;
			case 'right':
				border='borderRight';
			break;

			default:
				border='default';
			break;
		}

		if(active){
			$(control).style[border]='1px solid #78A3CE';
		}else{
			$(control).style[border]='1px dashed #dedede';
		}
	}
}


/*------------------------------------------------------------------------------------*/
// theese are used by every defined child.
var CloneTemplates=new Array();