/* 
 * CraftMap
 * author: Marcin Dziewulski
 * web: http://www.jscraft.net
 * email: info@jscraft.net
 * license: http://www.jscraft.net/licensing.html
 */

(function($){
    $.fn.craftmap = function(options) {
		var D = {
			cookies: false,
			fullscreen: false,
			container: {
				name: 'imgContent'
			},
			image: {
				width: 1475,
				height: 1200,
				name: 'imgMap'
			},
			map: {
				position: 'center'
			},
			marker: {
				name: 'marker',
				center: true,
				popup: true,
				popup_name: 'popup',
				onClick: function(marker, popup){},
				onClose: function(marker, popup){}
			},
			controls: {
				init: true,
				name: 'controls',
				onClick: function(marker){}
			},
			preloader: {
				init: true,
				name: 'preloader',
				onLoad: function(img, dimensions){}
			}
		}; // default settings
		
		var S = $.extend(true, D, options); 
		
        return this.each(function(){
			var M = $(this),
				IMG = M.find('.'+S.image.name),
				P = {
					init: function(){
						this._container.init();
						if (S.fullscreen) {
							this.fullscreen.init();
							this.fullscreen.resize();
						}
						this._globals.init();
						if (S.preloader.init) this.preloader.init();
						this.map.init();
						this.marker.init();
						if (S.controls.init) this.controls.init();
					},
					_container: {
						init: function(){
							P._container.css();
							P._container.wrap();
						},
						css: function(){
							var	max = {
									width: '100%',
									height: '100%'
								};
							IMG.css(max);
							var css = {
								position: 'relative', 
								overflow: 'hidden', 
								cursor: 'move'
							}
							M.css(css);
						},
						wrap: function(){
							var css = {
								zIndex: '1', 
								position: 'absolute',
								width: S.image.width,
								height: S.image.height
							}
							M.wrapInner($('<div />').addClass(S.container.name).css(css));
						}
					},
					_globals: {
						init: function(){
							C = M.find('.'+S.container.name),
							MARKER = C.find('.'+S.marker.name),
							md = false, mx = 0, my = 0, ex = 0, ey = 0, delta = 0, mv = [], interval = 0,
							D = {
								w: M.width(),
								h: M.height()
							},
							I = {
								w: C.width(),
								h: C.height()
							}
							if (S.controls.init){
								CONTROLS = $('.'+S.controls.name).find('a');
							}
						}
					},
					_mouse: {
						get: function(e){
							var x = e.pageX,
								y = e.pageY; 
							return {'x': x, 'y': y}
						},
						update: function(e){
							var mouse = P._mouse.get(e),
								x = mouse.x,
								y = mouse.y,
								movex = x-mx,
								movey = y-my,
								top = ey+movey,
								left = ex+movex,
								check = P.map.position.check(left, top),
								css = {
									top: check.y,
									left: check.x
								}
							C.css(css);
							if (S.cookies){
								P.cookies.create('position', check.x + ',' + check.y, 7);
							}
						},
						decelerate: function(e){
							var l = mv.length, timer = 0;
							if (l){
								var tc = 20;
								interval = setInterval(function(){
									var	position = C.position(), left = position.left, top = position.top,
										remain = (tc-timer)/tc,
										last = l-1,
										xd = (mv[last].x-mv[0].x)/l,
										yd = (mv[last].y-mv[0].y)/l,
										vx = xd*remain,
										vy = yd*remain,
										coords = P.map.position.check(vx+left, vy+top),
										css = {
											left: coords.x,
											top: coords.y
										};
									C.css(css);	
									++timer;
									if (timer == tc){
										clearInterval(interval);
										timer = 0;
									}
								}, 40);	
							}
						},
						wheel: {
							init: function(e){
								M.handle = function(e){
									e.preventDefault();
									if (!e) {
										e = window.event;
									}
									if (e.wheelDelta) {
										delta = e.wheelDelta/120;
										if (window.opera) {
											delta = -delta;
										}
									} else if (e.detail) {
										delta = -e.detail/3;
									}
								}
								if (window.addEventListener){
									window.addEventListener('DOMMouseScroll', M.handle, false);
								}	
								window.onmousewheel = document.onmousewheel = M.handle;
							},
							remove: function(){
								if (window.removeEventListener){
									window.removeEventListener('DOMMouseScroll', M.handle, false);
								}
								window.onmousewheel = document.onmousewheel = null;
							}
						}
					},
					fullscreen: {
						init: function(){
							var win = $(window), w = win.width(), h = win.height(),
								css = {
									width: w,
									height: h
								}
							M.css(css);
						},
						resize: function(){
							$(window).resize(function(){
								P.fullscreen.init();
								D = {
									w: M.width(),
									h: M.height()
								}
							});
						}
					},
					cookies: {
						create: function(name, value, days) {
							if (days) {
								var date = new Date(), set = date.getTime() + (days * 24 * 60 * 60 * 1000);
								date.setTime(set);
								var expires = '; expires=' + date.toGMTString();
							} else {
								var expires = '';
							}
							document.cookie = name+'='+value+expires+'; path=/';
						},
						erase: function(name) {
							cookies.create(name, '', -1);
						},
						read: function(name) {
							var e = name + '=',
								ca = document.cookie.split(';');
							for(var i=0;i < ca.length;i++) {
								var c = ca[i];
								while (c.charAt(0) == ' '){
									c = c.substring(1, c.length);
								}
								if (c.indexOf(e) == 0){
									return c.substring(e.length,c.length);
								}
							}
							return null;
						}
					},
					preloader: {
						init: function(){
							var img = new Image(),
								src = IMG.attr('src');
							P.preloader.create();
							$(img).addClass(S.image.name).attr('src', src).load(function(){
								var t = $(this),
									css = {
										width: this.width,
										height: this.height
									}
								t.css(css);
								IMG.remove();
								P.preloader.remove();
								S.preloader.onLoad.call(this, t, css);
							}).appendTo(C);
						},
						create: function(){
							var css = {
								position: 'absolute', 
								zIndex: '10', 
								top: '0', 
								left: '0', 
								width: '100%', 
								height: '100%'
							}
							M.append($('<div />').addClass(S.preloader.name).css(css));
						},
						remove: function(){
							M.find('.'+S.preloader.name).fadeOut(400, function(){
								var t = $(this);
								t.remove();
							});
						}
					},
					map: {
						init: function(){
							P.map.position.set();
							P.map.move();
						},
						position: {
							set: function(){
								if (S.cookies){
									if (typeof P.cookies.read('position') != 'null') {
										var position = P.cookies.read('position').split(','), 
											x = position[0], 
											y = position[1];
									} else {
										var x = (D.w-I.w)/2, 
											y = (D.h-I.h)/2;
									}
								} else {
									var position = S.map.position;
									switch (position){
										case 'center':
											var x = (D.w-I.w)/2,
												y = (D.h-I.h)/2;
											break;
										case 'top_left':
											var x = 0,
												y = 0;
											break;
										case 'top_right':
											var x = D.w-I.w,
												y = 0;
											break;
										case 'bottom_left':
											var x = 0,
												y = D.h-I.h;
											break;
										case 'bottom_right':
											var x = D.w-I.w,
												y = D.h-I.h;
											break;
										default:
											var coords = position.split(' '),
												x = -(coords[0]),
												y = -(coords[1]),
												coords = P.map.position.check(x, y),
												x = coords.x,
												y = coords.y;
									}	
								}
								var css = { top: y, left: x }
								C.css(css);
							},
							check: function(x, y){
								if (y < (D.h-I.h)){
									y = D.h-I.h;
								} else if (y > 0){
									y = 0;
								}
								
								if (x < (D.w-I.w)){
									x = D.w-I.w;
								} else if (x>0){
									x = 0;
								}
								return {'x': x, 'y': y}
							}
						},
						move: function(){
							C.bind({
								mousedown: function(e){
									md = true;
									var mouse = P._mouse.get(e);
										mx = mouse.x,
										my = mouse.y;
									var el = C.position();
										ex = el.left,
										ey = el.top;
										mv = [];
										clearInterval(interval);
									P._mouse.update(e);
									return false;
								},
								mousemove: function(e){
									if (md) {
										P._mouse.update(e);
										var mouse =  P._mouse.get(e),
											coords = {
												x: mouse.x,
												y: mouse.y
											}
										mv.push(coords);
										if (mv.length > 15){
											mv.pop();
										}	
									}
									return false;
								},
								mouseup: function(e){
									if (md)	md = false;
									P._mouse.decelerate(e);
									return false;
								},
								mouseout: function(){
									if (md)	md = false;
									P._mouse.wheel.remove();
									return false;
								},
								mouseover: function(e){
									P._mouse.wheel.init(e);
									return false;
								},
								mousewheel: function(e){
									P._zoom.init(e);
								}
							});
						}
					},
					_zoom: {
						init: function(e){}
					},
					marker: {
						init: function(){
							P.marker.set();
							P.marker.open();
							P.marker.close();
						},
						set: function(){
							MARKER.each(function(){
								var t = $(this), position = t.attr('data-coords').split(',');
									x = parseInt(position[0]), y = parseInt(position[1]),
									css = {
										position: 'absolute',
										zIndex: '2',
										top: y,
										left: x
									}
								t.css(css);
							}).wrapInner($('<div />').addClass(S.marker.name+'Content').hide());
						},
						open: function(){
							MARKER.live('click', function(){
								var t = $(this), id = t.attr('id'), marker = S.marker, w = t.width(), h = t.height(),
									position = t.position(), x = position.left, y = position.top, id = t.attr('id'),
									html = t.find('.'+marker.name+'Content').html();
									
								if (marker.center){
									var cy = -y+D.h/2-h/2,
										cx = -x+D.w/2-w/2,
										c = P.map.position.check(cx, cy),
										animate = {
											top: c.y,
											left: c.x
										};
									C.animate(animate);
								}
								
								if (marker.popup){
									$('.'+marker.popup_name).remove();
									var css = {
										position:'absolute', 
										zIndex:'3'
									}
									t.after(
										$('<div />').addClass(marker.popup_name+' '+id).css(css).html(html).append(
											$('<a />').addClass('close')
										)
									);
									var POPUP = t.next('.'+marker.popup_name), 
										pw = POPUP.innerWidth(), 
										ph = POPUP.innerHeight(),
										x0 = 0, y0 = 0;
									
									if (x-pw < 0){
										x0 = x;
									} else if (x+pw/2 > I.w){
										x0 = x-pw+w;
									} else {
										x0 = x-(pw/2-w/2);
									}
									
									if (y-ph < 0){
										y0 = y+h+h/1.5;
									} else {
										y0 = y-ph-h/1.5;
									}
									
									if (x-pw < 0 && y-ph < 0){
										x0 = x+w*2;
										y0 = y-h/2;
									} else if (y-ph < 0 && x+pw/2 > I.w){
										x0 = x-pw-w/2;
										y0 = y-h/2;
									} else if (y+ph > I.h && x+pw/2 > I.w){
										x0 = x-pw+w;
										y0 = y-ph-h/2;
									} else if (y+ph > I.h && x-pw < 0){
										x0 = x;
										y0 = y-ph-h/2;
									}
									
									var	css = {
											left: x0,
											top: y0
										}
									POPUP.css(css);
								}
								P.controls.active.set(id);
								marker.onClick.call(this, t, POPUP); 
								return false;
							});
						},
						close: function(){
							C.find('.close').live('click', function(){
								var t = $(this), popup = t.parents('.'+S.marker.popup_name), marker = popup.prev('.'+S.marker.name);
								popup.remove();
								P.controls.active.remove();
								S.marker.onClose.call(this, marker, popup);
								return false;
							});
						}
					},
					controls: {
						init: function(){
							P.controls.set();
						},
						set: function(){
							CONTROLS.click(function(){
								var t = $(this), rel = t.attr('rel');
								div = C.find('.'+ S.marker.name).filter('#'+rel);
								div.trigger('click');
								S.controls.onClick.call(this, div);
								return false;
							});
						},
						active: {
							set: function(id){
								if (S.controls.init){
									CONTROLS.removeClass('active').filter(function(){
										return this.rel == id;
									}).addClass('active');
								}
							},
							remove: function(){
								if (S.controls.init) {
									CONTROLS.removeClass('active');
								}
							}
						}
					}
				}
			P.init();
        });
    };
}(jQuery));