/*
 event:		:loaded
 event:		:loading
 event:		:zoomIn
 event:		:zoomOut
 event:		:zoomTo
 event:		:zoomInc
 event:		:zoomDec
*/
Df.EmbeddedZoom = Class.create(Df.Ui, {
	initialize: function($super, element){
		$super(element)

		this.setPars({
			pauseToClose: 1000, //int|false
			moveEvent: 'hover', //hover|drag
			loader: false,
			images: {},
			classNames: {
				base: 'base',
				zoom: 'zoom'
			}
		});

		/** @private */
		this.loader;

		/** @private */
		this.image

		/** @private */
		this.base = $(new Image());

		/** @private */
		this.baseAnimation;
		this._baseAnimationCompleteEvent = this.baseAnimationCompleteEvent.bindAsEventListener(this)

		/** @private */
		this.loaderAnimation;
		this._loaderAnimationCompleteEvent = this.loaderAnimationCompleteEvent.bindAsEventListener(this)

		/** @private */
		this.zoomAnimation;
		this._zoomAnimationCompleteEvent = this.zoomAnimationCompleteEvent.bindAsEventListener(this)

		/** @private */
		this.index;

		/** @private */
		this.maxHeight;

		/** @private */
		this.maxWidth;

		/** @private */
		this.baseHeight;

		/** @private */
		this.baseWidth;

		/** @private */
		this.out = false;

		/** @private */
		this.moveable = false;

		/** @private */
		this.startPointerX;
		/** @private */
		this.startPointerY;
		/** @private */
		this.startImageTop;
		/** @private */
		this.startImageLeft;

		this._zoomIn = this.zoomIn.bindAsEventListener(this)
		this._zoomOut = this.zoomOut.bindAsEventListener(this)
		this._zoomTo = this.zoomTo.bindAsEventListener(this)

		return this
	},

	set: function($super, pars){

		$super(pars)

		this.holderDims()

		//build elements
		this.buildBaseImage()
		this.buildLoader()

		//event handlers
		this.holderClickEvent()

		if (this.pars.moveEvent === 'drag') {
			this.documentMouseUpEvent()
		}

		return this;
	},

	zoomTo: function(e){
		e.memo.decimal = e.memo.decimal.toRange(0,1)
		if(e.memo.decimal != this.decimal){

			this.decimal = e.memo.decimal

			if(this.decimal == 0){
				this.moveable = false
				this.element.style.cursor = 'pointer';
			}

			var height = ((this.maxHeight - this.baseHeight) * this.decimal) + this.baseHeight
			var width = ((this.maxWidth - this.baseWidth) * this.decimal) + this.baseWidth

			if(e.memo.event){
				var top = - parseInt((this.getPointerY(e.memo.event) / this.baseHeight) * (height - this.baseHeight))
				var left = - parseInt((this.getPointerX(e.memo.event) / this.baseWidth) * (width - this.baseWidth))
			} else {
				var top = (parseInt(this.image.style.top) - ((height - parseInt(this.image.style.height)) / 2)).toRange(-height + this.baseHeight, 0)
				var left =  (parseInt(this.image.style.left) - ((width - parseInt(this.image.style.width)) / 2)).toRange(-width + this.baseWidth, 0)
			}

			this.image.style.visibility = "visible";

			this.zoomAnimation.run({
				top: top,
				left: left,
				height: height,
				width: width
			});
		}
	},

	zoomAnimationCompleteEvent: function(e){
		if(this.decimal == 0){
			this.image.style.visibility = "hidden";
		} else {
			if (this.pars.moveEvent === 'hover') {
				this.moveable = true;
			} else if (this.pars.moveEvent === 'drag') {
				this.element.style.cursor = 'auto';
			}
		}
	},

	zoomIn: function(e){
		e.memo.decimal = 1
		this.zoomTo(e)
		return this
	},

	zoomOut: function(e){
		e.memo.decimal = 0
		this.zoomTo(e)
		return this
	},

	loadIndex: function(index) {
		this.index = index;
		this.load(this.pars.images[this.index])

		return this
	},

	load: function(imageGroup){
		if(imageGroup && imageGroup != this.currentImageGroup){

			this.decimal = 0

			this.element.stopObserving(':zoomIn', this._zoomIn);
			this.element.stopObserving(':zoomTo', this._zoomTo);
			this.element.stopObserving(':zoomInc', this._zoomInc);
			this.element.stopObserving(':zoomDec', this._zoomDec);
			this.element.stopObserving(':zoomOut', this._zoomOut);

			this.currentImageGroup = imageGroup

			if(this.image){
				this.image.remove()
				delete(this.image)
			}

			this.base.src = this.currentImageGroup.base;
			this.base.style.display = 'block';

			this.element.style.cursor = 'auto';

			this.baseAnimation.run({opacity:1});

			if(imageGroup && imageGroup.zoom && imageGroup.zoom.trim() != ''){
				this.showLoader()
				this.buildZoomImage()
			}
		}
		return this
	},

	holderDims: function(){
		this.baseHeight = parseInt(this.element.getStyle('height'));
		this.baseWidth = parseInt(this.element.getStyle('width'));
	},

	baseAnimationCompleteEvent: function(e){
		this.element.style.backgroundImage = "url('" + this.currentImageGroup.base + "')";
		this.base.setStyle({opacity:0});
		this.base.style.display = 'none';
	},

	buildBaseImage: function(){
		this.base.addClassName(this.pars.classNames.base);
		this.base.setStyle({opacity:0});
		this.element.insert(this.base);
		this.baseAnimation = new Df.Animate(this.base);
		this.baseAnimation.setPars({time:500})
		this.baseAnimation.getElement().observe(':complete', this._baseAnimationCompleteEvent)
	},

	buildZoomImage: function(){
		this.image = $(new Image());
		this.image.addClassName(this.pars.classNames.zoom);
		this.image.style.visibility = "hidden";


		if (this.pars.moveEvent === 'drag') {
			this.image.style.cursor = "move";
			this.zoomMousedownEvent()
			this.zoomDragClickEvent()
		}
		else if(this.pars.moveEvent === 'hover'){
			this.zoomClickEvent()
		}

		this.zoomMouseMoveEvent()
		this.zoomMouseOutEvent()
		this.zoomMouseOverEvent()
		this.zoomLoadEvent()

		this.element.insert(this.image);
		this.zoomAnimation = new Df.Animate(this.image);
		this.zoomAnimation.getElement().observe(':complete', this._zoomAnimationCompleteEvent)

		this.image.src = this.currentImageGroup.zoom;
	},

	//START event handlers
	holderClickEvent: function(){
		this.element.observe('click', function(e){
			Event.stop(e);
			this.element.fire(':zoomIn', {event:e})
		}.bind(this));
	},

	zoomDragClickEvent: function(){
		this.image.observe('click', function(e){
			Event.stop(e);
		}.bind(this));
	},

	zoomClickEvent: function(){
		this.image.observe('click', function(e){
			Event.stop(e);
			this.element.fire(':zoomOut', {event:e})
		}.bind(this));
	},

	zoomMousedownEvent: function(){
		Event.observe(this.image, 'mousedown', function(e){
			Event.stop(e);
			this.moveable = true;
			this.startPointerX = this.getPointerX(e);
			this.startPointerY = this.getPointerY(e);
			this.startImageTop = parseInt(this.image.style.top);
			this.startImageLeft = parseInt(this.image.style.left);
		}.bind(this));
	},

	documentMouseUpEvent: function(){
		Event.observe(document.body, 'mouseup', function(e){
			this.moveable = false;
		}.bind(this));
	},

	zoomMouseMoveEvent: function(){
		//move zoom image inside holder
		this.image.observe('mousemove', function(e){
			Event.stop(e);
			if(this.moveable){
				if(this.pars.moveEvent === 'hover'){
					this.image.style.top = this.zoomTopPosition(e) + 'px';
					this.image.style.left = this.zoomLeftPosition(e) + 'px';
				}
				else if (this.pars.moveEvent === 'drag'){
					this.image.style.top = this.zoomTopPositionDrag(e) + 'px';
					this.image.style.left = this.zoomLeftPositionDrag(e) + 'px';
				}
			}
		}.bind(this));
	},

	zoomMouseOutEvent: function(){
		//zoom image mouseout event
		this.image.observe('mouseout', function(e){
			Event.stop(e);
			if(this.decimal != false){
				this.out = true;
				if(this.pars.pauseToClose !== false){
					setTimeout(this.handleMouseOver.bind(this), this.pars.pauseToClose);
				}
			}
		}.bind(this));
	},

	zoomMouseOverEvent: function(){
		//zoom image mousein event
		this.image.observe('mouseover', function(e){
			Event.stop(e);
			this.out = false;
		}.bind(this));
	},

	zoomLoadEvent: function(){
		//zoom image load event
		this.image.observe('load', function(e){
			Event.stop(e);

			this.element.style.cursor = 'pointer';

			this.maxHeight = parseInt(this.image.offsetHeight);
			this.maxWidth = parseInt(this.image.offsetWidth);

			this.image.style.height = this.baseHeight + 'px';
			this.image.style.width = this.baseWidth + 'px';

			this.image.style.top = '0px';
			this.image.style.left = '0px';

			this.element.observe(':zoomIn', this._zoomIn);
			this.element.observe(':zoomTo', this._zoomTo);
			this.element.observe(':zoomOut', this._zoomOut);

			this.hideLoader()

		}.bind(this));
	},

	//END event handlers

	//START loader methods
	loaderAnimationCompleteEvent: function(e){
		if(e.memo.pointer == 0){
			this.pars.loader.style.display = 'none';
		}
	},

	buildLoader: function(){
		this.pars.loader.setStyle({opacity:0})
		this.element.insert(this.pars.loader);
		this.loaderAnimation = new Df.Animate(this.pars.loader);
		this.loaderAnimation.setPars({time:1000, opacity:.50})
		this.loaderAnimation.getElement().observe(':complete', this._loaderAnimationCompleteEvent)
	},

	showLoader: function(){
		this.element.fire(':loading')

		this.element.style.cursor = 'auto';

		this.pars.loader.style.display = 'block';
		this.loaderAnimation.toggle();

		return this
	},

	hideLoader: function(){
		this.element.fire(':loaded')
		this.loaderAnimation.toggle();
	},

	//END loader methods

	handleMouseOver: function(e){
		if(this.out){
			this.element.fire(':zoomOut')
		}
	},

	zoomLeftPosition: function(e){
		return - parseInt((this.getPointerX(e) / this.baseWidth) * (this.image.getWidth() - this.baseWidth));
	},

	zoomTopPosition: function(e){
		return - parseInt((this.getPointerY(e) / this.baseHeight) * (this.image.getHeight() - this.baseHeight));
	},

	zoomLeftPositionDrag: function(e){
		var left = this.startImageLeft - (this.startPointerX - this.getPointerX(e));
		if (left > 0) {
			left = 0;
		} else if (left < -this.image.getWidth() + this.baseWidth) {
			left = -this.image.getWidth() + this.baseWidth;
		}
		return left;
	},

	zoomTopPositionDrag: function(e){
		var top = this.startImageTop - (this.startPointerY - this.getPointerY(e));
		if (top > 0) {
			top = 0;
		} else if (top < -this.image.getHeight() + this.baseHeight) {
			top = -this.image.getHeight() + this.baseHeight;
		}
		return top;
	}

});