/*
# $Id$
#
# Provides some generic method for selecting Models.
*/

/*
# @class GCms.ModelSelector( [string infoElementId], [string dataElementId], [object options] )
# infoElementId	= ID of the HTML element into which details of the selected Model(s) are inserted (optional)
# dataElementId	= ID of the HTML form field that will hold (or already holds) the data for selected Model(s) (optional)
# options		= Options to customize the selector (see below)
#
# Create a new GCms.ModelSelector instance.
#
# Valid options:
#	string url				= REQUIRED. The URL of the selection interface you want to use.
#	string title			= Title of the selector overlay.
#	string validtype		= Model type that will be accepted by this selector (eg. "Document", "ObjectMeta", etc)
#	int maxselections		= Max. number of Models that can be selected (defaults to 1).
#	Function onselect		= This function is called whenever a Model is selected. (params: object modelObj, string type)
#	Function oncomplete		= This function is called when the overlay is closed down.
#	Function onclear		= This function is called when the elements are cleared.
#	Function onpopulateinfo	= This function is called whenever the info element needs populating.
#
# Usage:
# 1. Create a DIV block to hold all info about the selected Model(s).
# 2. Create a form field element to hold the saveable data passed back (in JSON format) when an object is selected. This field
#	can contain previously saved data (in JSON format) which will be used when initialising the selector. If set, it must
#	contain at least the "id" field and any other fields that are required by the function that populates the information block.
# 3. JavaScript to initialise the selector:
#		var PS = new GCms.Module.Crm.Selector('id-of-your-DIV-block', 'id-of-your-field-element', {validtype:'ModelName'});
# 4. JavaScript to launch the selector window (attach to anything you like):
#		PS.launch();
#
# Notes:
# - All callback functions are sent "this" ModelSelector instance as their first parameter.
*/
GCms.ModelSelector = function(infoElementId, dataElementId, options) {

	// Class properties
	this.infoElement = infoElementId!=null ? $(infoElementId) : {innerHTML:''};
	this.dataElement = dataElementId!=null ? $(dataElementId) : {value:''};
	this.options = options==null ? {} : options;
	this.selections = [];

	// Populate missing options
	var defaultOptions = {
		objectName: null,
		validtype: null,
		url: null,
		title: 'Select ...',
		maxselections: 1,
		onselect: null,
		oncomplete: null,
		onclear: null,
		onpopulateinfo: null,
		currentselections: null
	};
	for(var i in defaultOptions) {
		if(this.options[i]==null) this.options[i] = defaultOptions[i];
	}

	// Populate the information block
	this.populateInfoElement();
}

/*
# @method void GCms.ModelSelector.launch()
#
# Opens the selector interface in an Overlay.
*/
GCms.ModelSelector.prototype.launch = function() {

	// Populate this.selections with pre-existing data from the dataElement field
	this.selections = [];
	if(this.dataElement.value!='') {
		var d = this.dataElement.value.evalJSON();
		this.selections = d.push ? d : [d];
	}

	// Open interface
	var _this = this;
	var overlayId = 'GCms.ModelSelector.'+Math.round(Math.random()*1000000);
	var overlay = GCms.Overlay.create(overlayId, {
		title: this.options.title,
		src: this.options.url,
		callbacks: {

			/*
			# @function void onselect( object modelObj, [string type] )
			# modelObj	= Object containing all info about the selected Model
			# type		= The Model's type (name)
			#
			# Should be called by the selector interface whenever a Model is selected.
			*/
			onselect: function(modelObj, type, link) {

				// Check type
				if(type!=null && _this.options.validtype!=null && type!=_this.options.validtype) {
					alert("Invalid selection.\n\nYou selected: "+type+"\nValid type: "+_this.options.validtype);
					return;
				}
				
				var lastRemoved = null
				
				// Add the object to the list of selections or remove if exists
				for(sit=0;_this.selections.length>sit;sit++){
					if(_this.selections[sit]['id'] == modelObj['id']){
						if(link && link.className.indexOf("gcms-selected-overlay-object")>=0){
							lastRemoved = _this.selections.splice(sit,1)
							link.className=""
						}else{
							lastRemoved = 1
							link.className="gcms-selected-overlay-object";
						}
					}
				}
				// add if not just removed
				if(lastRemoved == null){
					_this.selections.push(modelObj)
					if(link && link.className.indexOf("gcms-selected-overlay-object")<0){
						link.className="gcms-selected-overlay-object";
					}
				}
				
				while(_this.selections.length>_this.options.maxselections) {
					_this.selections.shift();
				}

				// Sync container elements
				_this.populateDataElement();
				_this.populateInfoElement();

				// Execute the custom "onselect" function
				if(_this.options.onselect!=null) {
					_this.options.onselect(_this, modelObj, type);
				}

				// If we've reached our max selection limit then close the overlay
				if(_this.selections.length>=_this.options.maxselections) {

					// Close overlay
					overlay.destroy();
				}
			}
		},
		ondestroy: function() {

			// Clear selections cache
			_this.selections = [];

			// Trigger custom "oncomplete" 
			if(_this.options.oncomplete!=null) {
				_this.options.oncomplete(_this);
			}
		}
	});
	overlay.show();
}

