var MAP = ( function ( ) {

	var container, map, viewport;
	var currentChapter;
	var visited;
	
	var dragging, panning;

	var dragInitX, dragInitY;
	var mapInitX, mapInitY;

	function setupDragging ( ) {
		viewport.onmousedown = function ( e ) {
			e = e || window.event;
			clearTimeout ( panning );
			dragging = true;
			dragInitX = e.clientX;
			dragInitY = e.clientY;
			mapInitX = parseInt ( map.style.left );
			mapInitY = parseInt ( map.style.top );
			document.body.style.cursor = "move";
		}
		document.onmouseup = function ( ) {
			dragging = false;
			document.body.style.cursor = "default";
		}
		document.onmousemove = function ( e ) {
			if ( dragging ) {
				e = e || window.event;
				var deltaX = e.clientX - dragInitX;
				var deltaY = e.clientY - dragInitY;
				var x = mapInitX + deltaX;
				var y = mapInitY + deltaY;
				map.style.left = x + "px";
				map.style.top = y + "px";
				map.x = ( viewport.offsetWidth / 2 - x );
				map.y = ( viewport.offsetHeight / 2 - y );
			}
		}
	}
	
	var join = ( function ( ) {
		
		var normalise = function ( location, side ) {
			var nl = { x : location.x || 0, y : location.y || 0 };
			switch ( side.toUpperCase() ) {
				case "N":
					nl.y -= 5;
					break;
				case "E":
					nl.x += 5;
					break;
				case "S":
					nl.y += 5;
					break;
				case "W":
					nl.x -= 5;
					break;
			}
			return nl;
		}

		return function join ( a, b, curved, cb ) {
			if ( typeof cb != "function" ) cb = function ( ) { };

			var lineId = "line_" + a.id + "_" + b.id;
			var altLineId = "line_" + b.id + "_" + a.id;
			if ( document.getElementById(lineId) || document.getElementById(altLineId) ) {
				cb.call(this);
			} else {
				var an = NODES[a.id];
				var bn = NODES[b.id];
				drawLine (
					normalise ( an.location, a.side ),
					normalise ( bn.location, b.side ),
					lineId,
					curved,
					function ( ) { bn.show(); }
				);
			}
		}
	} )();
	
	function drawLine ( a, b, id, curved, cb ) {
	
		var line = document.createElement('li');
		line.className = "line";
		line.style.position = "absolute";
		line.style.left = a.x + "px";
		line.style.top = a.y + "px";
		line.style.opacity = 0.75;
		line.id = id;
		
		var dx = b.x - a.x;
		var dy = b.y - a.y;
		
		var d = Math.sqrt ( dx * dx + dy * dy );
		var m = ( b.y - a.y ) / ( b.x - a.x );
		
		var steps = d / 2; //co * 2; // * ( 3/4 );
		
		map.insertBefore ( line, map.childNodes[0] ); //appendChild ( line );
		var end = function ( ) {
			if ( typeof cb == "function" ) {
				cb();
			}
		}
		
		var step = function ( x, y, step ) {
			var e = document.createElement('span');
			e.className = "segment";
			e.innerHTML = "<span></span>";
			e.style.left = ( x - a.x - 2 ) + "px";
			e.style.top = ( y - a.y - 2 ) + "px";
			
			line.appendChild ( e );
				
			if ( step < steps ) {
				setTimeout ( function ( ) { f ( step + 1 ); }, 1 );
			} else {
				end();
			}
		}

		if ( false ) { // curved ) {
			
			var f = function ( s ) {
				step ( s );
			}
			
		} else {
		
			var f = function ( s ) {
				if ( dx != 0 ) {
					var tx = getTween ( s, a.x, dx, steps );
					var ty = m * ( tx - a.x ) + a.y;
					if ( isNaN ( ty ) ) ty = a.y;
				} else {
					var ty = getTween ( s, a.y, dy, steps );
					var tx = ( ( ty - a.y ) / m ) + a.x;
					if ( isNaN ( tx ) ) tx = a.x;
				}
				
				step ( tx, ty, s );
			}

		}
		
		setTimeout ( function ( ) { f ( 1 ) }, 1 );
	}

	return {
		init : function ( ) {
			this.init = function(){};
			container = document.getElementById('chapterMap');
			var divs = container.getElementsByTagName('div');
			map = divs[1].getElementsByTagName('ul')[0];
			viewport = divs[divs.length-1];
			viewport.ondblclick = function ( ) {
				MAP.panTo ( currentChapter );
			}
			this.hide(true);
			setupDragging();
		},
		getNodes : function ( ) {
			return map.getElementsByTagName('li');
		},
		show : function ( immediate, reset ) {
			var f = function ( o ) {
				StS.utils.DOM.setOpacity ( container, o );
				container.style.display = "block";
				if ( o < 100 ) {
					setTimeout ( function ( ) { f ( o + 2 ); }, 5 );
				}
			}
			f ( immediate ? 100 : ( reset ? 0 : container.opacity || 0 ) );
		},
		hide : function ( immediate, reset ) {
			var f = function ( o ) {
				if ( o == 0 ) {
					container.style.display = "none";
				} else {
					StS.utils.DOM.setOpacity ( container, o );
					setTimeout ( function ( ) { f ( o - 2 ); }, 10 );
				}
			}
			f ( immediate ? 0 : container.opacity || 100 );
		},
		panTo : function ( chapter, cb ) {
			currentChapter = chapter;
			if ( dragging ) {
				if ( typeof cb == "function" ) cb();
				return;
			}
			
			var mw = map.offsetWidth;
			var mh = map.offsetHeight;
			
			var curX = parseInt ( map.x || mw / 2 );
			var curY = parseInt ( map.y || mh / 2 );
			
			var x = NODES[chapter].location.x;
			var y = NODES[chapter].location.y;
			
			var deltaX = x - curX;
			var deltaY = y - curY;

			var steps = 50;
			
			var f = function ( step ) {
				var tweenX = getTween ( step, curX, deltaX, steps );
				var tweenY = getTween ( step, curY, deltaY, steps );

				map.x = tweenX;
				map.y = tweenY;
				
				map.style.left = ( viewport.offsetWidth / 2 - tweenX ) + "px";
				map.style.top = ( viewport.offsetHeight / 2 - tweenY ) + "px";
				
				if ( step < steps && !dragging ) {
					panning = setTimeout ( function ( ) { f ( step + 1 ); }, 10 );
				} else if ( typeof cb == "function" ) {
					cb();
				}
			}
			clearTimeout ( panning );
			f ( 1 );
		},
		visit : function ( chapter ) {
			NODES[chapter].show();
			this.panTo ( chapter, function ( ) {
				NODES[chapter].visit();
			} );
			/*
			join ( current, chapter, function ( ) {
				mapNodes[chapter].visit();
			} );
			*/
			/*
			var nodes = map.getElementsByTagName('li');
			for ( var i = 0, node; node = nodes[i]; i ++ ) {
				node.className = "";
			}
			if ( ( node = document.getElementById('node_chapter'+chapter) ) == null ) {
				node = document.createElement('li');
				node.id = "node_chapter" + chapter;
				node.innerHTML = "<span>Chapter " + chapter + "</span>";
				map.appendChild ( node );
			}
			node.className = "active";
			*/
		},
		join : function ( node1, node2, curved ) {
			var exit = null;
			var entry = null;
			var curved = false;
			
			for ( e in node1.exits ) {
				if ( node1.exits[e].id == node2.id ) {
					exit = e.toUpperCase();
					break;
				}
			}
			if ( !exit ) return;
			
			for ( e in node2.exits ) {
				if ( node2.exits[e].id == node1.id ) {
					entry = e.toUpperCase();
					break;
				}
			}
			
			switch ( exit ) {
				case "N":
					if ( !entry ) entry = "S";
					else if ( entry != "S" ) curved = true;
					break;
				case "E":
					if ( !entry ) entry = "W";
					else if ( entry != "W" ) curved = true;
					break;
				case "S":
					if ( !entry ) entry = "N";
					else if ( entry != "N" ) curved = true;
					break;
				case "W":
					if ( !entry ) entry = "E";
					else if ( entry != "E" ) curved = true;
					break;
			}

			join.call (
				this,
				{ id : node1.id, side : exit },
				{ id : node2.id, side : entry },
				curved,
				function ( ) {
					NODES[node1.id].show();
					NODES[node2.id].show();
				}
			);
		},
		appendChild : function ( child ) {
			map.appendChild ( child );
		}
	}
} )();

