Hash.ify = function(a) {
	answer = $H();
	a.each(function(el) { answer.set(el.id, el)})
	a.get = answer.get.bind(answer)
	a.keys = answer.keys.bind(answer)
	return answer;
}

function loaded()
{
	$$(".highlight").each(function(link) {
		var href = link.href;
		var id = href.substr(href.indexOf("#") + 1)
		var target = $(id)
		
		if (target)
		{
			link.href = "#"
			Event.observe(link, "click", function() {
				new Effect.ScrollTo(target, {duration: 0.75, afterFinish: function() {
					window.location = window.location + id
					new Effect.Highlight(target, {startcolor: "#BBBBFF"});
					new Effect.Highlight(target.nextSiblings().first(), {startcolor: "#BBBBFF"})			
				}})
			});
		}
	})
	
	//var flash = $$("flash");
	
	$$(".flash").each(function(f) {
		new Effect.Highlight(f, {startcolor: f.hasClassName("error") ? "#ffbbbb" : "#bbbbff"})
	});
	
	//var important = $$("important")
	
	$$(".important").each(function(f) {
		f.pulsate();
	})
	
	connect();
}

Event.observe(window, "load", loaded)

function connect()
{
	
	if ($("itches"))
	{
		Hash.ify(itches = $("itches").getElementsBySelector(".itch").collect(function(e) { return new Itch(e)}))
	}

	Building.find($("map"));
	
	if ($("scheduler"))
	{
		scheduler = new Scheduler($("scheduler"))
		
		
		if (setPaths)
		{
			setPaths();
		}

	}
	
	if ($("users"))
	{
		users = $("users").getElementsBySelector(".user").collect(function(e) { return new User(e)})
		Hash.ify(users)
	}
	
	if ($("appointments"))
	{
		Hash.ify(appointments = $("appointments").getElementsBySelector(".appointment").collect(function(e) { return new Appointment(e)}))
	}
	
	if ($("connexions"))
	{
		Hash.ify(connexions  = $("connexions").getElementsBySelector(".connexion").collect(function(e) { return new Connexion(e)}));
	}
	
	if ($("users"))
	{
		users.each(function(u) { u.proxy()})
		User.fadeLatest();
	}
}

var Connector = Class.create({
	initialize: function(e, events) {
		this.e = e;
		this.id = e.id.split("_").last();
		
		if (events)
		{
			Event.observe(e, "mouseenter", this.entered.bind(this))
			Event.observe(e, "mouseleave", this.left.bind(this))
		}
	}, 
	
	extract: function(selector) {
		return this.e ? this.e.getElementsBySelector(selector).first() : null;
	},
	
	parse: function(selector) {
		return this.extract(selector).innerHTML;
	},
	
	parseInt: function(selector) { return parseInt(this.parse(selector))},
	
	makeActive: function() { this.e.addClassName("active")},
	makeHyperactive: function() { this.e.addClassName("hyper")},
	makeInactive: function() { 
		this.e.removeClassName("active"); 
		this.e.removeClassName("hyper")
	},
	
	entered: function() {
		//console.log("entered")
	},
	
	left: function() {
		//console.log("left")
	}
})

var Itch = Class.create(Connector, {
	initialize: function($super, e) {
		$super(e, true);
		this.confluences = $A()
		this.countE = this.extract(".count")
	},
	
	entered: function($super) {
		this.makeActive();
		
		this.confluences.each(function(confluence) {
			confluence.building().itch(confluence.itch);
			
			confluence.building().makeHyperactive();
			confluence.makeHyperactive();
		});
	},
	
	count: function(c) {
		this.countCache = this.countE.innerHTML;
		this.countE.innerHTML = c;
	},
	
	uncount: function() {
		this.countE.innerHTML = this.countCache;
	},
	
	left: function($super) {
		this.makeInactive();
		
		this.confluences.each(function(confluence) {
			confluence.building().unitch();
			confluence.building().makeInactive();
			confluence.makeInactive()
		})
	}
});

var Connexion = Class.create(Connector, {
	initialize: function($super, e) {
		$super(e, true)
		
		e.style.opacity = 0.1
	},
	
	entered: function($super) {
		connexions.each(function(c) { c.makeActive(); })
	},
	
	left: function($super) {
		connexions.each(function(c) { c.makeInactive(); })
	},
	
	makeActive: function() {
		this.e.style.opacity = 1
	},
	
	makeInactive: function() {
		this.e.style.opacity = 0.1
	}
})

