// "child elements" for the Control class

// the newLine control.
// define events, attributes, and methods to handle a "newLine"
function _control_newLine( parent ){// constructor for the main class
	if(this.name==null || !this.name )	{
		this.name='_control_newLine';
	}

	this.parent=parent;
	this.version='1.0.0.0';
	this._heap=new Array();
	this.attributes={};
	this.defaultAttributes={};
	this.controls={};

	this.autoApplyUpdateDelay=0.25;

	this.defaults=this.getDefaults();
}

// initialize the control with "default" pre-specified values
_control_newLine.prototype.initialize=function (attributes){
	if(attributes==null)attributes={};

	/////////////// OBJECT POSITION AND DIMENSIONS ////////////////////////////
	this.attributes.Hmm=(attributes.Hmm?attributes.Hmm:this.defaults.Hmm);
	this.attributes.H=mm2px(this.attributes.Hmm);

	this.attributes.repeatable=(attributes.repeatable?attributes.repeatable:this.defaults.repeatable);

	this.attributes.orderIndex=(attributes.orderIndex?attributes.orderIndex:this.defaults.orderIndex);

	// this object will always be "fixed" so we ccan assume the layer is always 2, and that is fixed
	this.attributes.layer=2;
	this.attributes.fixed=true;
	this.attributes.block=true;
	this.attributes.assignedGroup=(attributes.assignedGroup?attributes.assignedGroup:this.defaults.assignedGroup);


	// save the default attrbiutes, so they may get re-used
	//  when invalid propreties are met, and we need to do some kind of rollback
	this.defaultAttributes=Object.clone(this.attributes);

	return true;
}

// create the control, the attributeSelector, and attach them to the DOM
_control_newLine.prototype.create=function (){
	if(this.preview==null)
		this.preview = CloneTemplates['_control_newLine'].createClone(this.parent.page);

	if(this.object==null)
		this.object= $(this.preview).select("[id='object']").first();


	if(this.attributesSelector==null)
		this.attributesSelector = CloneTemplates['_control_newLine_attributes'].createClone(this.parent.attributesContainer);

	// standard initializing
	this.controls=this.getAttributesControls();
	this.fillAttributes();

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

	// move this control to the statics group - this will always be a static object
	this.parent.staticPage.appendChild(this.preview);

	if(this.attributes.orderIndex==-1){
		this.attributes.orderIndex=(distanceToParent(this.preview)+1);
		this.fillAttributes({orderIndex:this.attributes.orderIndex});
	}
}


// FAST create the control, the attributeSelector, and attach them to the DOM
_control_newLine.prototype.fastCreate=function (){
	if(this.object==null)
		this.object= $(this.preview).select("[id='object']").first();

	// standard initializing
	this.controls=this.getAttributesControls();
	this.fillAttributes();

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

	var elements=$(this.attributesSelector).select("[id='objectStatus']");

	this.parent.status({status:'idle',percent:1});
}


_control_newLine.prototype.destroy=function (){
	if(this.controls){
		for(var i in this.controls){
			if(!Object.isFunction(this.controls[i])){
				this.controls[i]=null;
			}
		}
	}

	if(this.preview)
		$(this.preview).remove();

	if(this.attributesSelector)
		$(this.attributesSelector).remove();

	this._heap=null;
	this.attributes=null;
	this.object=null;
	this.preview=null;
	this.attributesSelector=null;
	this.defaultAttributes=null;
	this.parent=null;
	this.controls=null;
}

_control_newLine.prototype.getDimensions=function (){
	// calculate the object dimensions. we do a caclulation hare, and another in the onChange event
	this.objectDimensions=Element.getDimensions(this.object);
	return this.objectDimensions;
}

// used by "group" controls, to display a short description of this control
_control_newLine.prototype.getDescription=function (){
	return "new line";
}

// - an attribute has changed, reflect this in the internal data, and in the viewed item
// - some attributes are checked separately, when needing to do extra validation,
//     or the input data is non-standard (for example when $F cannot handle it)
_control_newLine.prototype.onChange=function (event,attribute,disableUpdate){
	if(attribute==null) return;
	var disableUpdate=false;

	var element=this.controls[attribute];
	var initialValue=this.attributes[attribute];

	value=$F(element);

	switch(attribute){
		/////////////// OBJECT POSITION AND DIMENSIONS ////////////////////////////
		case 'Hmm':
			this.attributes.Hmm=value;
			this.attributes.H=mm2px(value);
		break;

		case 'repeatable':
			this.attributes.repeatable=(value==null?false:true);
			this.hidden=($F('repeatable_edit_')? !this.attributes.repeatable: this.attributes.repeatable) ;
		break;

		case 'orderIndex':
			value=parseInt(value);
			if(isNaN(value))value=0;

			var newOrder=smartPlaceElement(this,value,this.attributes.orderIndex,this.parent.staticPage,true);

			if(newOrder!=$F(this.controls['orderIndex']))this.controls['orderIndex'].value=newOrder;	// update the input value if needed.

			this.attributes.orderIndex=newOrder;

			disableUpdate=true;
		break;

		case 'assignedGroup':
			this.attributes.assignedGroup=value;
		break;


		default:
		break;
	}

	if(!disableUpdate){
		this.updateObject();
		this.parent.reposition({Xmm:0, Ymm:0});
	}
	return true;
}

