/*
Copyright (c) 2009 Marcello Mamino

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

var Bird = function(){with(Utils)with(Dom_utils){

	var image_extension = ie6?".gif":".png"; // ie6 is defined in nicebrowser.js
	
	var open_bird_address = "bird-open"+image_extension;
	var closed_bird_address = "bird-closed"+image_extension;
	var bird_head_address = "bird-top"+image_extension;
	var sad_balloon_address = "balloon-sad"+image_extension;
	var happy_balloon_address = "balloon-happy"+image_extension;
	
	var bird_height = "85px";
	var bird_width = "100px";
	var beak_center = [25,35]; // px
	var beak_tip = [10,32]; // px
	var clock_tick = 257; // ms
	var animation_tick = 25; // ms
	var travel_time = 100; // animation ticks
	var long_travel_time = 200; // animation ticks
	var anxiety_treshold = 150;
	var mouse_scaryness = 50;
	var balloon_persistence = 3000; // ms
	
	var open_birds;
	var closed_birds;
	var fixed_birds;
	var moving_bird;
	var sad_balloon;
	var happy_balloon;
	
	var current_bird = undefined;
	var stay_invisible = false;
	var very_scared = false;
	var anxiety = 0;
	
	var create_image = function(address)
	{
		var img = absolute_zero(remove_border(document.createElement("img")));
		img.src = address;
		return img;
	}
	
	var create_bird = function()
	{
		var bird = make_invisible(remove_border(document.createElement("div")));
		var open = create_image(open_bird_address);
		var closed = create_image(closed_bird_address);
		open.className = "open-bird";
		closed.className = "closed-bird";
		bird.appendChild(open);
		bird.appendChild(closed);
		bird.style.height = bird_height;
		bird.style.width = bird_width;
		return bird;
	}
	
	var add_bird_top = function(bird)
	{
		var bird_top = absolute_zero(remove_border(document.createElement("div")));
	
		var exp = document.getElementById("exp");
		var moving_exp = absolute_zero(exp.cloneNode(true));
		moving_exp.style.visibility = "";
		bird_top.appendChild(moving_exp);
	
		var head = create_image(bird_head_address);
		bird_top.appendChild(head);
	
		bird.appendChild(bird_top);
	
		var moving_two = getElementsByClassName(moving_exp,"span","exp")[0];
		var cx = Math.floor(moving_two.offsetWidth/2);
		var cy = Math.floor(moving_two.offsetHeight/2);
		moving_two.style.position = "absolute";
		bird_top.home = vector_plus(beak_center,[-cx,-cy]);
		set_position(moving_two,bird_top.home);
	
		return bird_top;
	}
	
	var prepare_site = function(site)
	{
		var bird = create_bird();
		with(bird.style) {
			position = "relative";
			top = "-"+bird_height;
			width = bird_width;
		}
		site.appendChild(bird);
		site.bird = bird;
		return bird;
	}
	
	var create_moving_bird = function()
	{
		var bird = absolute_zero(create_bird(true));
		document.getElementById("body").appendChild(bird);
		return bird;
	}
	
	var create_balloon = function(file_name)
	{
		var balloon = make_invisible(remove_border(document.createElement("img")));
		balloon.src = file_name;
		balloon.style.position = "absolute";
		document.getElementById("body").appendChild(balloon);
		return balloon;
	}
	
	var go = function(obj,to_obj,correction,arc,time,continuation)
	{
		var args = arguments;
		var interval;
		var src = get_position(obj);
		var dst = get_position(to_obj);
		var delta = vector_plus(dst,correction,vector_times(-1,src));
		var atled = [-delta[1],delta[0]];
		var orig_time = time;
	
		var _go = function()
		{
			if(time>0) {
				if(vector_eql(dst,get_position(to_obj))) {
					var f = time/orig_time;
					f=f*f; f=1-f; f=f*f;
					var g = arc*f*(1-f);
					var h = vector_plus(src,vector_times(f,delta),vector_times(g,atled));
					set_position(obj,h);
				} else {
					clearInterval(interval);
					go.apply(null,args);
				}
				time--;
			} else {
				set_position(obj,vector_plus(get_position(to_obj),correction));
				clearInterval(interval);
				continuation();
			}
		}
	
		interval = setInterval(_go,animation_tick);
	}
	
	var fly = function(obj,from,to,continuation)
	{
		set_position(obj,get_position(from));
		make_visible(obj);
		make_invisible(from);
		var cont = function() {
			make_visible(to);
			make_invisible(obj);
			continuation();
		}
		var v1 = get_position(from);
		var v2 = get_position(to);
		var delta = vector_plus(v2,vector_times(-1,v1));
		var d = vector_norm(delta);
		var arc_abs = d>0 ? 300/d : 0;
		var arc = Math.abs(delta[0]) < Math.abs(delta[1]) ?
				-arc_abs :
				delta[0]>0 ? -arc_abs : arc_abs;
		go(obj,to,[0,0],arc,travel_time,cont);
	}
	
	var show_balloon = function(balloon,bird)
	{
		set_position(balloon,
			vector_plus(	get_position(bird),
					beak_tip,
					vector_times(-1,[balloon.offsetWidth,balloon.offsetHeight])));
		make_visible(balloon);
		setTimeout(function(){make_invisible(balloon);},balloon_persistence);
	}
	
	var close_beak = function()
	{
		map(make_visible,closed_birds);
		map(make_invisible,open_birds);
	}
	
	var open_beak = function()
	{
		map(make_visible,open_birds);
		map(make_invisible,closed_birds);
	}
	
	var clopen = function()
	{
		if(arguments.callee.state = !arguments.callee.state) close_beak();
		else open_beak();
		var t = Math.random()<0.25 ?
				1000+Math.floor(Math.random()*3000):
				100;
		if(Math.random()<0.01 && current_bird && !very_scared && is_in_viewport(current_bird))
			show_balloon(happy_balloon,current_bird);
		setTimeout(clopen,t);
	}
	
	var remove_current_bird = function()
	{
		var bird = current_bird;
		current_bird = null;
		bird.onmouseover = "";
		return bird;
	}
	
	var make_current_bird = function(bird)
	{
		current_bird = bird;
		bird.onmouseover = when_scared;
	}
	
	var go_somewhere = function(choice_p)
	{
		var this_bird = remove_current_bird();
		var other_birds = filter(function(e){return e!=this_bird;},fixed_birds);
		var choose_from = filter(choice_p,other_birds);
		if(choose_from.length==0) choose_from = other_birds;
		var destination = choose_from[ Math.floor(choose_from.length * Math.random()) ];
	
		var cont = function() {make_current_bird(destination);};
		fly(moving_bird,this_bird,destination,cont);
	}
	
	var go_if_you_can = function(choice_p)
	{
		if(!choice_p(current_bird) && exists(fixed_birds,choice_p))
			go_somewhere(choice_p);
	}
	
	var when_scared = function()
	{
		anxiety += mouse_scaryness;
		very_scared =	   very_scared
				|| anxiety > anxiety_treshold
				|| for_all(fixed_birds,function(x){return x==current_bird || !is_in_viewport(x);});
		if(very_scared) show_balloon(sad_balloon,current_bird);
		stay_invisible = very_scared;
		go_somewhere(very_scared?negate(is_in_viewport):is_in_viewport);
	}
	
	var move_around = function()
	{
		if(anxiety<=0) very_scared = false;
		else anxiety--;
	
		if(!current_bird) return;
	
		if(very_scared)
			go_if_you_can(negate(is_in_viewport));
		else if(is_in_viewport(current_bird))
			stay_invisible = false;
		else if(!stay_invisible)
			go_if_you_can(is_in_viewport);
	}
	
	var init = function()
	{
		var landing_sites = getElementsByClassName(document,"div","landing-site");
	
		sad_balloon = create_balloon(sad_balloon_address);
		happy_balloon = create_balloon(happy_balloon_address);
	
		fixed_birds = map(prepare_site,landing_sites);
		moving_bird = create_moving_bird();
	
		open_birds = getElementsByClassName(document,"img","open-bird");
		closed_birds = getElementsByClassName(document,"img","closed-bird");
	
		setInterval(move_around,clock_tick);
	}
	
	var run_sequence = function(s)
	{
		var _do = function(n) {
			if(s[n]) s[n](function(){_do(n+1);});
		};
		_do(0);
	}
	
	var start = function()
	{
		init();
	
		var exp = document.getElementById("exp");
		var bird_top;
		run_sequence([
			function(continuation) {
				close_beak();
				bird_top = add_bird_top(moving_bird);
				// go to the starting position on the right of the screen
				set_position(moving_bird,[document.body.offsetWidth+100,0]);
				// fly to the page's title
				make_visible(moving_bird);
				var static_two = getElementsByClassName(exp,"span","exp")[0];
				go(moving_bird,static_two,vector_times(-1,bird_top.home),-0.5,long_travel_time,continuation);
			}, function(continuation) {
				// drop the "2"
				make_visible(exp);
				open_beak();
				make_invisible(bird_top);
				// fly somewhere
				first_base = document.getElementById("first-base").bird;
				go(moving_bird,first_base,[0,0],-1,long_travel_time,continuation);
			}, function(continuation) {
				make_visible(first_base);
				make_invisible(moving_bird);
				// start the main cycle
				clopen();
				make_current_bird(first_base);
				show_balloon(happy_balloon,first_base);
			}
		]);
	}
	
	var all_visible = function()
	{
		map(make_visible,fixed_birds);
	}

	return {
		start:		start,
		all_visible:	all_visible
	}
}}();
