window.addEvent('domready', function() {
	var viewport = new PhotoViewport('photo-viewport');
	var taggable_photo = new TaggablePhoto(1);
	viewport.addEvents({
		'image_fitted':function() {
			if (taggable_photo.ui != null) taggable_photo.ui.update();
		}
	});
});

var PhotoViewport = new Class({
	Extends: Events,
	initialize: function (id) {
		this.viewport = $(id);
		this.img = this.viewport.getElement('img');
		this.footer = this.viewport.getElement('footer'); 
		this.wait_for_image();
		window.addEvent('resize', this.fit_image.bind(this));
	},
	wait_for_image: function () {
		this.current_image_file = new Image();
		this.current_image_file.src = this.img.getProperty('src');
		this.image_check_periodical = this.image_check.periodical(100,this);
	},
	image_check: function () 
	{
		if (this.current_image_file.width > 0) 
		{
			var h, w;
			$clear(this.image_check_periodical);
			h = this.current_image_file.height;
			w = this.current_image_file.width;
			this.aspect = w/h;
			this.fit_image();
		}
	},
	fit_image: function () {
		var v_dim, v_pos, v_aspect, i_h, i_w, i_x, i_y, styles;
		v_dim = this.viewport.getDimensions();
		v_pos = this.viewport.getPosition();
		v_aspect = v_dim.width/v_dim.height;
		if (v_aspect < this.aspect) {  
			//if the viewport is too narrow
			i_h = v_dim.height - v_pos.y;
			i_w = i_h * this.aspect;
			i_x = (v_dim.width-i_w)/2;
			i_y = 0;
		} else if (v_aspect > this.aspect) {  
			//if the viewport is too tall
			i_w = v_dim.width - v_pos.x;
			i_h = i_w / this.aspect;
			i_x = 0;
			i_y = (v_dim.height-i_h)/2;
		} else {
			//if the viewport is a perfect fit
			i_h = v_dim.height - v_pos.y;
			i_w = v_dim.width - v_pos.x;
			i_x = i_y = 0;
		}
		this.img.setStyles({'width':i_w,'height':i_h,'left':i_x,'top':i_y});
		this.fireEvent('image_fitted');
	}
});

var TaggablePhoto = new Class( {
	
	Extends: Events,
	
	initialize: function(id,embed) {
		this.photo_id = id;
		this.map = $('photo-map~'+this.photo_id);
		this.areas = this.map.getElements('area.tag');
		this.preload_thing_images();
	},
	
	preload_thing_images: function ( ) {
		this.images = [];
		this.areas.each(function(area) {
			var thingcode = area.getProperty('data-thingcode');
			var image = area.getProperty('data-image');
			if (image == null) image = '';
			this.images.include('http://beta.thinglink.com/thingPicture/'+thingcode+'/'+image+'/200/200/downScaled');
		}.bind(this));
		new Asset.images(this.images, { onComplete: this.on_images_loaded.bind(this) });
	},
	
	on_images_loaded: function () {
		this.ui = new TaggablePhotoUI(this.photo_id);
		this.ui.addEvent('ready', this.parse_map.bind(this));
	},
	
	parse_map: function(map) {
		
		this.areas.each(function(area) {
			var data = {
				'id':area.getProperty('data-id'),
				'name':area.getProperty('alt'),
				'thingcode':area.getProperty('data-thingcode'),
				'image':area.getProperty('data-image'),
				'creators':area.getProperty('data-creators'),
				'period':area.getProperty('data-period'),
				'price':area.getProperty('data-price'),
				'retailer_name':area.getProperty('data-retailer_name'),
				'purchase_url':area.getProperty('data-purchase_url'),
				'x1':area.getProperty('data-x1').toFloat(),
				'y1':area.getProperty('data-y1').toFloat(),
				'x2':area.getProperty('data-x2').toFloat(),
				'y2':area.getProperty('data-y2').toFloat()				
			};
			this.ui.add_tag(data);
		}.bind(this));
		
	}
});

