if(!window.BN){
	window.BN={};
}

if(!BN.Has){
	BN.Has ={}
}

//BN.Has value must match file name;	
BN.Has.FormUtil = true;


//Encloses and protects $, and all other defined symbols. attachement to BN object inside is link to outer world.
(function($){
var FormUtil = {};
// input group selector should not be an id or name and templateSelector should not contain group selector
// Only numbers in input ids and names should be at the end

FormUtil.Control =  function(name,myHtm,clickselector,clickFunc,param){
	//alert('control start');
	var control = $(myHtm);
	var boundTo = null;
	var container = null;
	var setToActivate = true;
	var setToDeactivate=false;
	
	

	this.setContainer = function(contain){
		container=contain;
	}
	this.getName = function(){
		return name;
	}
	
	this.setAction = function(func){
		clickFunc = func;
	}
	this.setParam=function(p){
		param=p;
	}
	
	var activate=function(){
		//alert('activating');
		try{
			setToDeactivate = false;
			if(container.find(clickselector).size() != 0){
				container.find(clickselector).bind(function(){clickFunc(param);});
				setToActivate=false;				
			}else{
				setToActivate=true;
			}
			return true;
		}catch(e){
			setToActivate = true;
			alert(e.message);
			return false;
		}
	}
	
	var deactivate=function(){
		try{
			setToActivate=false;
			$(clickselector).unbind(function(){clickFunc(param);});
			setToDeactivate = false;
			return true;
		}catch(e){
			setToDeactivate = true;
			alert(e.message);
			return false;
		}
	}

	var retry =function(){
		if(setToActivate)
			activate();
		if(setToDeactivate)
			deactivate();
	}
	
	this.hide= function(){
		control.hide();
	}
	this.show= function(){
		control.show();
	}

	this.get= function(){return control;}
	this.addTo = function(){
		control.appendTo(container);
	}
	
	this.remove=function(){
		control.remove();
	}
	this.correct =retry;
}

FormUtil.InputSection = function(rootSelector,inputGroupSelector,templateSelector,counterInputSelector){
	//Construction
	var myInputs = [];
	var controlTemplates=[];
	var myCounter = $(counterInputSelector).get(0);
	var executeOnUpdate=function(x){};
	
	

	
	//var addContHTML='<td class="functionalLink"><span class="addItemGroup" onclick="iSection.newGroup()">Add</span></td>';
	//var addContClickSelector ="span.addItemGroup";
	//var addContDestination=null;
	
	var removeContHTML ='<td class="functionalLink"><span  class="removeItemGroup" onclick="iSection.deleteGroup(iSection.getIndex(this))">Remove</span></td>';
	var removeContClickSelector ="span.removeItemGroup";
	var removeContDestination=null;
	
	//Public methods
	this.getGroup=function(x){return myInputs[x];}
	this.setPopulator=function(func){
		getPopulator = function(){
			return func;
		}
	}
	
	this.displayAllControls=function(func){
		if(func)
			var showControl = func;
		for(var i =0; i<myInputs.length;i++)
			myInputs[i].addControlsToDom(this.showControl);
	}
	
	this.initialize = function(){
		myInputs.length=0;
		$(rootSelector).find(inputGroupSelector).not(templateSelector).each(function(){
			myInputs[myInputs.length] = new InputGroup($(this),myInputs.length,true);
			setControlsInGroup(myInputs.length -1);
			//alert('existing grps done')
		});
		myCounter.value = myInputs.length;
		//alert('initialize done')
		return myInputs.length;
	}
	
	this.getIndex=function(obj){
		var templateInp = $(templateSelector).find('input').get();
		var x;
		var nam;
		for(var y in templateInp){
			nam=templateInp[y].name;
			x=y;
			if(nam){
				break;
			}
		}
		var foundName=$(obj).parents(inputGroupSelector).find('input').get(x).name;
		num=foundName.substr(nam.length);
		return num;
	}
	
	
	this.setControlDetails=function(contr,htm,selector,dest,func,param){
		if(contr =='add'){
			addContHTML = htm;
			addContClickSelector = selector;
			addContDestination=dest;
		}else if(contr=='remove'){
			removeContHTML =htm;
			removeContClickSelector =selector;
			removeContDestination=dest;
		}else{
			//Final two params are required where values are not - 'add' or 'remove'
			var template={name:contr,htm:htm,selector:selector,dest:dest,func:func,param:param};
			controlTemplates[controlTemplates.length]=template;
			
			
		}
	}
	var setControlsInGroup= function(gidx){
		IGroup = myInputs[gidx];
		for(var i=0;i<controlTemplates.length;i++){
			curr =controlTemplates[i];
			IGroup.newControl(new FormUtil.Control(curr.name,curr.htm.replace('XXXXX',gidx),curr.selector.replace('XXXXX',myInputs.length),curr.func,curr.param),curr.dest);
		}
		IGroup.newControl(new FormUtil.Control('remove',removeContHTML.replace('XXXXX',gidx),removeContClickSelector.replace('XXXXX',gidx),function(x){iSection.removeInput(x);},gidx),removeContDestination);
		//IGroup.newControl(new FormUtil.Control('add',addContHTML.replace('XXXXX',gidx),addContClickSelector.replace('XXXXX',gidx),function(){iSection.addNewInput();},''),addContDestination);

	}
	
	this.doOnUpdate=function(func){
		executeOnUpdate=func;
	}
		
	this.newGroup=function(){
		newContent = $(templateSelector).clone();
		newContent.id='groupinput'+myInputs.length;
		newCount = myInputs.length;
		myInputs[myInputs.length] = new InputGroup($(newContent),newCount);
		setControlsInGroup(myInputs.length -1);
		myCounter.value = myInputs.length;
		this.displayAllControls();
		executeOnUpdate('add');
		return myInputs[myInputs.length -1];
	}
	
	
	this.deleteGroup = function(idx){
		if(myInputs.length !== 1){
			deleted = myInputs.splice(idx,1);
			deleted[0].removeGroup();
			myCounter.value--;
			for(var i=idx;i<myInputs.length;i++){
				myInputs[i].reNumber(i);
			}
			this.displayAllControls();
			executeOnUpdate('delete');
			return deleted;	
		}else{
			myInputs[0].clearValues();
		}
	}
	//Private methods
	var getPopulator= function(){
		return function(name,proot,idx){
			field='';
			proot.find('input').each(function(){
				if(this.name.indexOf(name + idx)==0){
					field=this;
				}
			}).each(function(){
				if(this.id.indexOf(name + idx)==0){
					field=this;
				}					
			});
			return field;
		};
	}
		

	
	this.showControl= function(name,grpIdx){
		grpIdx++;
		if(name == 'add' ||name.toLowerCase().indexOf('last')!=-1){
			if(grpIdx==myCounter.value){
				return true;
			}else{
				return false;
			}
		}else if(name=='remove'){
			//added or true, because logic is added to give remove different purpose - could be controlled elsewise
			//like a config object...
			if(myCounter.value != 1 || true){
				return true;
			}else{
				return false;
			}
		}else if(name.toLowerCase().indexOf('all')!=-1){
			return true;
		}else if(name.toLowerCase().indexOf('first')!=-1){
			if(grpIdx == 1){
				return true;
			}else{
				return false;
			}
		}
	}		
	
		
		

		
				
	var InputGroup = function(root,idx,exists){
		//Private Methods
		var controls = new Array();
				
		this.reNumber=function(nxt){
			resetElemNum(root,idx,nxt);
			idx=nxt;
		}
			

			

			
		this.removeGroup = function(){
			root.remove();
			return this;
		}
			
		var findControl=function(contName){
			//alert('internal index = ' + idx);
			for(var i=0;i<controls.length;i++)
				if(controls[i].getName() == contName){
					return i;
				}
			return -1;
		}

			
		var removeControlFromGroup=function(contName){
			pos=findControl(contName);
			if(pos != -1){
				return controls.splice(pos,1)[0].remove();
			}else{
				return -1;
			}	
		}
			
		var getControl=function(nam){
			pos=findControl(nam);
			return (pos==-1)?null:controls[pos];
		}

		
		var	addToDom = function(){
			root.show();
			$(rootSelector).append(root.get(0));
		}
			

		var	initElemNum=function(elem,num){
			if(elem.id && elem.id !=''){
				elem.id+=num;
			}
			if(elem.name && elem.name!=''){
				elem.name+=num;
			}
			$(elem).children().each(function(){
				initElemNum(this,num);
			});
		}
			
		var	clearElemNum=function(elem,num){
			if(elem.id && elem.id.indexOf(num)!= -1)
				elem.id.replace(num,'');
			if(elem.name && elem.name.indexOf(num)!= -1)
				elem.name.replace(num,'');
		}
			
		var	resetElemNum=function(elem,old,next){
			if(elem.id && elem.id.indexOf(old) != -1){
				elem.id=elem.id.replace(old,next);
			}else if(elem.id){
				elem.id+=next;
			}
			if(elem.name && elem.name.indexOf(old) != -1){
				elem.name=elem.name.replace(old,next);
			}else if(elem.name){
				elem.name+=next;
				
			}
			$(elem).children().each(function(){
				resetElemNum(this,old,next);
			});
		}
		
		var addNewValue = function(nam,val){
			for(var i = 0; i<values.length;i++){
				if(values[i].name == nam){
					values[i].value=val;
					return;
				}
			}
			//not here if already found in array
			values[values.length]={};
			values[values.length - 1].name = nam;
			values[values.length - 1].value = val;
		}
		
		this.getValue=function(nam){
			for(var i = 0; i<values.length;i++){
				if(values[i].name == nam){
					return values[i].value;
				}
			}
			return '';
		}
		var setValues=function(){
			root.find('input').each(function(){
				if(this.value.length > 0);
					addNewValue(this.name,this.value);
			});
		}
		this.clearValues=function(){
			root.find('input').each(function(){
					this.value='';
					
			});
		};
		this.setValues = setValues;						
		this.addNewValue =addNewValue;		
		this.populate = function(instanceFunc){
			if(instanceFunc)
				populator=instanceFunc;
			else
				populator =getPopulator();
			for(var i = 0;i < values.length; i++){
				field = populator(values[i].name,root,idx);			
				field.value = values[i].value;			
			}
		}
		
		this.testEmpty=function(){
			setValues();
			for(var i=0;i< values.length;i++){
				if(values[i].value.length >0 && values[i].name != ''){
					return false;
				}
			}
			return true;
		}
		
		this.newControl=function(control,relSelector){
			pos=findControl(control.getName());
			if(pos == -1)
				pos= controls.length;
			if(relSelector)
				control.setContainer(root.find(relSelector));
			else
				control.setContainer(root);
			controls[pos]=control;					
		}
		this.removeControl=removeControlFromGroup;
	
		this.addControlsToDom = function(func){
			for(var i=0;i<controls.length;i++){
				currCont=controls[i];
				currCont.remove();
				currCont.addTo();
				if(!(func) || func(currCont.getName(),idx)){
					currCont.show();
				}else{
					currCont.hide();
				}
			}
		}

		//Construction
		var idx=(idx || idx==0)?idx:null;
		var	values=[];
		initElemNum(root.get(0),idx);
			
		if(!(exists)){
			addToDom();
		}else{
			setValues();
		}
	}// end input group			
}//end input section.



FormUtil.Form = function(sel){
	var myForm = $(formName);
	var Valid ={};
	Valid.state =true;
	Valid.tests =[];
	Valid.exclude =[];
	Valid.include =[];
	this.startPoint = function(){
		return $(sel +':input').filter(':disabled');
	}
	
	
	var removeFromList=function(arr,x){
		var slot=[];
		for(var i in arr){
			if(arr[i].is(x)){
				slot[slot.length] = i;
			}			
		}
		for(var j in slot){
			arr.splice(slot[j],1);
		}
		return;
	}
	
	this.makeRequired = function(x){
		if(typeof(x)=='string'){
			removeFromList(Valid.exclude,x);
			Valid.include[Valid.include.length] = $(x);
		}else{
			for(var i in x){
				removeFromList(Valid.exclude,x[i]);
				Valid.include[Valid.include.length] = $(x[i]);
			}
		}
	}
	
	this.makeNotRequired = function(x){
		if(typeof(x)=='string'){
			removeFromList(Valid.include,x);
			Valid.exclude[Valid.exclude.length] = $(x);
		}else{
			for(var i in x){
				removeFromList(Valid.include,x[i]);
				Valid.exclude[Valid.exclude.length] = $(x[i]);
			}
		}
	}
	
}
BN.FormUtil = FormUtil;

})(jQuery); 
//Encloses and protects $, and all other defined symbols. attachement to BN object inside is link to outer world.
