/**
 * This control is used to create or edit a geo-based
 * resource. A resource is expected as the first parameter.
 * The control makes a decision byself if the resource will
 * be edited or created.
 * 
 * @param {SResource or SStruct} resource_or_struct A resource
 * or a struct is expected.
 */
function SResourceGeoControl(resource_or_struct, clazz) {
	clazz = clazz || 'resource';
	if (clazz == 'struct') {
		this.mode = 'create';
		this.struct = resource_or_struct;
	} else {
		this.mode = 'edit';
		this.resource = resource_or_struct;
	}
	
	if (!this.resource && !this.struct)
		throw 'Neither struct nor resource is given.';
}
SResourceGeoControl.prototype = Object.extend(new GControl(), {
	mode: 'create',
	
	/**
	 * Initializes the control and assign the map.
	 * Gets all geo-based resources within the given on
	 * and puts them in the queue if resource is new and
	 * not created yet.
	 * 
	 * If resource should be edited the control will interact
	 * with the user.
	 * 
	 * @param {GMap2} map The google Maps map
	 */
	initialize : function(map) {
		this.map = map;
		/* Sets the state of the RControl object */
		rControl.reset(rControl.sGeoResource);
		
		if (this.mode == 'create' && this.struct) {
			var opts = new Hash({
				map : this.map,
				parent : null,
				struct : this.struct
			});
			this.resource = this.struct.isGeo() ? new SGeoResource(opts) : new SResource(opts);
		}
			
		this.container = this.getContainerContent();
		map.getContainer().appendChild(this.container);
		
		/* Check if resource is new. Then create new georesources... */
		if (this.mode == 'create') {
			/* Get next geo-based resource to process. */
			this.processGeoResource(this.nextGeoResource(this.resource));
		} else {
			/* The mode is important for the user-information */
			this.mode = 'edit';
			
			/* This resource isn't new, it will be edited. */
			this.processGeoResource(this.resource);
		}
		return this.container;
	},
	
	/**
	 * This function is only used if a resource should
	 * be created. Expects a struct as parameter. It
	 * processes all children and looking for a primitive
	 * geo-based resource. if its found and resource has
	 * no appropriate child, this child will be created
	 * and returned.
	 * @param {SStruct} struct The current Struct
	 * @param {SResource} resource The current Resource
	 */
	nextGeoResource : function(resource) {
		var cResource;
		/* Get struct for faster access */
		var struct = resource.struct;
		
		/* If this resource is geobased */
		if (resource.isGeo() && !resource.created) {
			resource.created = true;
			return resource;
		}
		
		/* Check if all resource children are created. */
		for (var i = 0; i < struct.children.length; i++) {
			var cStruct = struct.children[i];
			
			if (resource.hasChildWithSymbol(cStruct.symbol)) {
				cResource = resource.getChildBySymbol(cStruct.symbol);
			} else {
				var opts = new Hash({
					map : this.map,
					parent : resource,
					struct : cStruct
				});
				cResource = cStruct.isGeo() ? new SGeoResource(opts) : new SResource(opts);
				resource.addChild(cResource);
			}
			
			var nResource = this.nextGeoResource(cResource);
			if (nResource) { 
				return nResource; 
			}
		}
		return null;
	},
	
	/**
	 * Process the creation or editing of a geo-based
	 * resource.
	 * @param {SResource} resource The resource to create or to edit.
	 */
	processGeoResource : function(resource) {
		if (!resource) {
			throw "Can't process null resource";
		}
		/* Memorise the current resource */
		this.currentResource = resource;
		/* 
		 * Register 'finish' event on resource. Otherwise
		 * this control will not be informed when user is finished.
		 */
		var self = this;
		resource.onFinish = function(r) {
			var nextResource = self.mode == 'create' ? self.nextGeoResource(self.resource) : null;
			if (nextResource) {
				self.processGeoResource(nextResource);
			} else {
				self.onAccept();
			}
		}
		
		/* Give the user some info about what to do. */
		if (this.mode == 'create') {
			this.setText(t('tResourceEditGeoControlPlacement') + ': ' + resource.struct.name);
		} else {
			this.setText(t('tResourceEditGeoControlEditing') + ': ' + resource.struct.name);
		}
	},
	
	/**
	 * If user cklicks the 'accept' button, this method
	 * will be called. It will save or update the resource.
	 */
	onAccept : function() {
		this.accepted = true;
		/* Display some info to the user. */
		if (this.mode == 'create') {
			this.setText(t('tResourceEditGeoControlCreate'));
		} else {
			this.setText(t('tResourceEditGeoControlUpdate'));
		}
		/* Take a snapshot of the current resource. */
		if (this.currentResource) {
			this.currentResource.snapshot();
			this.currentResource = null;
		}
		
		/* Destroy this control. */
		this.finalize();
		
		/*
		 * It the given resource is valid then create
		 * a new one if not existant or update it.
		 */
		if (this.resource.isValid() && !this.resource.isEmpty()) {
			if (this.mode == 'create')
				this.map.rControl.fireOnNewNonGeoResource(this.resource.getRoot(), 'resource');
			else
				this.map.rControl.requestGeoResourceUpdate(this.resource, true);
		} else {
			this.resource.destroy();
		}
	},
	
	/**
	 * Cancels the creation or edition of the resource.
	 * The user will be asked, if it is really his intention.
	 */
	onCancel : function() {
		if (confirm(t('tResourceEditGeoControlCancelConfirm'))) {
			this.accepted = false;
			this.finalize();
			if (!this.resource.isNew()) {
				this.map.rControl.requestGeoResourceDetails(this.resource);
			}
		}
	},
	
	finalize : function() {
		if (this.onResourceFinishEvent) {
			GEvent.removeListener(this.onResourceFinishEvent);			
		}
		this.map.rControl.reset();
	},
	
	/**
	 * Creates the HTML content for the control
	 * and returns it.
	 */
	getContainerContent : function() {
		var container = document.createElement("div");
		container.className = 'gcontrol_container';
		
		var bg = document.createElement("div");
		bg.className = 'gcontrol_bg';
		container.appendChild(bg);
		
		this.info = document.createElement("div");
		this.info.className = 'gcontrol_tb_info';
		this.info.innerHTML = '<img class="fl" src="/images/32x32/help-browser.png" /><div id="gcontol_rmessage"></div>'
		container.appendChild(this.info);
		
		this.actions = document.createElement("div");
		this.actions.className = 'gcontrol_tb_actions';
		container.appendChild(this.actions);
		
		var cancel = document.createElement("div");
		this.actions.appendChild(cancel);
		cancel.style.display = 'inline';
		cancel.innerHTML = '<img class="gcontrol_tb_button" src="/images/16x16/cancel.png"/>';
		GEvent.bindDom(cancel, "click", this, function() {
			this.onCancel();
		});
		
		var save = document.createElement("div");
		this.actions.appendChild(save);
		save.style.display = 'inline';
		save.innerHTML = '<img class="gcontrol_tb_button" src="/images/16x16/accept.png"/>';
		GEvent.bindDom(save, "click", this, function() {
			this.onAccept();
		});
		return container;
	},
	
	/**
	 * It's a helper method to change the text within the message
	 * area. The expected parameter is the new Text.
	 * @param {String} text Texts that should be displayed.
	 */
	setText : function(text) {
		if (!this.msgElement) {
			this.msgElement = document.getElementById('gcontol_rmessage'); 
		}
		this.msgElement.innerHTML = text;
	},
	
	/**
	 * Destroys this control and if user has not accepted
	 * the changes, the resource will be destroyed.
	 */
	destroy : function() {
		if (!this.destroyed) {
			if (!this.accepted && this.resource && this.resource.isNew()) {
				this.resource.destroy();
			}
			this.destroyed = true;
		}
		this.map.removeControl(this);
	},
	
	printable : function() {
		return false;
	},
	
	selectable : function() {
		return false;
	},
	
	getDefaultPosition : function() {
		return new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize(0, 0));
	}
});