/*
# @method void GCms.ModelSelector.clear()
#
# Clears all data from all fields.
*/
GCms.ModelSelector.prototype.clear = function() {

	// Clear all elements
	try{this.infoElement.innerHTML = '';}catch(e){}
	this.dataElement.value = '';
	// Clear selections cache
	
	try{
	
	this.selections = [];
	
	this.populateInfoElement();
	
	this.populateDataElement();
	
	}catch(e){alert(e.message)};
	
	// Trigger custom "onclear"
	if(this.options.onclear!=null) {
		this.options.onclear(this);
	}
}

/*
# @method bool GCms.ModelSelector.setOption( string name, mixed value )
# name	= Option name
# value	= Option value
#
# Sets an element in "this.options".
*/
GCms.ModelSelector.prototype.setOption = function(name, value) {

	// Ignore read-only options
	var readonly = [];
	for(var i=0; i<readonly.length; i++) {
		if(name==readonly[i]) {
			return false;
		}
	}

	// Set
	this.options[name] = value;

	// Result
	return true;
}

/*
# @method mixed GCms.ModelSelector.getOption( [string name] )
# name	= Option name
#
# Return a value from "this.options".
# If "name" is ommited then all options are returned.
*/
GCms.ModelSelector.prototype.getOption = function(name) {

	// Result
	return name==null ? this.options : this.options[name];
}

/*
# @method void GCms.ModelSelector.populateInfoElement( [array data] )
# data	= Data with which to populate the element
#
# Populate the information element with data currently held in this.selections
*/
GCms.ModelSelector.prototype.populateInfoElement = function(data) {
	
		// Call custom "onpopulateinfo" function
		if(this.options.onpopulateinfo!=null) {
			return this.options.onpopulateinfo(this);
		}
	
		// Vars
		if(data==null) {
			data = this.getData();
		}
		if(data=='') {
			data = [];
		}
		else if(!data.push) {
			data = [data];
		}
	
		// Populate
		this.infoElement.innerHTML = '';
		for(var i=0; i<data.length; i++) {
			var obj = data[i];
			for(var j in obj) {
				this.infoElement.innerHTML += j+': <b>'+obj[j]+"</b><br/>";
			}
		}
}

/*
# @method void GCms.ModelSelector.populateDataElement()
#
# Populate the data element with data currently held in this.selections.
# If only one model is in this.selections, then the stored data with be an object.
# If more than one model is in this.selections, then the stored data will be an array of objects.
*/
GCms.ModelSelector.prototype.populateDataElement = function() {

	// Populate
	this.dataElement.value = Object.toJSON(this.selections.length==1 ? this.selections[0] : this.selections);
}

/*
# @method object|string GCms.ModelSelector.getData()
#
# Return the value currently stored in this.dataElement.
# If the value is JSON encoded, then it will be decoded before being returned by this function.
*/
GCms.ModelSelector.prototype.getData = function() {
	var data =  this.dataElement.value=='' ? '' : this.dataElement.value.toString().evalJSON();
	return data;
}

/*
# @method object|string GCms.ModelSelector.popById()
#
*/
GCms.ModelSelector.prototype.popById = function(id) {
	var data = this.dataElement.value=='' ? '' : this.dataElement.value.toString().evalJSON();
	//var data = data.push ? data : [data] ;
	
	this.clear()
	for(c=0;data.length>c;c++){
		if(data[c]['id'] != id){
			this.selections.push(data[c])
		}
	}

	this.populateDataElement()
	this.populateInfoElement()
}

/*
# @method object|string GCms.ModelSelector.promote()
#
*/
GCms.ModelSelector.prototype.promote = function(id,index) {
	try{
		
		var data = this.dataElement.value=='' ? '' : this.dataElement.value.toString().evalJSON();
		//var data = data.push ? data : [data] ;
		
		//calling clear here forces error in IE7
		this.clear()
		
		//this.infoElement.innerHTML = '';
		/*this.dataElement.value=='';
		this.selections=[];*/
		for(c=0;data.length>c;c++){
			if(data[c]['id'] != id){
				this.selections.push(data[c])
			}else{
				var moveitem = data[c]
				var point = c-index
			}
		}
		this.selections.splice(point,0,moveitem)
		this.populateDataElement()
		this.populateInfoElement()
	}catch(er){
		alert(Util.dump(er))
	}
}