_control_newLine.prototype.updateObject=function (realCall,updateGrid){
	if(realCall!=true){
		this.parent.eventScheduler.schedule('updateObject',this.updateObject.bind(this,true,updateGrid),this.autoApplyUpdateDelay);
		return false;
	}

	this.parent.status({status:'update',percent:0.1});

	var style={};
	var previewStyle={};

	if(this.attributes.Hmm>0)style.height=mm2px(this.attributes.Hmm)+'px';

	previewStyle.clear="both";

	previewStyle.position='static';

	previewStyle.zIndex=parseInt(this.attributes.layer)+100;

	if(this.attributes.assignedGroup) {
		previewStyle.border = '1px dashed #008';
	}else {
		previewStyle.border = '';
	}


	this.object.setStyle(style);
	this.preview.setStyle(previewStyle);

	this.getDimensions();

	if(this.hidden){
		this.preview.hide();
		this.hidden=false;
	}else{
		this.preview.show();
	}
	this.parent.status({status:'idle',percent:1});
}

// return the internal attributes(you should rely on this, instead of the attributes in the attributesSelector!. They are keeped in sync anyway)
_control_newLine.prototype.getAttributes=function (){
	if(this.object==null) return false;
	return this.attributes;
}

// return a list of attribute controls (the actual inputs). Internally used to sync with the internal attributes list
_control_newLine.prototype.getAttributesControls=function (){
	var a;
	var elements;
	var subElement;
	var ret={};

	var attributes=this.getAttributes();
	var attributesSelector=this.attributesSelector;

	for(var i in attributes){
		a="[id='"+i+"']";
		elements=$(attributesSelector).select(a);

		if(elements){
			for(var j=0;j<elements.length;j++){
				subElement=elements[j];
				ret[i]=subElement;
			}
		}
	}

	return ret;
}

// startDrag:
_control_newLine.prototype.startDrag=function (realDragging){
	if(realDragging){
		this.parent.eventScheduler.schedule('child.onDrag',this.onDrag.bind(this),0.1);
	}else{

	}
}

// endDrag :
_control_newLine.prototype.endDrag=function (realDragging){
	if(!realDragging){
		this.parent.eventScheduler.cancel('child.onDrag');
	}else{
		this._heap['onDrag_timed']=null;
		this.parent.eventScheduler.schedule('child.onDrag',this.onDrag.bind(this,'deccelerate'),1);
	}
}

_control_newLine.prototype.onDrag=function (delay){
	if(this.parent._heap['x']!=null && this.parent._heap['y']!=null){
		if(this.parent._heap['Xmm'] && this.parent._heap['Ymm']){
			this.attributes.Xmm=this.parent._heap['Xmm'];
			this.attributes.Ymm=this.parent._heap['Ymm'];
		}else{
			this.attributes.Xmm=px2mm(this.parent._heap['x'],true,2);
			this.attributes.Ymm=px2mm(this.parent._heap['y'],true,2);
		}

		this.attributes.X=this.parent._heap['x'];
		this.attributes.Y=this.parent._heap['y'];

		var fillResponse=this.fillAttributes({Xmm:this.attributes.Xmm,Ymm:this.attributes.Ymm});
	}

	switch(delay){
		case 'deccelerate':
			this._heap['onDrag_timed']=(this._heap['onDrag_timed']?this._heap['onDrag_timed']:1);
			if(fillResponse && fillResponse.changed){
				this._heap['onDrag_timed']=Math.round(this._heap['onDrag_timed']*0.75);
			}else{
				// prevent this event from reoccuring
				break;
			}

			this._heap['onDrag_timed']=Math.max(this._heap['onDrag_timed'],0.25);
			this._heap['onDrag_timed']=Math.min(this._heap['onDrag_timed'],60);
			this.parent.eventScheduler.schedule('child.onDrag',this.onDrag.bind(this,'deccelerate'),this._heap['onDrag_timed']);
		break;
		case 'slow':
			this.parent.eventScheduler.schedule('child.onDrag',this.onDrag.bind(this,'slow'),2.5);
		break;
		default:
			this.parent.eventScheduler.schedule('child.onDrag',this.onDrag.bind(this),0.5);
		break;
	}
}

// sync the attributesSelector with the internal attributes (overwrite them)
_control_newLine.prototype.fillAttributes=function (attr){
	var controls=this.controls;
	var attributes=(attr?attr:this.attributes);
	var changed=false;

	changed=this.parent._updateAttribtues(attributes,controls);

	return {attributes:attributes,changed:changed};
}

///////////////////////////////////////////////////////////////////////////////////
// standard initalization for this class, performed on pageLoad ///////////////////

Event.observe(window, 'load', function() {
	CloneTemplates['_control_newLine']=new _cloneFactory(
											'_control_newLine_.:id:.',
											{
												'id':	{	type:'int',	start:'1'	}
											},
											{
												bulkEval:true
											}
										);

	CloneTemplates['_control_newLine_attributes']=new _cloneFactory(
											'_control_newLine_.:id:._attributes',
											{
												'id':	{	type:'int',	start:'1'	}
											},
											{
												bulkEval:true
											}
										);
});