// "child elements" for the Control class

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

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

	this.forceX='0';

	this.autoApplyUpdateDelay=0.25;

	this.defaults=this.getDefaults();
}

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

	var defX=px2mm($('pageContainer').scrollLeft);
	var defY=px2mm($('pageContainer').scrollTop);

	/////////////// OBJECT POSITION AND DIMENSIONS ////////////////////////////
	this.attributes.Xmm=(attributes.Xmm?attributes.Xmm:defX);
	this.attributes.Ymm=(attributes.Ymm?attributes.Ymm:defY);
	this.attributes.X=mm2px(this.attributes.Xmm);
	this.attributes.Y=mm2px(this.attributes.Xmm);

	this.attributes.fixed=(attributes.fixed?attributes.fixed:this.defaults.fixed);
	this.attributes.layer=(attributes.layer?attributes.layer:this.defaults.layer);

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

	this.attributes.block=true; // forced to true, always
	// 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_newPage.prototype.create=function (){
	if(this.preview==null)
		this.preview = CloneTemplates['_control_newPage'].createClone(this.parent.page);

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


	if(this.attributesSelector==null)
		this.attributesSelector = CloneTemplates['_control_newPage_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_newPage.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_newPage.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_newPage.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_newPage.prototype.getDescription=function (){
	return "new page";
}

// - 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_newPage.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 'Xmm':
			// called when manually setting the Xmm of the object

			value=0;	// force the Xmm to stay at 0, Xmm is ignored by the output plugins anyway.
			this.attributes.Xmm=value;
			this.attributes.X=mm2px(value);
		break;
		case 'Ymm':
			// called when manually setting the Ymm of the object

			this.attributes.Ymm=value;
			this.attributes.Y=mm2px(value);

			// add new pages to this document if needed
		    if(this.attributes.Y>=(grid._heap['pageH']*grid._heap['pages'])){
				grid.expandPageRange(this.attributes.X,this.attributes.Y);
		    }
		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 'fixed':
			this.attributes.fixed=(value==null?false:true);

			if(this.attributes.fixed){
				this.attributes.Xmm=0;
				this.attributes.Ymm=0;
				this.attributes.X=0;
				this.attributes.Y=0;

				disableElement(this.controls.Xmm,true);
				disableElement(this.controls.Ymm,true);

				this.attributes.layer=2;

				disableElement(this.controls.layer,true);

				this.parent.staticPage.appendChild(this.preview);

				this.attributes.orderIndex=(distanceToParent(this.preview)+1);
			}else{
				disableElement(this.controls.Xmm,false);
				disableElement(this.controls.Ymm,false);

				disableElement(this.controls.layer,false);

				this.parent.page.appendChild(this.preview);

				this.attributes.orderIndex=-1;
			}

			this.parent._updateAttribtues({	Xmm:this.attributes.Xmm,
											Ymm:this.attributes.Ymm,
											X:this.attributes.X,
											Y:this.attributes.Y,
											layer:this.attributes.layer,
											orderIndex:this.attributes.orderIndex
										},this.controls);

		break;

		default:
		break;
	}


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

_control_newPage.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={};

	previewStyle.clear="both";

	previewStyle.position=(this.attributes.fixed?'static':'absolute');

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

	style.width=this.parent.pageDimensions['width']+'px';

	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_newPage.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_newPage.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_newPage.prototype.startDrag=function (realDragging){
	if(realDragging){
		this.parent.eventScheduler.schedule('child.onDrag',this.onDrag.bind(this),0.1);
	}else{

	}
}

// endDrag :
_control_newPage.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_newPage.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='0';
			this.attributes.Ymm=this.parent._heap['Ymm'];
		}else{
			this.attributes.Xmm=px2mm('0',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({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_newPage.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_newPage']=new _cloneFactory(
											'_control_newPage_.:id:.',
											{
												'id':	{	type:'int',	start:'1'	}
											},
											{
												bulkEval:true
											}
										);

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