// t b c d
function getTween ( step, begin, delta, steps ) {
	if ( ( step /= steps / 2 ) < 1 ) 
		return delta / 2 * Math.pow ( step, 3 ) + begin; 
	return delta / 2 * ( Math.pow ( step - 2, 3 ) + 2 ) + begin;

	// return delta / 2 * ( 1 - Math.cos ( Math.PI * step / steps ) ) + begin;
}

( function ( ) {
	var directions = { NORTH : null, SOUTH : null, EAST : null, WEST : null };
	var directionOptions = {
		NORTH : null,
		SOUTH : {
			id : 1,
			text : "Start your story",
			callback : function ( ) {
				StS.utils.cookies.remove('cyogrinned','cyogrinning');
			}
		},
		EAST : null,
		WEST : null
	};
	var chapter;
	var navigating = false;
	
	var _TITLE_;
	var _CONTENT_;
	
	function getDirection ( direction ) {
		var control;
		switch ( (""+direction).toLowerCase() ) {
			case "north":
			case "38":
				control = directions.NORTH; break;
			case "east":
			case "39":
				control = directions.EAST; break;
			case "south":
			case "40":
				control = directions.SOUTH; break;
			case "west":
			case "37":
				control = directions.WEST; break;
			default:
				control = null;
		}
		if ( control ) return control;
		 return { direction : null };
	}

	function slideOut ( style, direction, cb ) {
		var initX = 36;
		var initY = 78;
		if ( arguments.length <= 3 ) {
			chapter.style.top = initY + "px";
			chapter.style.left = initX + "px";
		}

		var step = arguments[3] || 1;
		var steps = 50;
		var delta = chapter.parentNode[style == "top" ? "offsetHeight" : "offsetWidth"];
		var init = ( style == "top" ? initY : initX );
		var tween = getTween ( step, 0, delta, steps );

		chapter.style[style] = init + ( tween * direction ) + "px";
		//StS.utils.DOM.setOpacity ( chapter, 100 / steps * ( steps - step ) );

		if ( step < steps ) {
			setTimeout ( function ( ) { slideOut ( style, direction, cb, step + 1 ); }, 10 );
		} else if ( typeof cb == "function" ) {
			cb();
		}
	}
	function slideIn ( style, direction, cb ) {
		var initX = 36;
		var initY = 78;
		var init = chapter.parentNode["offset" + ( style == "top" ? "Height" : "Width" )] * direction;;
		if ( arguments.length <= 3 ) {
			if ( style == "top" ) {
				chapter.style.left = initX + "px";
			} else if ( style == "left" ) {
				chapter.style.top = initY + "px";
			}
			chapter.style[style] = init + "px";
		}

		var step = arguments[3] || 1;
		var steps = 50;
		var delta = Math.abs ( init - ( style == "top" ? initY : initX ) ) * direction * -1;
		var tween = getTween ( step, delta, init, steps );

		chapter.style[style] = tween + "px";
		//StS.utils.DOM.setOpacity ( chapter, 100 / steps * step );

		if ( step < steps ) {
			setTimeout ( function ( ) { slideIn ( style, direction, cb, step + 1 ); }, 10 );
		} else if ( typeof cb == "function" ) {
			cb();
		}
	}
	
	function checkDirectionOptions ( ) {
		for ( d in directionOptions ) {
			var c = getDirection(d);
			if ( directionOptions[d] != null ) {
				( function ( dir ) {
					setTimeout ( function ( ) {
						enable ( dir );
					}, 500 );
				} ) ( d );
				c.chapter = directionOptions[d].id;
				c.control.href = "/chapter/" + directionOptions[d].id + "/";
				text = directionOptions[d].text;
			} else {
				disable ( d );
				text = null;
				c.control.href = "#";
			}
			if ( text ) {
				text = text.replace ( /&#(\d+);/g, function ( a, m ) {
					return String.fromCharCode ( parseInt ( m ) );
				} );
			}
			c.control.innerHTML = '<span class="i1"><span class="i2">' + ( text || "" ) + '</span></span>';
			c.title = unescape (  text ) || "";
		}
	}
	
	function getContent ( url, cb ) {
		var key = "content/" + encodeURIComponent ( url );
		if ( content = StS.cache.get ( key ) ) {
			cb ( content );
		} else {
			StS.server.get ( url, {
				onComplete : function ( r ) {
					StS.cache.set ( key, r );
					cb ( r );
				}
			} );
		}
	}
	
	
	function getChapter ( chapter, cb ) {
		var node = NODES[chapter];
		if ( !node ) return;
		/*_TITLE_.innerHTML = node.title;*/
		MAP.visited = ""+StS.utils.cookies.get('cyogrinned');
		for ( d in directionOptions ) {
		    directionOptions[d] = node.directionOption(d.charAt(0).toUpperCase());
		}
		StS.server.get ( node.contentUrl, {
			onComplete : function ( rsp ) {
				_CONTENT_.innerHTML = '<div class="inner">' + rsp.response + '</div>';
				if ( typeof cb == "function" ) cb();
			},
			useCache : false
		} );
		/*
		StS.server.get ( "/chapter/" + chapter + "/", {
			onComplete : function ( r ) {
				try {
					var rsp = eval ( "(" + r + ")" );
					_TITLE_.innerHTML = rsp.title;
					MAP.nodes[chapter].exits = rsp.exits;
					MAP.nodes[chapter].title = rsp.title;
					for ( d in directionOptions ) {
						directionOptions[d] = rsp.exits[d.substr(0,1)];
					}
					getContent ( rsp.contentUrl, function ( c ) {
						_CONTENT_.innerHTML = c;
						if ( typeof cb == "function" ) cb();
					} );
				} catch ( e ) {
					var a = [];
					for ( i in e ) {
						a.push ( i + " = " + e[i] );
					}
					a.sort();
					alert ( a.join ( "\n\n" ) );
				}
			},
			onError : function ( err ) {
				alert ( err.message );
			}
		} );
		*/
	}

	var isCentered = ( function ( ) {
		// put the chapter IDs of all chapters that require vertical centering in this array
		// we can easily black-box this if that makes more sense
		var centered = [ 1, 14, 15, 16, 17, 18, 19, 20 ];
		return function ( cId ) {
			return ("," + centered.join(",") + ",").indexOf ( "," + cId + "," ) > -1;
		}
	} )();

	function navigate ( direction ) {
		if ( !navigating && (control = getDirection(direction)).direction != null  && directionOptions[control.direction.toUpperCase()] != null ) {
			for ( d in directions ) {
				deactivate ( d );
				disable ( d );
			}
			navigating = true;
			var end = function ( ) {
				checkDirectionOptions();
				navigating = false;
			}
			var start = function ( s, d ) {
				if ( typeof ( f = directionOptions[control.direction.toUpperCase()].callback ) == "function" ) {
					f();
				}
				slideOut ( s, d, function ( ) {
					var chapter = getDirection(direction).chapter;
					getChapter ( chapter, function ( ) {
						MAP.show();
						MAP.visit ( chapter );
						document.getElementById('chapter').className = "c" + chapter + ( isCentered ( chapter ) ? " centered" : "" );
						slideIn ( s, d, end );
					} );
				} );
			}
			switch ( control.direction ) {
				case "north":
					start ( "top", 1 );
					break;
				case "east":
					start ( "left", -1 );
					break;
				case "south":
					start ( "top", -1 );
					break;
				case "west":
					start ( "left", 1 );
					break;
			}
		}
	}
	function activate ( direction ) {
		if ( !navigating ) {
			var control = getDirection ( direction );
			if ( control.direction && directionOptions[control.direction.toUpperCase()] ) {
				if ( !control.className.match(/\bactive\b/) )
					control.className += " active";
			}
		}
	}
	function deactivate ( direction ) {
		var control = getDirection ( direction );
		if ( control.direction ) {
			control.className = control.className.replace(/\bactive\b/,'').replace(/(^\s*|\s*$)/,'');
		}
	}
	function disable ( direction ) {
		var control = getDirection ( direction );
		if ( control.direction ) {
			if ( !control.className.match(/\bdisabled\b/) )
				control.className += " disabled";
			control.disabled = true;
		}
	}
	function enable ( direction ) {
		var control = getDirection ( direction );
		if ( control.direction ) {
			control.className = control.className.replace(/\bdisabled\b/,'').replace(/(^\s*|\s*$)/,'');
			control.disabled = false;
		}
	}

	function handleKeyEvent ( e ) {
		e = e || window.event;
		if ( e.keyCode >= 37 && e.keyCode <= 40 ) {
			if ( e.type == "keyup" ) {
				navigate ( e.keyCode );
				return false;
			} else if ( e.type == "keydown" ) {
				activate ( e.keyCode );
			}
		} else {
			//alert ( e );
		}
	}
	//window.addEvent ( 'keydown', handleKeyEvent );
	//window.addEvent ( 'keyup', handleKeyEvent );
	window.onkeydown = handleKeyEvent;
	window.onkeyup = handleKeyEvent;
	/*
	window.onkeyPress = handleKeyEvent;
	document.onKeyDown = handleKeyEvent;
	document.onKeyUp = handleKeyEvent;
	document.onKeyPress = handleKeyEvent;
	*/
	/*
	window.addEvent ( 'domready', function ( ) {
		setupControls();
		chapter = document.getElementById('chapter');
		_TITLE_ = chapter.getElementsByTagName('h2')[0];
		_CONTENT_ = chapter.getElementsByTagName('div')[0];
		MAP.init();
		checkDirectionOptions();
	} );
	*/

	var currentGame = false;
	if ( current = StS.utils.cookies.get('cyogrinning') ) {
		directionOptions['EAST'] = {
			id : current,
			text : "Resume your story",
			callback : function ( ) {
				var visited = (""+StS.utils.cookies.get('cyogrinned')).split('.');
				for ( var i = 0; i < visited.length; i ++ ) {
					NODES[visited[i]].visit();
				}
			}
		};
		currentGame = true;
	}

	document.whenReady (
		function ( ) {
			// set up controls
			var controls = document.getElementById('chapterNavigation').getElementsByTagName('li');
			for ( var i = 0, c; c = controls[i]; i ++ ) {
				c.innerHTML = "";
				c.direction = (c.className.match(/\b(north|east|south|west)\b/i))[1];
				var background = StS.utils.DOM.create ( "span", {
					"class" : "background",
					parent : c
				} );
				c.control = StS.utils.DOM.create ( "span", {
					"class" : "content",
					parent : c
				} );
				c.onclick = function ( ) {
					navigate ( this.direction );
				}
				directions[c.direction.toUpperCase()] = c;
				/*
				//var control = c.getElementsByTagName('a')[0];
				if ( control != null ) {
					c.direction = (c.className.match(/\b(north|east|south|west)\b/i))[1];
					c.control = control;
					control.onmousemove = function ( ) { activate ( this.parentNode.direction ); }
					control.onmouseout = function ( ) { deactivate ( this.parentNode.direction ); }
					c.onclick = function ( ) {
						navigate ( this.direction );
						this.blur();
						return false;
					}
					directions[c.direction.toUpperCase()] = c;
				}
				*/
			}
		},
		checkDirectionOptions,
		function ( ) {
			if ( currentGame ) {
				//document.getElementById('load').id = "";
			}
			chapter = document.getElementById('chapter');
			_TITLE_ = chapter.getElementsByTagName('h2')[0];
			_CONTENT_ = chapter.getElementsByTagName('div')[0];
			MAP.init();
		}
	);

} )();