var Building = Class.create(Connector, {
	initialize: function($super, e) {
		$super(e)
		
		this.confluencesE = this.extract(".confluences")
		
		this.confluences = Confluence.find(this.confluencesE, this)
		
		Event.observe(this.extract(".connector"), "click", this.clicked.bind(this))
		
		this.timeE = this.extract(".time")
		//this.untime()
		
		this.distanceE = this.extract(".distance")
		
		this.proxiesE = this.extract(".proxies")
		
		//if (!e.hasClassName("empty"))
		this.empty = e.hasClassName("empty")
		{
			Event.observe(e, "mouseenter", this.enter.bind(this));
			Event.observe(e, "mouseleave", this.leave.bind(this));
		}
	},
	
	enter: function() {
		if (!this.empty)	this.confluencesE.show();
		this.distanceFromMe();
	},
	
	makeHyperactive: function($super) {
		$super();
		this.distanceFromMe();
	},
	
	makeInactive: function($super) {
		$super();
		this.undistance();
	},
	
	distanceFromMe: function() {
		me = this;
		buildings.each(function(b) { b.distance(me)});
	},
	
	leave: function() {
		if (!this.empty) this.confluencesE.hide()
		buildings.each(function(b) { b.undistance()});
	},
	
	distance: function(other) {
		this.distanceE.innerHTML = this.distances.get(other.id)
		this.distanceE.show();
	},
	
	undistance: function() {
		this.distanceE.hide();
	},
	
	clicked: function() {
		if (origin)
		{
			new Ajax.Request(
				"/connexions/create",
				{ parameters: "connexion[building_id_target]=" + this.id + "&" + "connexion[building_id]=" + origin.id}
			);
			origin = null;
		}
		else
		{
			origin = this;
			origin.activate();
		}
	},
	
	activate: function() {
		this.e.appear({to: 0.5})
	},
	
	bottom: function() {
		return this.e.offsetTop + this.e.offsetHeight
	},
	
	time: function(t) { this.timeE.innerHTML = "@" + t; this.timeE.show()},
	untime: function() { this.timeE.hide()},
	
	itch: function(itch) {
		this.confluences.each(function(c) { 
			if (c.itch != itch)
			{
				c.e.hide();
			}
		})
		this.confluencesE.show();
	},
	
	unitch: function(itch) {
		this.confluences.each(function(c) { c.e.show(); c.makeInactive()})
		this.confluencesE.hide();
	},
	
	appoint: function(confluence, time) {
		this.makeActive();
		this.confluences.each(function(c) { if (c.id != confluence.id) c.e.hide(); })
		if (time) this.time(time)
		this.confluencesE.show();
	},
	
	unappoint: function(confluence) {
		this.makeInactive();
		this.confluencesE.hide();
		this.untime();
		this.confluences.each(function(c) { c.e.show(); c.makeInactive()})
	}
})

Building.find = function(container) {
	if (container)
	{
	buildings = container.getElementsBySelector(".building").collect(function(element) { return new Building(element)})
	origin = null
	
	building_hash = Hash.ify(buildings)
	
	confluences = buildings.collect(function(b) { return b.confluences ? b.confluences : []}).flatten()
	Hash.ify(confluences)
	}
}

var Confluence = Class.create(Connector, {
	initialize: function($super, e, building) {
		$super(e, true);
		
		this.a = this.parse(".a")
		this.b = this.parse(".b")
		this.c = this.parse(".c")
		this.d = this.parse(".d")
		this.f = this.parse(".f")
		
		this._appointments = null;
		
		//debugger;
		
		this.itch = itches.get((this.extract(".itch").getAttribute("itch_id")))
		this.itch.confluences.push(this);
		
		this._building = building
		
		Event.observe(e, "click", this.use.bind(this))
	},
	
	use: function() {
		scheduler.confluence(this)
	},
	
	building: function() { return this._building},
	
	appointments: function() {
		if (this._appointments == null)
		{
			id = this.id
			this._appointments = appointments.select(function(a) { return a.confluence().id == id})
		}
		
		return this._appointments;
	},
	
	entered: function() {
		this.appointments().each(function(a) { a.show()})
	},
	
	left: function() {
		this.appointments().each(function(a) { a.hide()})
	}
})

Confluence.find = function(container, building) {
	if (container)
	{
		return container.getElementsBySelector(".confluence").collect(function(e) { return new Confluence(e, building)});
	}
}

Scheduler = Class.create(Connector, {
	initialize: function($super) {
		$super($("scheduler"));
		
		this.confluenceE = this.extract(".confluence")
		this.confluenceField = this.extract("#appointment_confluence_id")
		
		this.aE = this.extract(".user_1")
		this.aField = this.extract("#appointment_user_id")
		
		this.bE = this.extract(".user_2")
		this.bField = this.extract("#appointment_user_target_id")
		
		this.timeField = this.extract("#appointment_time")
		
		new Form.Element.EventObserver(this.timeField, this.checkReady.bind(this))
		
		this.button = this.extract(".submit")
		this.button.disabled = true
		
		Event.observe(this.extract(".clearer"), "click", this.clear.bind(this))
	},
	
	confluence: function(c) {
		clone = c.e.cloneNode(true)
		this.confluenceE.replace(clone)
		this.confluenceE = clone
		this.confluenceField.value = c.id
		this.checkReady();
	},
	
	user: function(u) {
		clone = u.e.cloneNode(true);
		
		if (this.choosingA())
		{
			field = this.aField
			el = this.aE
		}
		else
		{
			field = this.bField
			el = this.bE
		}
		
		field.value = u.id
		el.getElementsBySelector(".user").first().replace(clone)
		//el.replaceChild(el.getElementsBySelector(".user").first(), clone)
		
		this.checkReady();
	},
	
	checkReady: function() {
		if (!(this.aField.value.blank() || this.bField.value.blank() || this.confluenceField.value.blank() || this.timeField.value.blank()))
		{
			this.button.disabled = false;
		}
	},
	
	choosingA: function() { 
		return this.aField.value.blank();
	},
	
	clear: function() {
		this.confluenceE.innerHTML = "";
		this.confluenceField.value = "";
		this.aE.innerHTML = "<div class=\"user\">none</div>"
		this.aField.value = "";
		this.bE.innerHTML = "<div class=\"user\">none</div>"
		this.bField.value = ""
		this.button.disabled = true
	}
})