var TaggablePhotoUI = new Class({
	
	Extends: Events,
	
	/********************************************************
	Initialize
	*********************************************************/
	
	initialize: function(id) 
	{
		this.READY = false;
		
		this.id = id;
		this.tags = new Array();
		
		this.photo = $('photo~'+this.id);
		this.load();
	},
	
	/********************************************************
	Load
	*********************************************************/
	
	load: function () 
	{
		this.image = this.photo.getElement('img');
		this.file = new Image();
		this.file.src = this.image.getProperty('src');
		this.load_check_periodical = this.load_check.periodical(100,this);
	},
	
	load_check: function () 
	{
		if (this.file.width > 0) 
		{
			$clear(this.load_check_periodical);
			this.on_ready();
		}
	},
	
	on_ready: function () {
		this.READY = true;
		this.tag_info = new PhotoTagInfo();
		this.photo.grab(this.tag_info,'bottom');
		this.photo.addEvents({
			'mouseenter': this.reveal.bind(this),
			'mouseleave': this.conceal.bind(this),
			'mousedown:relay(.photo-tag)':function(e) {
				var tag=e.target.getParents('.photo-tag')[0];
				tag.getElement('.nubbin').setStyle('background-position', 'center -19px');
			},
			'mouseup:relay(.photo-tag)':function(e) {
				var tag=e.target.getParents('.photo-tag')[0];
				tag.getElement('.nubbin').setStyle('background-position', 'center -20px');
				this.tag_info.expand(e.client.x,e.client.y);
			}.bind(this),
			'click:relay(.bounds)':function(e) { e.stop(); },
			'mouseover:relay(.photo-tag)': function(e) {
				var tag=e.target.getParents('.photo-tag')[0];
				this.tag_info.show(tag);
			}.bind(this),
			'mouseout:relay(.photo-tag)': function (e) {
				if (e.target.hasClass('nubbin') || e.relatedTarget.hasClass('nubbin')) return;
				this.tag_info.hide();
			}.bind(this)
		});
		this.fireEvent('ready');
	},
	
	/********************************************************
	Update
	*********************************************************/
	
	update: function () {
		if (!this.READY) return;
		this.width = this.image.width;
		this.height = this.image.height;
		this.tags.each(function(tag) {
			tag.drawOn(this.photo);
		}.bind(this));
	},

	add_tag: function (data) { 
		var tag = new PhotoTag(data);
		tag.drawOn(this.photo);
		this.tags.push(tag);
	},
	
	reveal: function () 
	{
		this.tags.each ( function(tag,id) {
			tag.hint();
		});	
	},
	
	conceal: function () {		
		this.tags.each ( function(tag,id) {
			tag.hide();
		});
	}
});

/**
 * Photo Tags
 * @author Ryan Betts
 * @version 0.1
 * @requires mootools, raphael
 */
var PhotoTag = new Class({
	
	initialize: function(data) {
		
		this.data=data;
		var tag = new Element('a',{'href':'/thing:'+this.data.thingcode,'class':'photo-tag'});
		this.nubbin = new Element('span',{'class':'nubbin'});
		this.bounds = new Element('span',{'class':'bounds'});
		this.tween = new Fx.Tween(this.nubbin, {duration: 150, transition: Fx.Transitions.Quad.easeInOut});
		tag.adopt([this.bounds,this.nubbin]);
		
		tag.addEvents({
			'mouseenter':this.show.bind(this),
			'mouseleave':this.hint.bind(this)
		});
		
		$extend(tag, this);
		return tag;
	},
	
	drawOn: function (photo) {
		
		var dim, x, y, w, h;
		photo.grab(this);
		dim = photo.getElement('img').getDimensions();
		pos = photo.getElement('img').getPosition();
		x = this.data.x1*dim.width;
		y = this.data.y1*dim.height;
		w = this.data.x2*dim.width - x;
		h = this.data.y2*dim.height - y; 
		
		this.setStyles({
			'left':x+pos.x,
			'top':y+pos.y-15
		});
		
		this.bounds.setStyles({
			'width':w,
			'height':h
		});
		
		this.nubbin.setStyles({
			'left':w/2-10,
			'top':h/2-10
		});
	},
	
	hint: function () { 
		this.nubbin.setStyle('background-position','center 0px'); 
		this.bounds.removeClass('bounds-hover'); 
		this.tween.cancel().start('opacity',1); 
	},
	hide: function () { 
		this.nubbin.setStyle('background-position','center 0px');
		this.bounds.removeClass('bounds-hover'); 
		this.tween.cancel().start('opacity',0); 
	},
	show: function () { 
		this.nubbin.setStyle('background-position','center -20px');
		this.bounds.addClass('bounds-hover'); 
		this.tween.cancel().start('opacity',1); 
	}
});

