/*
 * @author 		Zensolutions
 * @category	Zen
 * @package		Zen_Categoryhotspot
 * @version		1.0.0
 * @copyright	Copyright (c) 2010 Zensolutions s.r.o. [http://www.zensolutions.cz]
 * @license		Commercial per server
 */

var dragMarkerClassObject	= null;
var markerClass				= Class.create();

markerClass.prototype		= {

	/**
	**********************************************
	*
	* ##########
	* Initializations
	* ##########
	*
	**********************************************
	*/

	image: null,
	activeMarkers: {arrayIndex: 0, existingEntries: [], newEntries: []},
	markerSrc: {active: null, inactive: null},
	defaultMarkerUrl: null,
	editable: null,
	markerContainer: null,
	markerDescriptionElement: null,
	markerProductSelect: null,
	savingInput: null,
	draggableMarker: null,
	deletionText: null,
	possibleMarkers: null,
	imageAttributes: {offsetX: 0, offsetY: 0, dimX: 0, dimY: 0},
	
	/**
	 * Standard initialize function.
	 *
	 * @param string	imageId				id of image to print markers on
	 * @param string	markerContainer		container for adding new markers into DOM
	 * @param string	activeMarkerUrl		url for markers with mouse over
	 * @param string	inactiveMarkerUrl	url when out of marker
	 * @param boolean	editable			(optional) defines if front(false)- or backend(true)
	 * @usage global
	 * @call extern
	 */
	initialize: function(imageId, markerContainer, activeMarkerUrl, inactiveMarkerUrl, editable)
	{
		this.resetVariables();
	
		if (null == editable) {
			this.editable = false;
		} else {
			this.editable = editable;
		}
		
		this.markerContainer = $(markerContainer);
		this.markerSrc.active = activeMarkerUrl;
		this.markerSrc.inactive = inactiveMarkerUrl;
		
		this.initImg(imageId);
	},
	
	/**
	 * Set the internal variable including all products which are possible for markers for showing name and short_description.
	 *
	 * @param mixed_array	markers		array with name & short_description of all possible entries
	 * @call extern
	 * @usage global
	 */
	setPossibleMarkerProducts:function(markers)
	{
		this.possibleMarkers = markers;
	},
	
	/**
	 * Add settings for editing of markers in admin.
	 *
	 * @param string	savingInputId			id of input send per post in admin
	 * @param string	draggableMarkerId		id of dragmarker
	 * @param string	markerProductSelectId	id of select holding products
	 * @param string	deletionText			translated text shown when deleting marker
	 * @usage admin
	 * @call extern
	 */
	initDraggableOptions: function(savingInputId, draggableMarkerId, markerProductSelectId, deletionText)
	{
		this.savingInput = $(savingInputId);
		this.draggableMarker = $(draggableMarkerId);
		this.deletionText = deletionText;
		
		this.setMarkerProductSelect(markerProductSelectId);
		
		dragMarkerClassObject = new Draggable(
			this.draggableMarker,
			{
				ghosting: true,
				revert: true,
				scroll: window
			}
		);
	},
	
	/**
	 * Set behaviour of select-box holding products for markers.
	 *
	 * @param string markerProductSelectId
	 * @usage admin
	 */
	setMarkerProductSelect: function(markerProductSelectId)
	{
		this.markerProductSelect = $(markerProductSelectId);
		
		this.markerProductSelect.observe('change', this.changeMarkerProductSelect.bindAsEventListener(this));
	},
	
	/**
	 * Initial method for setting active marker options/events.
	 *
	 * Add div of description for hoverred marker.
	 * Set marker(s) as drag objects.
	 * (optional) Set image as droppable area.
	 * @param mixed_array	markers				array of active marker elements
	 * @param string		defaultMarkerUrl	(optional) the url for representing products without id as param
	 * @usage global
	 * @call extern
 	 */
	initMarkers: function(markers, defaultMarkerUrl)
	{
		this.markerDescriptionElement = new Element('div');
		this.markerDescriptionElement.id = 'hotspot-marker-description';
		
		if (false == this.editable) {
			this.defaultMarkerUrl = defaultMarkerUrl;
		}
		
		this.markerContainer.insert(this.markerDescriptionElement);
		
		markers.each(this.addExistingActiveMarker, this);
		
		if (true == this.editable) {
			Droppables.add(
				this.image,
				{
					onDrop: this.dropMarker.bindAsEventListener(this),
					accept: 'drop-new-marker'
				}
			);
		}
	},
	
	/**
	 * Reset variables in fact of (non self-clearing) bug when updating page with ajax.
	 *
	 * @usage global
	 */
	resetVariables: function()
	{
		this.image = null;
		this.activeMarkers = {arrayIndex: 0, existingEntries: [], newEntries: []};
		this.markerSrc = {active: null, inactive: null};
		this.defaultMarkerUrl = null;
		this.editable = null;
		this.markerContainer = null;
		this.markerDescriptionElement = null;
		this.markerProductSelect = null;
		this.savingInput = null;
		this.draggableMarker = null;
		this.deletionText = null;
		this.possibleMarkers = null;
		this.imageAttributes = {offsetX: 0, offsetY: 0, dimX: 0, dimY: 0};
		
		// @extern dragMarkerClassObject
		if (null != dragMarkerClassObject) {
			dragMarkerClassObject.destroy();
		}
		
		dragMarkerClassObject = null;
	},

	/**
	 * Initial method for setting image options/events.
	 *
	 * @param string	imageId		id of image for markers
	 * @usage global
	 */
	initImg: function(imageId)
	{
		var tempOffset = null;
		var tempDim = null;
		
		this.image = $(imageId);
		tempOffset = this.image.positionedOffset();
		tempDim = this.image.getDimensions();
		
		this.imageAttributes.offsetX = tempOffset.left;
		this.imageAttributes.offsetY = tempOffset.top;
		this.imageAttributes.dimX = tempDim.width;
		this.imageAttributes.dimY = tempDim.height;
		
		this.image.observe('mouseover', this.mouseOverImage.bindAsEventListener(this));
		//this.image.observe('mouseout', this.mouseOutImage.bindAsEventListener(this));
	},

	/*
	 **********************************************
	 *
	 * ##########
	 * Eventhandlers
	 * ##########
	 *
	 **********************************************
	 */

	/**
	 * Event thrown when mouse over image.
	 *
	 * @usage global
	 */
	mouseOverImage: function()
	{
		this.markerContainer.show();
	},
	
	/**
	 * Check if the cursor is over marker and not really out of image, then disable markers.
	 * 
	 * Event thrown when mouse out image.
	 * @usage global
	 */
	mouseOutImage: function(e)
	{
		var xPointer = Event.pointerX(e);
		var yPointer = Event.pointerY(e);
		var imageMaxX = this.imageAttributes.offsetX + this.imageAttributes.dimX;
		var imageMaxY = this.imageAttributes.offsetY + this.imageAttributes.dimY;
		
		if(
			xPointer <= this.imageAttributes.offsetX || xPointer >= imageMaxX ||
			yPointer <= this.imageAttributes.offsetY || yPointer >= imageMaxY
		) {
			this.markerContainer.hide();
		}
	},
	
	/**
	 * Prepare marker description when mouse over it.
	 *
	 * @param HTML_IMG_Element	arguments.marker
	 * @param object			arguments.item
	 * @usage global
	 */
	mouseOverMarker: function()
	{
		var argv = arguments[1];
		
		argv.marker.src = this.markerSrc.active;
		this.prepareMarkerDescription(argv.marker, argv.item, true);
	},
	
	/**
	 * Disable visiblitity of marker description qwhen mouse out of image.
	 *
	 * @param HTML_IMG_Element arguments.item
	 * @usage global
	 */
	mouseOutMarker: function()
	{
		var argv = arguments[1];
		
		argv.marker.src = this.markerSrc.inactive;
		this.prepareMarkerDescription(null, null, false);
	},

	/**
	 * Set new marker when draggable is dropped on image with the same position.
	 *
	 * Event fired when marker is dropped on image.
	 * @param HTML_IMG_ELEMENT	dragItem
	 * @usage admin
	 */
	dropMarker: function(dragItem)
	{
		var windowScrolls = document.viewport.getScrollOffsets();
		var itemOffsets = dragItem.viewportOffset();
		var tempNewMarkerObject = {
			offset_x: itemOffsets.left + windowScrolls.left - this.imageAttributes.offsetX,
			offset_y: itemOffsets.top + windowScrolls.top - this.imageAttributes.offsetY,
			block_id: this.getMarkerProductSelectValue()};
	
		this.addActiveMarker(tempNewMarkerObject, true);
	},
	
	/*
	 **********************************************
	 *
	 * ##########
	 * Other methods
	 * ##########
	 *
	 **********************************************
	 */

	/**
	 * Wrapper function for addActiveMarker().
	 *
	 * @usage global
	 */
	addExistingActiveMarker: function(item)
	{
		this.addActiveMarker(item, false);
	},
	
	/**
	 * Add markers to image.
	 *
	 * First check if (and add) the given item is a new one (made in admin) or existing one (load from table)
	 * Create new marker object.
	 * Attach it to markerContainer.
	 * Add mouse events to display the description.
	 * If newItem then add the functionality for admin (onclick = delete)
	 *		or frontend (onclick = open product URL)
	 * optional: Make marker draggable
	 * @param object item
	 * @param boolean isNewItem
	 * @usage global
	 */
	addActiveMarker: function(item, isNewItem)
	{
		if (true == isNewItem) {
			this.activeMarkers.newEntries[this.activeMarkers.arrayIndex] = item;
		} else {
			this.activeMarkers.existingEntries[this.activeMarkers.arrayIndex] = item;
		}
		
		var latestMarker = this.createNewDOMMarker(item);
		
		latestMarker.observe('mouseover', this.mouseOverMarker.bindAsEventListener(this, {marker: latestMarker, item: item}));
		latestMarker.observe('mouseout', this.mouseOutMarker.bindAsEventListener(this, {marker: latestMarker}));
		
		if (true == this.editable) {
			latestMarker.observe(
				'click',
				this.removeMarker.bindAsEventListener(
					this,
					{markerElement: latestMarker, index: this.activeMarkers.arrayIndex}
				)
			);
		} else {
			/*latestMarker.observe(
				'click',
				this.openMarkerUrl.bindAsEventListener(
					this,
					{item: item}
				)
			);*/
		}
		
		this.activeMarkers.arrayIndex = this.activeMarkers.arrayIndex + 1;
		
		if (true == this.editable) {
			this.refreshSaveParams();
		}
	},
	
	/**
	 * Remove marker after last comfirmation and refresh the save input param.
	 *
	 * @param HTML_IMG_Element arguments.markerElement
	 * @param integer arguments.index
	 * @usage admin
	 */
	removeMarker: function()
	{
		var argv = arguments[1];
		var delConfirm = confirm(this.deletionText);
		
		if (true == delConfirm) {
			this.deleteMarkerFromArray(argv.index);
			argv.markerElement.remove();
		}
	},
	
	/**
	 * Open associated product view URL for clicked marker.
	 *
	 * @param object arguments.item
	 * @usage front
	 */
	openMarkerUrl: function()
	{
		var argv = arguments[1];
		
		window.location = this.defaultMarkerUrl + argv.item.url_path;
	},
	
	/**
	 * Refresh the value of input for saving changed markers in admin.
	 *
	 * The markers exist of new entries (dropped-down in this page request) or existing ones (already have a table entry)
	 * @usage admin
	 */
	refreshSaveParams: function()
	{
		var deletedExistingMarkers = this.activeMarkers.existingEntries.clone().findAll(this.getDeletedExistingMarkers, this);
		var newActiveMarkers = this.activeMarkers.newEntries.clone();
		
		this.savingInput.value = '[' + deletedExistingMarkers.toJSON() + ',' +
			newActiveMarkers.toJSON() + ']';
	},
	
	/**
	 * Change visibility of draggable marker depending on selected value of dropdown.
	 *
	 * @usage admin
	 */
	changeMarkerProductSelect: function()
	{
		if (true == this.isMarkerProductSelected()) {
			this.draggableMarker.show();
		} else {
			this.draggableMarker.hide();
		}
	},
	
	/**
	 * Check if dropdown is either filled with value or not.
	 *
	 * @usage admin
	 * @return boolean
	 */
	isMarkerProductSelected: function()
	{
		if ('' == this.getMarkerProductSelectValue()) {
			return false;
		}
		
		return true;
	},
	
	/**
	 * Return value of current selection of productmarker dropdown.
	 *
	 * @return string
	 * @usage admin
	 */
	getMarkerProductSelectValue: function()
	{
		return this.markerProductSelect.getValue();
	},
	
	/**
	 * Check given object if it has the tag: deleted.
	 *
	 * @param object	e	the element holding an object
	 * @return boolean 
	 * @usage admin
	 */
	getDeletedExistingMarkers: function(e)
	{
		if (true == e.deleted) {
			return true;
		}
		
		return false;
	},

	/**
	 * Prepare description for marker and set current position under the active marker.
	 *
	 * @param null|HTML_IMG_Element marker
	 * @param null|object item
	 * @param boolean show
	 * @usage global
	 */
	prepareMarkerDescription: function(marker, item, show)
	{
		if (true == show) {
			var usableMarker = this.possibleMarkers.find(
				this.getDescriptionElementByProductId.bindAsEventListener(
					this,
					{blockId: item.block_id}
				)
			);
			
			/* setup image url */
			/*
			* placeholderImg 	=> defined in head / js section
			* mediaUrl			=> defined in head / js section
			*/			
			if (usableMarker.image == 'no_selection'){
				var productImage	= placeholderImg;
			} else {
				var productImage	= usableMarker.image;
			}
			
			//var markerDescription = '<h2>' + usableMarker.name + '</h2><div class="container"><img class="resize" src="' + productImage + '" alt="' + usableMarker.name + '" /><div class="description">' + usableMarker.short_description + '</div><div class="clear"></div><div class="bottom"></div></div>';
			var markerDescription = '<div class="marker-description">' + usableMarker.content + '</div>';
			this.markerDescriptionElement.update(markerDescription);
			this.markerDescriptionElement.clonePosition(marker, {offsetLeft: 55, offsetTop: -33});
			this.markerDescriptionElement.setStyle({height: '', width: ''});
			this.markerDescriptionElement.show();
		} else {
			this.markerDescriptionElement.hide();
		}
	},

	deleteMarkerFromArray: function(index)
	{
		if (this.activeMarkers.existingEntries[index]) {
			this.activeMarkers.existingEntries[index].deleted = true;
		} else if (this.activeMarkers.newEntries[index]) {
			delete this.activeMarkers.newEntries[index];
		}

		this.refreshSaveParams();
	},
	
	/**
	 * Check if product ids of the two parameters are equal.
	 *
	 * @param object e
	 * @param integer productId
	 * @usage global
	 * @return boolean
	 */
	getDescriptionElementByProductId: function(e)
	{
		var argv = arguments[1];
		
		if (argv.blockId == e.block_id) {
			return true;
		}
		
		return false;
	},
	
	/**
	 * Create new marker element, set display style (position) and add it to DOM (to page).
	 *
	 * @param object	item	element holding style data for adding new marker
	 * @usage global
	 * @return HTML_IMG_ELEMENT
	 */
	createNewDOMMarker: function(item)
	{
		var newMarker = new Element('img');
        var resizedPercentage = window.resizedPercentage ? window.resizedPercentage : 1.0;
		
		var offsetLeft = Number(item.offset_x) * resizedPercentage + this.imageAttributes.offsetX;
		var offsetTop = Number(item.offset_y) * resizedPercentage + this.imageAttributes.offsetY;
		
		newMarker.src = this.markerSrc.inactive;
		
		newMarker.setStyle({position: 'absolute', left: String(offsetLeft + 'px'), top: String(offsetTop + 'px')}).addClassName('hotspot-marker');
		
		this.markerDescriptionElement.hide(); // hide Marker Description Element onload 
		
		this.markerContainer.insert(newMarker);
		newMarker.insert();
		return newMarker;
	}
};