var User = Class.create(Connector, {
	initialize: function($super, e) {
		$super(e, true);
		
		this.timeE = this.extract(".time")
		
		this.proxyE = this.extract(".proxy")
		
		this.countE = this.extract(".count")
		
		Event.observe(e, "click", this.move.bind(this))
		Event.observe(e, "mouseenter", this.show.bind(this))
		Event.observe(e, "mouseleave", this.hide.bind(this))
	},
	
	proxy: function() {
		if (appointments.size() > 0)
		{
		mt = this.maxtime();
		lasta = this.appointments().find(function(a) { return a.time == mt})
		
		if (lasta)
		{
			lasta.confluence().building().proxiesE.appendChild(this.proxyE.cloneNode(true))
		}
		}
	},
	
	move: function() {
		scheduler.user(this)
	},
	
	appointments: function() {
		if (!this._appointments)
		{
			myid = this.id
			this._appointments = appointments.select(function(a) { return a.teams.include(myid)});
		}
		
		return this._appointments
	},
	
	maxtime: function() {
		return this.appointments().collect(function(a) { return a.time}).max();
	},
	
	show: function() {
		this.makeActive();
		
		maxtime = this.maxtime();
		
		this.appointments().each(function(a) {
			a.confluence().building().appoint(a.confluence(), a.time);
			
			if (a.time == maxtime)
			{
				a.confluence().building().makeHyperactive();
				a.confluence().makeHyperactive();
			}
			
			a.teams.each(function(t_id) { users.get(t_id).makeActive()})
		})
	},
	
	entered: function() {
		itches.each(function(i) { i.c = 0; })
		this.appointments().each(function(a) { 
			a.confluence().itch.c++;
			a.confluence().itch.makeActive()
		})		
		
		itches.each(function(i) { i.count(i.c)})			
	},
	
	left: function() {
		itches.each(function(itch) { itch.makeInactive()})
		itches.each(function(i) { i.uncount()})
	},
	
	hide: function() {
		this.e.removeClassName("active")
		
		this.appointments().each(function(a) {
			a.confluence().building().unappoint(a.confluence());
			a.teams.each(function(t_id) { users.get(t_id).makeInactive()})
		})
		
		buildings.each(function(b) { b.makeInactive()})
	},
	
	time: function(time) {
		this.storedTime = this.timeE.innerHTML;
		this.timeE.innerHTML = time;
		this.makeActive();
	}, 
	
	untime: function() {
		this.timeE.innerHTML = this.storedTime;
		this.makeInactive();
	},
	
	count: function() {
		return parseInt(this.countE.innerHTML);
	}
})

User.maxtime = function() { return users.collect(function(u) { return u.maxtime()}).max()}

User.maxcount = function() { return users.collect(function(u) { return u.count()}).max()}

User.mincount = function() { return users.reject(function(u) { return u.id == "1"}).collect(function(u) { return u.count()}).min()}

User.fadeLatest = function() {
	mt = User.mincount();
	
	users.reject(function(u) { return u.id == "1" || u.count() == mt }).each(function(u) { u.e.style.opacity = 0.7})
}

var Appointment = Class.create(Connector, {
	initialize: function($super, e) {
		$super(e);
		
		this.teams = this.extract(".teams").innerHTML.split(",").collect(function(ids) { return parseInt(ids)})
		this._confluence = confluences.get(this.parseInt(".confluence"))
		this.time = this.parseInt(".time")
		//this. = parseInt(this.extract(".building"))
		this._teams = null;
	},
	
	confluence: function() { return this._confluence},
	
	getTeams: function() {
		if (this._teams == null)
		{
			this._teams = this.teams.collect(function(tid) { return users.get(tid)});
		}
		
		return this._teams;
	},
	
	show: function() {
		time = this.time
		this.getTeams().each(function(team) { team.time(time); team.e.highlight()})
	},
	
	hide: function() {
		this.getTeams().each(function(team) { team.untime()});
	}
})