var PhotoTagInfo = new Class({
	template: "<div class='contents'>"+
								"<div class='details'><a href='http://beta.thinglink.com/thing:{thingcode}' class='name'>{name} <span class='period'>({period})</span></a><br/><span class='creators'>By {creators}</span></div>"+
								"<a href='http://beta.thinglink.com/thing:{thingcode}' class='image'><img src='http://beta.thinglink.com/thingPicture/{thingcode}/{image}/200/200/downScaled'/></a>"+
								"<ul class='actions'>"+
									"<li><a class='button like' href='/addAssociation.html?code={thingcode}&associationType=LIKE'>I like it</a></li>"+
									"<li><a class='button have' href='/addAssociation.html?code={thingcode}&associationType=OWN'>I have it</a></li>"+
									"<li><a class='button collection' href='http://beta.thinglink.com/thing:{thingcode}'>Add to collection</a></li>"+
									"<li><a class='button buy' href='{purchase_url}' target='_blank'>Buy from <strong>{retailer_name}</strong><br/><strong>{price}</strong></a></li>"+
									"<li><a class='dismiss' href='#'>x</a></li>"+
								"</ul>"+
							"</div>"+
						"</div>",
	initialize: function() {
		this.EXPANDED = false;
		var holder = new Element('div', {
			'class'			: 'photo-tag-info',
			'styles' 	: {
				'position' 	: 'absolute',
				'top' 			: 0,
				'left' 			: 0,
				'z-index'   : 100,
				'opacity'		: 0
			}
		});
		this.tip_tween = new Fx.Tween(holder, {duration: 150, transition: Fx.Transitions.Quart.easeIn});
		$extend(holder, this);
		return holder;
	},
	
	show: function(tag) {
		if (tag == null || this.EXPANDED) return;
		this.tag = tag;
		this.contents = Elements.from(this.template.substitute(tag.data))[0];
		this.contents.addClass('tip');
		this.contents.getElement('.dismiss').addEvent('click', this.collapse.bind(this));
		if (tag.data.price==null) this.contents.getElement('.buy').setStyle('display','none');
		if (tag.data.period==null) this.contents.getElement('.period').setStyle('display','none');
		this.empty().grab(this.contents);

		var tag_p, tag_d, tip_d, t_d, t_w, t_h, x, y, html;
		tip_d = this.getDimensions();
		tag_p = tag.getPosition();
		tag_d = tag.getDimensions();
		this.o_w = tip_d.width-14;
		this.o_h = tip_d.height-10;
		
		this.o_x = tag_p.x+tag_d.width/2-this.o_w/2-10;
		this.o_y = tag_p.y-this.o_h-19;
		if (this.o_y < 50) this.o_y = tag_p.y+tag_d.height+19;
		
		this.setStyles({'left':this.o_x,'top':this.o_y});
    this.tip_tween.cancel().start('opacity',1);
	},
		
	hide: function () {
		if (this.EXPANDED) return;
		this.tip_tween.cancel().set('opacity',0);
	},
	
	expand: function (x,y) {
		this.EXPANDED=true;
		new Drag.Move(this.contents);
		this.tag.bounds.setStyles({
			'border':'1px dashed #fff',
			'-moz-box-shadow': '0px 0px 6px #000',
			'-webkit-box-shadow': '0px 0px 6px #000',
	  	'box-shadow': '0px 0px 6px #000'
		});
		this.setStyles({'width':'100%','height':'100%','top':0,'left':0});
		this.contents.removeClass('tip');
		var container_dimensions = this.getDimensions();
		var content_dimensions = this.contents.getDimensions();
		var width = content_dimensions.width;
		var height = content_dimensions.height;
		var left = x+10;
		if (left < 20) left = 10;
		else if (left+width > container_dimensions.width) left = container_dimensions.width - width - 20;
		var top = y-20;
		if (top < 50) top = 50;
		else if (top+height > container_dimensions.height-30) top = container_dimensions.height - height - 30;
		this.contents.setStyles({
			'position':'absolute',
			'left':this.o_x,
			'top':this.o_y,
			'overflow':'hidden',
			'height':this.o_h,
			'width':this.o_w
		});
		this.expand_morph = new Fx.Morph(this.contents, {duration: 275, transition: Fx.Transitions.Expo.easeInOut}).start({
			'left':left,
			'top':top,
			'height':height-14,
			'width':width-10
		});
		this.addEvent('click', function(e) {
			if (e.target == this) this.collapse();
		}.bind(this));
	},
	
	collapse: function () {
		this.EXPANDED=false;
		this.removeEvents('click');
		this.expand_morph.cancel();
		this.collapse_morph = new Fx.Tween(this.contents, {duration: 100, transition: Fx.Transitions.Expo.easeOut}).start('opacity',0);
		this.collapse_morph.addEvent('complete',function(e) {
			this.contents.addClass('tip');
			this.setStyles({
				'width':'',
				'height':''
			});
			this.tag.bounds.setStyles({
				'border':'',
				'-moz-box-shadow': '',
				'-webkit-box-shadow': '',
		  	'box-shadow': ''
			});
		}.bind(this));
	}
});