if ( typeof CupMan == "undefined" ) {
	CupMan = {};
}

CupMan.Event = function(retroactive) {
	this.retroactive = !!retroactive;
	this.fired = false;
	this.subscribers = new List();
}

CupMan.Event.prototype.subscribe = function( func ) {
	this.subscribers.add( func );
	if ( this.fired && this.retroactive ) {
		func(null);
	}
}

CupMan.Event.prototype.fire = function(a,b,c,d,e,f,g,h) {
	this.fired = true;
	var response = true;
	
	for ( var i=0; i<this.subscribers.size(); i++ ) {
		var func = this.subscribers.get(i);
		var res = func(a,b,c,d,e,f,g,h);
		if (res === false) {
			response = false;
		}
	}
	
	return response;
}
if ( typeof CupMan == "undefined" ) {
	CupMan = {};
}

var glow_suffix = "glow";
var selected_suffix = "glow";
var disabled_suffix = "gray";


CupMan.Map = function(el)
{
	this.loadEvent = new CupMan.Event(true);
	this.clickEvent = new CupMan.Event(false);
	this.hoverEvent = new CupMan.Event(false);
	
	
	// Back-compatible
	this.clickEvent.subscribe(function(marker){
		if (typeof markerClicked != "undefined") {
			markerClicked(marker);
		}
	});
	
	
	this.typeMarkers = new Map(); // type -> markers
	this.markers = new Map();	   // id -> marker
	this.bounds = new GLatLngBounds();
	var map = this.map = new GMap2( el.get(0) );
	
	map.setCenter( new GLatLng(0,0), 6 );
	map.enableScrollWheelZoom();
	map.enableContinuousZoom();
	map.addControl(new FancyMapControl());
}

CupMan.Map.prototype.hideMarkers = function(type)
{
	this.bounds = new GLatLngBounds();
	var ids = this.markers.keys();
	for (var i=0; i<ids.length; i++)
	{
		var id = ids[i];
		var marker = this.markers.get(id);
		
		if (marker.type == type && marker.visible)
		{
			marker.visible = false;
			this.map.removeOverlay(marker);
		}
		
		if (marker.visible)
		{
			this.bounds.extend(marker.getLatLng());
		}
	}
	return this;
}
CupMan.Map.prototype.showMarkers = function(type)
{
	this.bounds = new GLatLngBounds();
	var ids = this.markers.keys();
	for (var i=0; i<ids.length; i++)
	{
		var id = ids[i];
		var marker = this.markers.get(id);
		
		if (marker.type == type && !marker.visible)
		{
			marker.visible = true;
			this.map.addOverlay(marker);
		}
		
		if (marker.visible)
		{
			this.bounds.extend(marker.getLatLng());
		}
	}
	
	return this;
}

CupMan.Map.prototype.addMarker = function(id, title, type, lat, lng)
{
	var point = new GLatLng(lat,lng);
	this.bounds.extend(point);
	
	var parentType = type;
	if (type.indexOf("/") > -1) {
		parentType = type.substr(0, type.indexOf("/"));
	}
	
	var icon = CupMan.Map.getIconForType(parentType);
	var gIcon = CupMan.Map.getIcon(icon);
	var marker = new GMarker(point, { title: title, icon: gIcon });
	
	if ( !this.typeMarkers.containsKey(type) ) {
		this.typeMarkers.put(type, new List());
	}
	this.typeMarkers.get(type).add(marker);
	this.markers.put(id, marker);
	
	marker.iconId = icon;
	marker.type = type;
	marker.parentType = parentType;
	marker.title = title;
	marker.isEnabled = true;
	marker.visible = true;
	marker.id = id;
	
	var thisMap = this;
	
	GEvent.addListener(marker,"mouseover", function() {
		if( this && this.isEnabled ) {
			this.setImage( CupMan.Map.getIconUrl(this.iconId, true) );
			
			thisMap.hoverEvent.fire(this, "in");
		}
	});
	
	GEvent.addListener(marker,"mouseout", function() {
		if( this && this.isEnabled ) {
			if( this.isSelected ) {
				this.setImage("http://maps.cupmanager.net/map_icons/"+this.iconId+"_"+selected_suffix+".png");
			} else {
				this.setImage( CupMan.Map.getIconUrl(this.iconId, false) );
			}
			
			thisMap.hoverEvent.fire(this, "out");
		}
	});
	
	GEvent.addListener(marker,"click", function() {
		if( this && this.isEnabled ){
			thisMap.clickEvent.fire(this);
		}
	});
	
	this.map.addOverlay(marker);
	
	return marker;
}

CupMan.Map.prototype.glowMarker = function(marker) {
	marker.setImage( CupMan.Map.getIconUrl(marker.iconId, true) );
}
CupMan.Map.prototype.unGlowMarker = function(marker) {
	marker.setImage( CupMan.Map.getIconUrl(marker.iconId, false) );
}

CupMan.Map.prototype.fit = function()
{
	var zoom = this.map.getBoundsZoomLevel(this.bounds);
	this.map.setCenter(this.bounds.getCenter(), Math.min(Math.max(zoom-1,1), 13));
	
	return this;
}

CupMan.Map.prototype.setZoom = function(level) {
	this.map.setZoom(level);
}

CupMan.Map.prototype.done = function()
{
	this.loadEvent.fire(this);
}

CupMan.Map.getIconForType = function(type) 
{
	var icon = "simple";
	
	if ( type == "Lodging" )
		icon = "lodging";
	
	if ( type == "Arena" )
		icon = "sport";
	
	if ( type == "Food" )
		icon = "lodgingfood";
	
	if ( type == "Restaurant" )
		icon = "food";
	
	if ( type == "Other" )
		icon = "regular";
	
	if ( type == "Miscellaneous" )
		icon = "regular";
	
	if ( type == "Cup" )
		icon = "";
		
	if ( type == "Club" )
		icon = "home";
	
	return icon;
}

CupMan.Map.getIcon = function(iconId){
	var icon = new GIcon();
	
	icon.image = CupMan.Map.getIconUrl(iconId);
	// icon.shadow = "/images/mapicons/shadow_marker.png";
	
	//icon.image = "http://maps.cupmanager.net/map_icons/"+iconId+".png";
	//icon.shadow = "http://maps.cupmanager.net/map_icons/"+iconId+"_shadow.png";
	
	//icon.iconSize = new GSize(32.0, 32.0);
	//icon.shadowSize = new GSize(49.0, 32.0);
	//icon.iconAnchor = new GPoint(15.0, 32.0);
	//icon.infoWindowAnchor = new GPoint(16.0, 16.0);
	
	//icon.iconSize = new GSize(21.0, 34.0);
	//icon.shadowSize = new GSize(40.0, 37.0);
	//icon.iconAnchor = new GPoint(10.0, 34.0);
	//icon.infoWindowAnchor = new GPoint(16.0, 16.0);
	
	icon.iconSize = new GSize(32.0, 37.0);
	icon.shadowSize = new GSize(40.0, 37.0);
	if (iconId == "lodging")
		icon.iconAnchor = new GPoint(16.0, 3.0);
	else
		icon.iconAnchor = new GPoint(16.0, 34.0);
	
	icon.infoWindowAnchor = new GPoint(16.0, 16.0);
	
	return icon;
}


CupMan.Map.getIconUrl = function(iconType, glow) {
	if (glow) {
		return imageBaseUrl+"mapicons/"+iconType+"_marker_glow.png";
	} else {
		return imageBaseUrl+"mapicons/"+iconType+"_marker.png";
	}
}
addOnLoad(function(){
	jQuery("table.hoverable tr:not(.noHover) td").hover(function() {
		jQuery(this).closest("tr").addClass("hover");
	}, function() {
		jQuery(this).closest("tr").removeClass("hover");
	});
	
	/* Flyttat till
	 * jQuery("a[href *= liveViewer]").click(function() {
		popUp( jQuery(this).attr("url") );
		return false;
	});*/
	
	
	jQuery(".buttonLink").hover(function() {
		jQuery(this).addClass("hoverButtonLink");
	}, function() {
		jQuery(this).removeClass("hoverButtonLink");
	});
	
	jQuery(".languages a:not(.selected) img").css("opacity", "0.5");
	
	jQuery(".languages a img").hover(function() {
		jQuery(this).css("opacity", "1");
	}, function() {
		if (jQuery(this).parent().is(".selected")) {
			jQuery(this).css("opacity", "1");
		} else {
			jQuery(this).css("opacity", "0.5");
		}
		
	});
	
});
var CategorySearch = function() {
	this.nameMap = new Map();
}

CategorySearch.prototype.observeTeam = function(name, element) {
	this.nameMap.put( name, element );
}

CategorySearch.prototype.index = function() {
	var thisSearch = this;
	jQuery(".conferenceBox .teams a").each(function(){
		thisSearch.observeTeam( jQuery(this).html().toLowerCase(), jQuery(this) );
	});
}

CategorySearch.prototype.reset = function() {
	var values = this.nameMap.values();
	for ( var i=0; i<values.length; i++ ) {
		values[i].removeClass("searchMatch").removeClass("noSearchMatch");
	}
}
CategorySearch.prototype.search = function(query) {
	if ( query == "" ) {
		this.reset();
		return;
	}
	query = query.toLowerCase();
	var keys = this.nameMap.keys();
	for ( var i=0; i<keys.length; i++ ) {
		var key = keys[i];
		if ( key.indexOf(query) != -1 )  {
			this.nameMap.get(key).removeClass("noSearchMatch").addClass("searchMatch");
		} else {
			this.nameMap.get(key).removeClass("searchMatch").addClass("noSearchMatch");
		}
	}
}

var categorySearch = null;

addOnLoad(function(){
	categorySearch = new CategorySearch();
	categorySearch.index();
	
	jQuery(".categorySearchBox").keyup(function() {
		categorySearch.search( jQuery(this).val() );
	});
	
});
Math.log2 = function(i) {
	return Math.log(i)/Math.log(2);
}

var Ladder = {};

Ladder.Manager = Class.extend({
	init: function(element) {
		this.widgets = new List();
		this.matches = new Map();
		this.teams = new Map();
		this.rounds = new Map();
		
		this.nodes = new Map();
		this.selector = new Ladder.Selector(this);
		this.selectors = new List();
		this.things = new List();
		this.simpleMode = false;
	},
	
	build: function(element) {
		this.element = element;
		this.unit = this.element.height() / 1000.0;
		
		var finalMatch = new Ladder.Final(1, this);
		finalMatch.build();
	},
	
	clear: function() {
		for ( var i=0; i<this.widgets.size(); i++ ) {
			var w = this.widgets.get(i);
			if (w) {
				if ( w.clear ) w.clear();
				if ( w.clearUpper ) w.clearUpper();
				if ( w.clearLower ) w.clearLower();
				if ( w.clearHome ) w.clearHome();
				if ( w.clearAway ) w.clearAway();
			}
		}
	},
	
	position: function() {
		
		this.nodes.get(1).position();
	},
	
	getElement: function() {
		return this.element;
	},
	
	getUnit: function(multiplier) {
		multiplier = multiplier || 1;
		return this.unit * multiplier;
	},
	
	setMatches: function(matches) {
		for (index in matches) {
			var match = matches[index];
			this.matches.put(index, new Ladder.Match(index, match, this));
		}
	},
	setTeams: function(teams) {
		for (index in teams) {
			var team = teams[index];
			this.teams.put(index, new Ladder.Team(index, team, this));
		}
	},
	
	addRound: function(round) {
		var key = round.rank+"_"+round.dir;
		this.rounds.put(key, round);
	},
	getRound: function(roundRank, dir) {
		var key = roundRank+"_"+dir;
		return this.rounds.get(key);
	},
	
	getVerticalBoxCount: function() {
		return Ladder.Manager.getTop(this.matches.size());
	},
	getBoxHeight: function() {
		var b = this.getVerticalBoxCount();
		var r = Ladder.Manager.BOX_HEIGHT_SPACE_RATIO;
		
		// Split height into (b+1) + (b*r) pieces 
		var piece = this.element.height() / (b*r + b + 1);
		
		// Height of one box is r pieces
		var height = r * piece;
		
		return height;
	},
	
	getHorizSpacing: function() {
		var space = this.element.width() - Ladder.Manager.FINAL_WIDTH - 2*Ladder.Manager.TEAM_WIDTH; // Total space between final and teams, on both sides
		var levels = Math.log2(this.matches.size()) + 1;
		levels = levels * 2;
		return space / levels;
	},
	
	getSmallestConnectorHeight: function() {
		var level = Math.floor( Ladder.Manager.getTop( this.matches.size() ) );
		return this.element.height() / level;
	},
	
	getMatch: function(index) {
		return this.matches.get(index);
	},
	getTeam: function(index) {
		return this.teams.get(index);
	},
	
	
	setSimpleMode: function(simpleMode) {
		this.simpleMode = simpleMode;
	},
	
	add: function(drawable) {
		this.widgets.add(drawable);
	},
	
	getNode: function(index) {
		return this.nodes.get(index);
	},
	addNode: function(node) {
		this.nodes.put(node.index, node);
	},
	
	
	addSelector: function(selector) {
		this.selectors.add(selector);
		this.runSelectors();
	},
	removeSelector: function(selector) {
		this.selectors.remove( this.selectors.indexOf(selector) );
		this.runSelectors();
	},
	runSelectors: function() {
		this.clear();
		if ( this.selectors.isEmpty() ) {
			new Ladder.DefaultSelector(this).run();
		} else {
			for (var i=0; i<this.selectors.size(); i++) {
				var sel = this.selectors.get(i);
				sel.run();
			}
		}
	}
});
Ladder.Manager.getTop = function(index) {
	var f = Math.floor( Math.log2(index) );
	var top = Math.pow(2,f);
	return top;
}
Ladder.Manager.getDirection = function(index) {
	if (index==1) {
		return 0;
	}
	
	var top = Ladder.Manager.getTop(index);
	var offset = index - top;
	var height = top;
	
	if ( offset >= height/2 ) {
		return 1;
	} else {
		return -1;
	}
}
Ladder.Manager.BOX_HEIGHT_SPACE_RATIO = 5;
Ladder.Manager.FINAL_WIDTH = 100;
Ladder.Manager.FINAL_HEIGHT = 80;
Ladder.Manager.TEAM_WIDTH = 150;


Ladder.TeamSelector = Class.extend({
	init: function(teamNode, lm) {
		this.teamNode = teamNode;
		this.ladderManager = lm;
	},
	run: function() {
		this.teamNode.select();
		this._run( this.teamNode.getParent(), this.teamNode.index%2 == 0 );
	},
	_run: function(matchNode, fromHome) {
		var match = matchNode.getMatch();
		
		// Markera connector / line
		if ( matchNode.index > 1 ) {
			var con = matchNode.connector;
			if (fromHome) {
				con.selectUpper();
			} else {
				con.selectLower();
			}
		} else {
			if (fromHome) {
				matchNode.selectHome();
			} else {
				matchNode.selectAway();
			}
		}
		
		
		if (match.finished && match.index > 1) {
			// Kolla vem som vann
			if	(  (match.winner == "home" && fromHome) 
				|| (match.winner == "away" && !fromHome) ) 
			{
				matchNode.select();
				this._run( matchNode.getParent(), matchNode.index%2 == 0 );
			}
		}
	},
	undo: function() {
		this.teamNode.clear();
		this._undo( this.teamNode.getParent(), this.teamNode.index%2 == 0 );
	},
	_undo: function(matchNode, fromHome) {
		var match = matchNode.getMatch();
		
		// Markera connectorn
		var con = matchNode.connector;
		if (fromHome) {
			con.clearUpper();
		} else {
			con.clearLower();
		}
		
		if (match.finished) {
			// Kolla vem som vann
			if	(  (match.winner == "home" && fromHome) 
				|| (match.winner == "away" && !fromHome) ) 
			{
				matchNode.clear();
				this._undo( matchNode.getParent(), matchNode.index%2 == 0 );
			}
		}
	}
});
Ladder.MatchSelector = Class.extend({
	init: function(matchNode, lm) {
		this.matchNode = matchNode;
		this.ladderManager = lm;
	},
	run: function() {
		this.matchNode.select();
		// Leta p� home-sidan efter homeId och motsv. p� andra
		
		var isHome = this._search( this.matchNode.index*2, this.matchNode.getMatch().homeId );
		if (isHome) {
			this.matchNode.index>1 ? this.matchNode.connector.selectUpper() : this.matchNode.selectHome();
		}
		var isAway = this._search( this.matchNode.index*2+1, this.matchNode.getMatch().awayId );
		if (isAway) {
			this.matchNode.index>1 ? this.matchNode.connector.selectLower() : this.matchNode.selectAway();
		}
	},
	_search: function(index, actorId) {
		var node = this.ladderManager.getNode(index);
		
		if (!node) {
			return false;
		}
		
		if (node.id == actorId) {
			// YAY!
			node.select();
			return true;
		} else {
			var homeIndex = index*2;
			var awayIndex = index*2+1;
			
			var isHome = this._search(homeIndex, actorId);
			if (isHome) {
				// Markera
				node.select();
				if (node.index > 1) {
					node.connector.selectUpper();
				} else {
					node.selectHome();
				}
				return true;
			} else {
				var isAway = this._search(awayIndex, actorId);
				if (isAway) {
					// Markera
					node.select();
					if (node.index > 1) {
						node.connector.selectLower();
					} else {
						node.selectAway();
					}
					return true;
				}
			}
		}
		
		return false;
	},
	undo: function() {
		this.matchNode.clear();
		// Leta p� home-sidan efter homeId och motsv. p� andra
		
		var isHome = this._undoSearch( this.matchNode.index*2, this.matchNode.getMatch().homeId );
		if (isHome) {
			this.matchNode.connector.clearUpper();
		}
		var isAway = this._undoSearch( this.matchNode.index*2+1, this.matchNode.getMatch().awayId );
		if (isAway) {
			this.matchNode.connector.clearLower();
		}
	},
	_undoSearch: function(index, actorId) {
		var node = this.ladderManager.getNode(index);
		
		if (!node) {
			return false;
		}
		
		if (node.id == actorId) {
			// YAY!
			node.clear();
			return true;
		} else {
			var homeIndex = index*2;
			var awayIndex = index*2+1;
			
			var isHome = this._undoSearch(homeIndex, actorId);
			if (isHome) {
				// Markera
				node.clear();
				node.connector.clearUpper();
				return true;
			} else {
				var isAway = this._undoSearch(awayIndex, actorId);
				if (isAway) {
					// Markera
					node.clear();
					node.connector.clearLower();
					return true;
				}
			}
		}
		
		return false;
	}
});


Ladder.DefaultSelector = Class.extend({
	init: function(lm) {
		this.ladderManager = lm;
	},
	
	run: function() {
		var finalNode = this.ladderManager.getNode(1);
		var thisSel = this;
		//if ( !finalNode.getMatch().finished ) {
			this._search( finalNode, function(matchNode) {
				new Ladder.MatchSelector(matchNode, thisSel.ladderManager).run();
			} );
		//}
	},
	_search: function(matchNode, callback) {
		var homeIndex = matchNode.index*2;
		var awayIndex = matchNode.index*2 + 1;
		
		var home = this.ladderManager.getNode(homeIndex);
		var away = this.ladderManager.getNode(awayIndex);
		
		if ( home instanceof Ladder.TeamNode || home.getMatch().finished ) {
			// This is an unplayed leaf.
			callback(matchNode);
		} else {
			this._search(home, callback);
		}
		
		if ( away instanceof Ladder.TeamNode || away.getMatch().finished ) {
			// This is an unplayed leaf.
			callback(matchNode);
		} else {
			this._search(away, callback);
		}
	},
	undo: function() {
		var finalNode = this.ladderManager.getNode(1);
		var thisSel = this;
		if ( !finalNode.getMatch().finished ) {
			this._search( finalNode, function(matchNode) {
				new Ladder.MatchSelector(matchNode, thisSel.ladderManager).undo();
			} );
		}
	}
});


Ladder.Selector = Class.extend({
	init: function(lm) {
		this.ladderManager = lm;
	},
	hoverTeam: function(teamNode) {
		var sel = new Ladder.TeamSelector(teamNode, this.ladderManager);
		teamNode.hoverSel = sel;
		this.ladderManager.addSelector( sel );
	},
	unHoverTeam: function(teamNode) {
		if ( teamNode.hoverSel) {
			this.ladderManager.removeSelector(teamNode.hoverSel);
			teamNode.hoverSel = null;
		}
	},
	
	clickTeam: function(teamNode) {
		teamNode.clicked = !teamNode.clicked;
		if (teamNode.clicked) {
			var sel = new Ladder.TeamSelector(teamNode, this.ladderManager);
			teamNode.clickSel = sel;
			this.ladderManager.addSelector( sel );
		} else {
			if ( teamNode.clickSel ) {
				this.ladderManager.removeSelector( teamNode.clickSel );
				teamNode.clickSel = null;
			}
		}
	},
	
	
	hoverMatch: function(matchNode) {
		var sel = new Ladder.MatchSelector(matchNode, this.ladderManager);
		matchNode.hoverSel = sel;
		this.ladderManager.addSelector( sel );
		
		matchNode.timeoutHandle = setTimeout(function() {
			matchNode.element.qtip("api").show();
		}, 100);
		
	},
	unHoverMatch: function(matchNode) {
		if ( matchNode.hoverSel) {
			this.ladderManager.removeSelector(matchNode.hoverSel);
			matchNode.hoverSel = null;
		}
		clearTimeout( matchNode.timeoutHandle );
	},
	
	clickMatch: function(matchNode) {
		matchNode.clicked = !matchNode.clicked;
		if (matchNode.clicked) {
			var sel = new Ladder.MatchSelector(matchNode, this.ladderManager);
			matchNode.clickSel = sel;
			this.ladderManager.addSelector( sel );
		} else {
			if ( matchNode.clickSel ) {
				this.ladderManager.removeSelector( matchNode.clickSel );
				matchNode.clickSel = null;
			}
		}
	}
});



Ladder.Match = Class.extend({
	init: function(index, obj, lm) {
		this.ladderManager = lm;
		this.index = index;
		this.id = obj.id;
		this.finished = obj.finished;
		this.homeResult = obj.homeResult;
		this.awayResult = obj.awayResult;
		this.homeId = obj.homeId;
		this.awayId = obj.awayId;
		this.winner = obj.winner;
		this.arena = obj.arena;
		this.dateTime = obj.dateTime;
		this.round = obj.round;
		
		this.homeName = obj['homeName'];
		this.awayName = obj['awayName'];
	}
});
Ladder.Team = Class.extend({
	init: function(index, obj, lm) {
		this.ladderManager = lm;
		this.index = index;
		this.id = obj.id;
		this.name = obj.name;
		this.subtitle = obj.subtitle;
		this.color1 = obj.color1;
		this.color2 = obj.color2;
		this.hexColor = obj.hexColor;
	}
});



Ladder.Drawable = Class.extend({
	init: function(lm) {
		this.ladderManager = lm;
		this.ladderManager.add(this);
		this.element = jQuery("<div/>").appendTo( this.ladderManager.getElement() );
		this.element.css("position", "absolute");
	},
	getRightPoint: function() {
		var point = {
			left: this.element.position().left + this.element.width(),
			top: this.element.position().top + this.element.height() / 2
		}
		return point;
	},
	getLeftPoint: function() {
		var point = {
			left: this.element.position().left,
			top: this.element.position().top + this.element.height() / 2
		}
		return point;
	},
	getCenterPoint: function() {
		var point = {
			left: this.element.position().left + this.element.width() / 2,
			top: this.element.position().top + this.element.height() / 2
		}
		return point;
	},
	build: function() {},
	position: function() {},
	redraw: function() {}
});



Ladder.Round = Ladder.Drawable.extend({
	init: function(lm, rank, dir, name) {
		this._super(lm);
		this.name = name;
		this.rank = rank;
		this.dir = dir;
	},
	build: function() {
		
		this.element = jQuery("<div/>");
		this.element.attr("rank", this.rank);
		this.element.attr("direction", this.dir);
		this.element.addClass("round");
		
		
		var text = jQuery("<span/>");
		this.element.append(text);
		text.html(this.name);
		
		this.ladderManager.element.append(this.element);
	}, 
	position: function() {
		var middle = this.ladderManager.element.width() / 2;
		var spacing = this.ladderManager.getHorizSpacing();
		
		var fromMiddle = 74;
		
		fromMiddle += spacing * (this.rank-1);
		
		var x = middle + fromMiddle * this.dir;
		
		if (this.dir < 0) {
			x -= 30;
			
			// �t v�nster blir det en pixel f�rskjutning per rank-enhet ocks�, antagligen avrundning.
			x += this.rank * 1;
		}
		
		this.element.css("left", x);
	},
	redraw: function() {
		
	}
});




Ladder.Node = Ladder.Drawable.extend({
	init: function(index, lm) {
		this._super(lm);
		this.index = index;
		this.id = 0;
		this.selected = false;
		this.ladderManager.addNode(this);
	},
	clear: function() {
		this.selected = false;
		this.redraw();
	},
	isSelected: function() {
		return this.selected;
	},
	select: function(){
		this.selected = true;
		this.redraw();
	},
	getParent: function() {
		var parentIndex = Math.floor(this.index / 2);
		return this.ladderManager.getNode(parentIndex); 
	}
});

Ladder.TeamNode = Ladder.Node.extend({
	init: function(index, lm) {
		this._super(index, lm);
		this.ladderManager = lm;
	},
	setPosition: function(left,top) {
		this.left = left;
		this.top = top;
	},
	getTeam: function() {
		return this.ladderManager.getTeam(this.index);
	},
	
	build: function() {
		this.id = this.getTeam().id;
		this.element.addClass("team");
		this.element.width( Ladder.Manager.TEAM_WIDTH );
		this.element.height( this.ladderManager.getBoxHeight() );
		
		var dir = Ladder.Manager.getDirection(this.index);
		if (dir < 0) {
			this.element.addClass("teamLeft");
		} else {
			this.element.addClass("teamRight");
		}
		
		var team = this.ladderManager.getTeam(this.index);
		
		if (!this.ladderManager.simpleMode) 
		{
			if (team.color1 != "") 
			{
				var img = this.element.append( '<img src="" />' ).find("img");
				img.attr("src", CupMan.getServiceUrl("ClubImageService")+"?type=shield&w=20&h=20&c1="+ team.color1 +"&c2="+ team.color2);
			}
			
			var span = jQuery("<div />");
			span.addClass("name");
			span.html(team.name);
			span.css("color", team.hexColor);
			this.element.append( span );
			
			var span = jQuery("<div />");
			span.addClass("origin");
			span.html(team.subtitle);
			this.element.append( span );
		}
		
		this.element.attr("title", team.name);
		
		var thisTeamNode = this;
		this.element.hover(function() {
			thisTeamNode.ladderManager.selector.hoverTeam( thisTeamNode );
		}, function() {
			thisTeamNode.ladderManager.selector.unHoverTeam( thisTeamNode );
		});
		
		this.element.click(function() {
			thisTeamNode.ladderManager.selector.clickTeam( thisTeamNode );
		});
	},
	
	position: function() {
		var dir = Ladder.Manager.getDirection(this.index);
		
		if (dir < 0 ) {
			this.element.css("left", this.left - this.element.width());
		}
		if (dir > 0 ) {
			this.element.css("left", this.left);
		}
		this.element.css("top", this.top - this.element.height()/2);
		
		this.redraw();
	},
	
	redraw: function() {
		var dir = Ladder.Manager.getDirection(this.index);
		
		if (this.selected) {
			if (dir < 0) {
				this.element.addClass("teamSelectedLeft");
			} else {
				this.element.addClass("teamSelectedRight");
			}
		} else {
			this.element.removeClass("teamSelectedRight");
			this.element.removeClass("teamSelectedLeft");
		}
		
		
	},
	
	clear: function() {
		this._super();
	},
	select: function() {
		this._super();
	}
});



Ladder.MatchNode = Ladder.Node.extend({
	init: function(index, lm) {
		this._super(index, lm);
		this.id = 0;
	},
	getMatch: function() {
		return this.ladderManager.getMatch(this.index);
	},
	getRound: function() {
		var roundRank = Math.floor(Math.log2(this.getMatch().index));
		var round = this.ladderManager.getRound(roundRank, Ladder.Manager.getDirection(this.index));
		return round;
	},
	build: function() {
		this.id = this.getMatch().id;
		
		var thisMatchNode = this;
		this.element.hover(function() {
			thisMatchNode.hover();
			thisMatchNode.ladderManager.selector.hoverMatch(thisMatchNode);
		}, function() {
			thisMatchNode.unhover();
			thisMatchNode.ladderManager.selector.unHoverMatch(thisMatchNode);
		});
		
		this.element.click(function() {
			thisMatchNode.ladderManager.selector.clickMatch(thisMatchNode);
		});
	},
	position: function() {},
	redraw: function() {},
	hover: function() {},
	unhover: function() {}
});



Ladder.Point = Ladder.MatchNode.extend({
	init: function(index, lm) {
		this._super(index, lm);
		this.left = 0;
		this.top = 0;
	},
	setPosition: function(left,top) {
		this.left=left;
		this.top=top;
	},
	build: function() {
		this._super();
		this.element.addClass("point");
		this.element.css("font-size", "1px");
		this.element.html("<!-- -->");
		
		// Har inte s� mycket att bygga sj�lv, men forts�tter rekursivt!
		this.connector = new Ladder.Connector( this.index*2, this.index*2+1, this.index, this.ladderManager );
		
		this.connector.build();
		
		if (!this.ladderManager.simpleMode && this.getMatch().finished) {
			var match = this.getMatch();
			
			this.upper = jQuery("<div />");
			this.upper.addClass("upper");
			this.upper.append("<span>"+match.homeResult+"</span>");
			
			this.lower = jQuery("<div />");
			this.lower.addClass("lower");
			this.lower.append("<span>"+match.awayResult+"</span>");
			
			this.element.append(this.upper);
			this.element.append(this.lower);
			
			if ( match.homeResult < match.awayResult ) {
				this.upper.addClass("upperWon");
			} else {
				this.lower.addClass("lowerWon");
			}
		}
		
		var dir = Ladder.Manager.getDirection(this.index);
		var corner = {
		         target: 'rightMiddle',
		         tooltip: 'leftMiddle'
		      };
		var tip = "leftMiddle";
		if (dir > 0) {
			corner = {
		         target: 'leftMiddle',
		         tooltip: 'rightMiddle'
		      };
		    tip = "rightMiddle";
		}
		
		var thisMatch = this;
		
		var qtip = this.element.qtip({
		   content: thisMatch.getMatch().arena + ", " + thisMatch.getMatch().dateTime,
		   position: {
		      corner: corner
		   },
		   style: { 
		      tip: tip,
		      name: "blue",
		      padding: 2,
		      border: {
		      	width: 2
		      }
		   },
		   show: false,
		   hide: { fixed:false }
		}).qtip("api");
		
		var thisPoint = this;
		qtip.elements.wrapper.parent().hover(function(){
			thisPoint.ladderManager.selector.hoverMatch(thisPoint);
		}, function(){
			thisPoint.ladderManager.selector.unHoverMatch(thisPoint);
		});
		
		
		// Skapa runda ifall det inte finns
		var round = this.getRound();
		if (!round) {
			var roundRank = Math.floor(Math.log2(thisMatch.getMatch().index));
			round = new Ladder.Round(this.ladderManager, roundRank, dir, thisMatch.getMatch().round);
			
			this.ladderManager.addRound(round);
			round.build();
		}
		
	},
	position: function() {
		this._super();
		var size = this.ladderManager.simpleMode ? 5 : 10;
		
		var height = 56;
		var width = 36;
		
		this.element.css("left", this.left - width/2);
		this.element.css("top", this.top - height/2);
		this.element.width(width);
		this.element.height(height);
		
		var pos = this.element.position();
		
		if (!this.ladderManager.simpleMode && this.homeResult && this.awayResult) {
			this.homeResult.css("left", pos.left-2);
			this.homeResult.css("top", pos.top-17);
			this.awayResult.css("left", pos.left-2);
			this.awayResult.css("top", pos.top+12);
		}
		
		this.connector.position();
		
		try {
			this.getRound().position();
		} catch (e) {
			var roundRank = Math.floor(Math.log2(this.getMatch().index));
			var dir = Ladder.Manager.getDirection(this.index);
			
		}
		this.redraw();
	}, 
	redraw: function() {
		var bkg = ""; 
		if (this.getMatch().finished) {
			this.element.css("border-color", "black");
			bkg = "#fff";
		} else {
			this.element.css("border-color", "black");
			bkg = "#aaa";
		}
		
		if (this.selected) {
			var height = 65;
			var width = 36;
			
			this.element.css({
				left: this.left - width/2,
				top: this.top - height/2,
				width: width,
				height: height
			});
		} else {
			var height = 56;
			var width = 36;
			this.element.stop().css({
				left: this.left - width/2,
				top: this.top - height/2,
				width: width,
				height: height
			});
		}
		
		this.getRound().redraw();
	},
	hover: function() {
		if (this.upper.hasClass("upperWon")) {
			this.upper.addClass("upperWonHover");
		} else {
			this.upper.addClass("upperHover");
		}
		
		if (this.lower.hasClass("lowerWon")) {
			this.lower.addClass("lowerWonHover");
		} else {
			this.lower.addClass("lowerHover");
		}
	},
	unhover: function() {
		this.upper.removeClass("upperWonHover");
		this.upper.removeClass("upperHover");
		
		this.lower.removeClass("lowerWonHover");
		this.lower.removeClass("lowerHover");
	}
});





/************************************/
		// F I N A L
/************************************/

Ladder.Final = Ladder.MatchNode.extend({
	init: function(index, lm) {
		this._super(index, lm);
		this.lineHome = new Ladder.Line(index, index*2, -1, this.ladderManager);
		this.lineAway = new Ladder.Line(index, index*2+1, 1, this.ladderManager);
		
		//this.left = 0;
		//this.top = 0;
	},
	setPosition: function(left,top) {
		console.log("final.setposoition:", left, top);
		this.left=left;
		this.top=top;
	},
	build: function() {
		this._super();
		this.element.addClass("final");
		this.element.css("font-size", "1px");
		this.element.html("<!-- -->");
		
		var match = this.getMatch();
		
		this.leftNode = jQuery("<div />");
		this.leftNode.addClass("left");
		this.leftNode.append("<span>"+match.homeResult+"</span>");
		
		this.rightNode = jQuery("<div />");
		this.rightNode.addClass("right");
		this.rightNode.append("<span>"+match.awayResult+"</span>");
		
		this.element.append(this.leftNode);
		this.element.append(this.rightNode);
		
		if ( match.homeResult < match.awayResult ) {
			this.leftNode.addClass("leftWon");
		} else {
			this.rightNode.addClass("rightWon");
		}
		
		
		
		this.homeTeam = jQuery("<div/>");
		this.homeTeam.html(match.homeName);
		this.homeTeam.addClass("finalHomeTeam");
		this.ladderManager.element.append(this.homeTeam);
		
		this.awayTeam = jQuery("<div/>");
		this.awayTeam.html(match.awayName);
		this.awayTeam.addClass("finalAwayTeam");
		this.ladderManager.element.append(this.awayTeam);
		
		if ( match.homeResult > match.awayResult ) {
			this.homeTeam.css("font-weight", "bold");
		}
		if ( match.homeResult < match.awayResult ) {
			this.awayTeam.css("font-weight", "bold");
		}
		
		this.lineHome.build();
		this.lineAway.build();
		
		var corner = {
		         target: 'topMiddle',
		         tooltip: 'bottomMiddle'
		      };
		var tip = "bottomMiddle";
		
		var thisMatch = this;
		
		var qtip = this.element.qtip({
		   content: thisMatch.getMatch().arena + ", " + thisMatch.getMatch().dateTime,
		   position: {
		      corner: corner
		   },
		   style: { 
		      tip: tip,
		      name: "blue",
		      padding: 2,
		      border: {
		      	width: 2
		      }
		   },
		   show: false,
		   hide: { fixed:true }
		}).qtip("api");
		
		var thisPoint = this;
		qtip.elements.wrapper.parent().hover(function(){
			thisPoint.ladderManager.selector.hoverMatch(thisPoint);
		}, function(){
			thisPoint.ladderManager.selector.unHoverMatch(thisPoint);
		});
		
	},
	position: function() {
		this._super();
		
		var height = 36;
		var width = 56;
		
		this.element.width(width);
		this.element.height(height);
		
		
		this.element.css("left", this.ladderManager.element.width()/2 - this.element.width()/2);
		this.element.css("top", this.ladderManager.element.height()/2 - this.element.height()/2);
		
		this.homeTeam.css("left", this.ladderManager.element.width()/2 - this.homeTeam.width()/2);
		this.homeTeam.css("bottom", this.ladderManager.element.height()/2 + 10);
		
		this.awayTeam.css("left", this.ladderManager.element.width()/2 - this.awayTeam.width()/2);
		this.awayTeam.css("top", this.ladderManager.element.height()/2 + 10);
		
		
		var pos = this.element.position();
		
		this.lineHome.position();
		this.lineAway.position();
		
		this.redraw();
	}, 
	redraw: function() {
		var bkg = ""; 
		if (this.getMatch().finished) {
			this.element.css("border-color", "black");
			bkg = "#fff";
		} else {
			this.element.css("border-color", "black");
			bkg = "#aaa";
		}
		
		
		if (this.selected || true) {
			var height = 36;
			var width = 65;
			
			this.element.css({
				width: width,
				height: height
			});
		} else {
			var height = 36;
			var width = 56;
			this.element.stop().css({
				width: width,
				height: height
			});
		}
		
		this.lineHome.redraw();
		this.lineAway.redraw();
	},
	selectHome: function() {
		this.lineHome.select();
	},
	selectAway: function() {
		this.lineAway.select();
	},
	clearHome: function() {
		this.lineHome.clear();
	},
	clearAway: function() {
		this.lineAway.clear();
	},
	hover: function() {
		if (this.leftNode.hasClass("leftWon")) {
			this.leftNode.addClass("leftWonHover");
		} else {
			this.leftNode.addClass("leftHover");
		}
		
		if (this.rightNode.hasClass("rightWon")) {
			this.rightNode.addClass("rightWonHover");
		} else {
			this.rightNode.addClass("rightHover");
		}
	},
	unhover: function() {
		this.leftNode.removeClass("leftWonHover");
		this.leftNode.removeClass("leftHover");
		
		this.rightNode.removeClass("rightWonHover");
		this.rightNode.removeClass("rightHover");
	}
});




Ladder.OldFinal = Ladder.MatchNode.extend({
	init: function(index, lm) {
		this._super(index, lm);
		this.lineHome = new Ladder.Line(index, index*2, -1, this.ladderManager);
		this.lineAway = new Ladder.Line(index, index*2+1, 1, this.ladderManager);
	},
	build: function() {
		this.element.addClass("final");
		
		var match = this.getMatch();
		
		this.element.append( match.homeName );
		this.element.append( "<br/>-<br/>" );
		this.element.append( match.awayName );
		
		this.element.width( Ladder.Manager.FINAL_WIDTH ).height( Ladder.Manager.FINAL_HEIGHT );
		
		this.lineHome.build();
		this.lineAway.build();
	},
	position: function() {
		this.element.css("left", this.ladderManager.element.width()/2 - this.element.width()/2);
		this.element.css("top", this.ladderManager.element.height()/2 - this.element.height()/2);
		
		this.lineHome.position();
		this.lineAway.position();
	},
	redraw: function() {
		this.lineHome.redraw();
		this.lineAway.redraw();
	},
	selectHome: function() {
		this.lineHome.select();
	},
	selectAway: function() {
		this.lineAway.select();
	},
	clearHome: function() {
		this.lineHome.clear();
	},
	clearAway: function() {
		this.lineAway.clear();
	}
});





Ladder.Connector = Ladder.Drawable.extend({
	init: function(homeIndex, awayIndex, toIndex, lm) {
		this._super(lm);
		this.homeIndex = homeIndex;
		this.awayIndex = awayIndex
		this.toIndex = toIndex;
		this.dir = Ladder.Manager.getDirection(this.toIndex);
	},
	
	build: function() {
		this.element.addClass("connector");
		
		this.upper = jQuery("<div/>").appendTo(this.element).addClass("upper");
		this.lower = jQuery("<div/>").appendTo(this.element).addClass("lower");
		
		var match = this.ladderManager.getMatch(this.homeIndex);
		if (match) {
			var matchNode = new Ladder.Point(this.homeIndex, this.ladderManager);
			matchNode.build();
		} else {
			var node = new Ladder.TeamNode(this.homeIndex, this.ladderManager);
			node.build();
		}
		match = this.ladderManager.getMatch(this.awayIndex, this.ladderManager);
		if (match) {
			var matchNode = new Ladder.Point(this.awayIndex, this.ladderManager);
			matchNode.build();
		} else {
			var node = new Ladder.TeamNode(this.awayIndex, this.ladderManager);
			node.build();
		}
		
		this.clear();
	},
	
	position: function() {
		var home = this.ladderManager.getNode(this.homeIndex);
		var away = this.ladderManager.getNode(this.awayIndex);
		
		var height = this.ladderManager.element.height()/Ladder.Manager.getTop(this.toIndex);
		
		var minHeight = this.ladderManager.getSmallestConnectorHeight();
		var width = this.ladderManager.getHorizSpacing();
		
		this.element.width( width );
		
		if ( home instanceof Ladder.TeamNode && away instanceof Ladder.TeamNode ) {
			this.element.height( minHeight );
		} else {
			this.element.height( height );
		}
		
		this.upper.height(this.element.height()/2);
		this.lower.height(this.element.height()/2);
		
		if ( home instanceof Ladder.TeamNode && height > minHeight ) {
			var offset = 0.5 * height / minHeight;
			if (this.dir<0) {
				this.upper.css("left", -offset*width);
			}
			this.upper.css("width", (width*offset*2));
		}
		if ( away instanceof Ladder.TeamNode && height > minHeight ) {
			var offset = 0.5 * height / minHeight;
			if (this.dir<0) {
				this.lower.css("left", -offset*width);
			}
			this.lower.css("width", (width*offset*2));
		}
		
		var to = this.ladderManager.getNode( this.toIndex );
		var toHomePoint = {left:0, top:0};
		var toAwayPoint = {left:0, top:0};
		
		if(this.dir > 0) {
			// H�ger.
			var point = to.getCenterPoint();
			this.element.css("left", point.left );
			this.element.css("top", point.top - this.element.height()/2 );
			
			toHomePoint.left = point.left + this.upper.width();
			toAwayPoint.left = point.left + this.lower.width();
			
			toHomePoint.top = point.top - this.element.height()/2;
			toAwayPoint.top = point.top + this.element.height()/2;
		}
		
		if(this.dir < 0) {
			// V�nster.
			var point = to.getCenterPoint();
			point.left += 1;
			this.element.css("left", point.left - this.element.width() );
			this.element.css("top", point.top - this.element.height()/2 );
			
			toHomePoint.left = point.left - this.upper.width();
			toAwayPoint.left = point.left - this.lower.width();
			
			toHomePoint.top = point.top - this.element.height()/2;
			toAwayPoint.top = point.top + this.element.height()/2;
		}
		
		
		if(home) { 
			home.setPosition(toHomePoint.left, toHomePoint.top);
			home.position();
		}
		if(away) {
			away.setPosition(toAwayPoint.left, toAwayPoint.top);
			away.position();
		}
		
		this.redraw();
	},
	redraw: function() {
		var upperThickness = "1px";
		var lowerThickness = "1px";
		if( this.upperSelected ) {
			upperThickness = "3px";
		}
		if( this.lowerSelected ) {
			lowerThickness = "3px";
		}
		var color = "#89b";
		if (this.dir < 0) {
			// V�nster.
			this.upper.css("border-right", upperThickness+" solid "+color);
			this.upper.css("border-top", upperThickness+" solid "+color);
			
			this.lower.css("border-right", lowerThickness+" solid "+color);
			this.lower.css("border-bottom", lowerThickness+" solid "+color);
		}
		if (this.dir > 0) {
			// H�ger.
			this.upper.css("border-left", upperThickness+" solid "+color);
			this.upper.css("border-top", upperThickness+" solid "+color);
			
			this.lower.css("border-left", lowerThickness+" solid "+color);
			this.lower.css("border-bottom", lowerThickness+" solid "+color);
		}
	},
	
	clear: function(){
		this.upperSelected = false;
		this.lowerSelected = false;
		this.redraw();
	},
	selectUpper: function() {
		this.upperSelected = true;
		this.redraw();
	},
	selectLower: function() {
		this.lowerSelected = true;
		this.redraw();
	},
	clearUpper: function() {
		this.upperSelected = false;
		this.redraw();
	},
	clearLower: function() {
		this.lowerSelected = false;
		this.redraw();
	}
});




Ladder.Line = Ladder.Drawable.extend({
	init: function(fromIndex, toIndex, direction, lm) {
		this._super(lm);
		this.fromIndex = fromIndex;
		this.toIndex = toIndex;
		this.direction = direction;
	},
	
	build: function() {
		this.element.html("<!-- -->");
		this.element.addClass("line");
		// this.element.width( this.ladderManager.getHorizSpacing() );
		this.element.width( 20 );
		
		this.box = jQuery("<div/>");
		this.ladderManager.element.append(this.box);
		this.box.css("position", "absolute");
		
		this.box.height(17 + this.direction).width(70);
		
		if ( this.direction > 0 ) { // H�ger
			this.box.css("border-bottom", "1px solid #89b");
			this.box.css("border-right", "1px solid #89b");
		} else {
			this.box.css("border-top", "1px solid #89b");
			this.box.css("border-left", "1px solid #89b");
		}
		
		
		var match = this.ladderManager.getMatch(this.toIndex);
		if (match) {
			var matchNode = new Ladder.Point(this.toIndex, this.ladderManager);
			matchNode.build();
		} else {
			var node = new Ladder.TeamNode(this.toIndex, this.ladderManager);
			node.build();
		}
	},
	
	position: function() {
		var f = this.ladderManager.getNode(this.fromIndex);
		var toPoint = {left:0, top:0};
		
		var extraSpace = 40 * this.direction;
		
		if ( this.direction > 0 ) { // H�ger
			var point = f.getRightPoint();
			this.element.css("left", point.left + extraSpace -3 );
			this.element.css("top", point.top - this.element.height());
			toPoint.left = point.left + this.element.outerWidth() + extraSpace;
			toPoint.top = point.top;
			
			this.box.css("left", point.left + extraSpace - this.box.outerWidth() );
			this.box.css("top", point.top);
		}
		if ( this.direction < 0 ) { // V�nster
			var point = f.getLeftPoint();
			this.element.css("left", point.left - this.element.outerWidth() + extraSpace );
			this.element.css("top", point.top - this.element.height());
			
			toPoint.left = point.left- this.element.outerWidth()+ extraSpace;
			toPoint.top = point.top;
			
			this.box.css("left", point.left + extraSpace);
			this.box.css("bottom", point.top);
			
		}
		
		this.ladderManager.getNode(this.toIndex).setPosition(toPoint.left, toPoint.top);
		this.ladderManager.getNode(this.toIndex).position();
		
		this.redraw();
	},
	redraw: function () {
		if ( this.selected ) {
			this.element.css("border-bottom", "3px solid #89b");
			this.box.css("border-width", "3px").css("margin-left", "-3px");
		} else {
			this.element.css("border-bottom", "1px solid #89b");
			this.box.css("border-width", "1px").css("margin-left", "-1px");
		}
	},
	
	select: function() {
		this.selected = true;
		this.redraw();
	},
	clear: function() {
		this.selected = false;
		this.redraw();
	}
});
if (typeof CupMan == "undefined") {
	CupMan = {};
}

CupMan.MapPart = function() {
	this.selectedMarkerId = -1;
	this.selectedDay = 1;
	this.locations = new List();
	
	this.visibleTypes = new Set();
	
	// Register global variable
	window.mapPart = this;
	
	this.noFilter = false;
}

CupMan.MapPart.prototype.addLocation = function(loc) {
	this.locations.add(loc);
}

CupMan.MapPart.prototype.init = function(mapElement) {
	try {
		var thiz = this;
		this.map = new CupMan.Map( mapElement );
		
		for ( var i=0; i<this.locations.size(); i++ )
		{
			var loc = this.locations.get(i);
			
			var m = this.map.addMarker( loc.id, loc.name, loc.type, loc.lat, loc.lng );
			m.street = loc.street;
			m.postal = loc.postal;
			m.city = loc.city;
			m.nation = loc.nation;
			m.entityId = loc.entityId;
		}
		this.map.fit();
		
		this.map.clickEvent.subscribe(function(marker){
			thiz.markerClicked(marker);
		});
		
		jQuery("#directions .close").click(function() {
			jQuery("#directions").slideUp();
			return false;
		});
		
		jQuery("#directions button").click(function(){
			var m = thiz.map.markers.get(thiz.selectedMarkerId);
			
			var url = "http://maps.google.com/maps?f=d&daddr=$DEST&saddr=$SOURCE&hl=sv&geocode=&mra=cc&ie=UTF8&z=7&pw=2";
			url = url.replace("$DEST", m.getLatLng().lat()+","+m.getLatLng().lng());
			url = url.replace("$SOURCE", jQuery("#directions input#from").val());
			
			window.open(url);
		});
		
		thiz.filterMarkers();
	} catch (e) {
		console.log(e);
	}
}

CupMan.MapPart.prototype.addFilter = function(type) {
	this.visibleTypes.add(type);
	this.filterMarkers();
}
CupMan.MapPart.prototype.removeFilter = function(type) {
	this.visibleTypes.remove(type);
	this.filterMarkers();
}
CupMan.MapPart.prototype.setFilter = function(type) {
	this.visibleTypes.clear();
	this.addFilter(type);
}

CupMan.MapPart.prototype.filterMarkers = function() {
	var markers = this.map.markers.values();
	
	for ( var i=0; i<markers.length; i++ )
	{
		var m = markers[i];
		if ( this.isMarkerVisible(m) ) {
			m.show();
		} else {
			m.hide();
		}
	}
}

CupMan.MapPart.prototype.isMarkerVisible = function(m)
{
	return this.visibleTypes.contains(m.type) || this.noFilter;
}


CupMan.MapPart.prototype.selectLocation = function(id)
{
	if ( id != "" ) {
		var m = this.map.markers.get(id);
		
		this.selectMapMarker(m);
		
		jQuery("#directions .name").html( m.title );
		jQuery("#directions .street").html( m.street );
		if (m['postal']) {
			jQuery("#directions .postal").html( m.postal );
		} else {
			jQuery("#directions .postal").html( "" );
		}
		jQuery("#directions .city").html( m.city );
		jQuery("#directions .nation").html( m.nation );
	} else {
		this.map.map.closeInfoWindow();
		jQuery("#directions #address").html( "" );
		jQuery("#directions #toLocation").html( "" );
	}
}

CupMan.MapPart.prototype.showDirections = function()
{
	this.map.map.closeInfoWindow();
	jQuery("#directions").slideDown();
	return false;
}

CupMan.MapPart.prototype.markerClicked = function(m)
{
	this.selectMapMarker( m );
	this.selectLocation(m.id);
}

CupMan.MapPart.prototype.selectMapMarker = function(m)
{
	var thiz = this;
	
	m.show();
	this.selectedMarkerId = m.id;
	
	this.map.map.panTo( m.getLatLng() );
	
	
	var contentNode = document.createElement("div");
	jQuery(contentNode).html('<img src="http://static.cupmanager.net/images/spinner.gif" />');
	
	var center = thiz.map.map.getCenter();
	
	this.map.map.openInfoWindowHtml(m.getLatLng(), '<img src="http://static.cupmanager.net/images/spinner.gif" />', {
		onOpenFn: function() {
			CupMan.callService("mapPopupContent", {
				data: {
					type: m.type,
					id: m.entityId
				},
				success: function(result) {
					jQuery(contentNode).html(result);
					thiz.map.map.getInfoWindow().maximize();
				},
				error: function() {
					thiz.map.map.closeInfoWindow();
					thiz.map.map.openInfoWindowHtml(m.getLatLng(), "Error");
				}
			});
			
			GEvent.addListener(thiz.map.map.getInfoWindow(), "restoreend", function() {
				thiz.map.map.setCenter(center);
				thiz.map.map.closeInfoWindow();
				
			});
			
		},
		onCloseFn: function() {
			thiz.map.map.setCenter(center);
		},
		maxContent: contentNode, maxTitle: m.title
	});
}

CupMan.MapPart.prototype.getPopupContent = function(m) {
	if ( m.type == "Arena" ) {
		
		var content = '<h3>'+m.title+'</h3> '
			+'<a href="'+pageLoader.getHashedLink(getBaseUrl()+"result/arena/"+m.entityId)+'">View matches in '+m.title+'</a>'
			+'<h4>Driving directions:</h4>'
			
			+'<b>Address:</b><br/> '+m.street+', '+(m['postal']?m.postal:"")+' '+m.city+'<br/>'
			+'<a href="#'+m.entityId+'-'+m.title+'" onclick="window.mapPart.showDirections(); return false;">Get directions to '+m.title+'</a>';
		
		return content;
	} else {
		var content = '<h3>'+m.title+'</h3> '
			+'<b>Address:</b><br/> '+m.street+', '+(m['postal']?m.postal:"")+' '+m.city+'<br/>'
			+'<a href="#'+m.entityId+'-'+m.title+'" onclick="window.mapPart.showDirections(); return false;">Get directions to '+m.title+'</a>';
		
		return content;
	}
}
MapOverview = function() {
	this.selectedMarkerId = -1;
	this.selectedDay = 1;
}

MapOverview.prototype.addLocation = function(loc) {
	mapPart.addLocation(loc);
}

MapOverview.prototype.init = function() {
	var thiz = this;
	
	jQuery("#thingsContainer .buttonLink a").click(function(ev){
		var button = jQuery(this).closest(".buttonLink");
		
		button.toggleClass("selectedButtonLink");
		
		var type = button.find("a").attr("href").substr(1);
		
		if (button.hasClass("selectedButtonLink"))
		{
			mapPart.addFilter(type);
		} else {
			mapPart.removeFilter(type);
		}
		
		thiz.filter();
		return false;
	});
	
	jQuery(".locations a").live("click", function() {
		var id = jQuery(this).attr("locationId");
		
		jQuery("html,body").animate({scrollTop:0}, 500, function() {
			mapPart.selectLocation(id);
		})
		
		return false;
	});
	
	thiz.filter();
}

MapOverview.prototype.filter = function() {
	mapPart.filterMarkers();
	
	jQuery("#thingsContainer .buttonLink").each(function() {
		var type = jQuery(this).find("a").attr("href").substr(1);
		
		var locationElements = jQuery(".hiddenLocations ."+type);
		
		if (jQuery(this).is(".selectedButtonLink"))
		{
			locationElements.css("display", "block");
		} else {
			locationElements.css("display", "none");
		}
	});
	jQuery(".hiddenLocations").columnize({target:".locations", columns:4});
	
}

var ReggedClubs = function() {
	this.clubs = new Map();      // id -> club
	this.clubTeams = new Map();  // club -> teams
	this.categories = new Map(); // category -> teams
	this.markers = new Map();    // id -> marker
	this.alfaClubs = new Map();  // bokstav -> clubs
	
	this.filteredCategory = null;
	
	this.mouseoverlistener = null;
	this.mouseoutlistener = null;
	this.clicklistener = null;
	this.glow_suffix = "glow";
	this.selected_suffix = "glow";
	this.disabled_suffix = "gray";
	
	this.map = null;
	
	this.linkClubs = false;
}

ReggedClubs.prototype.init = function() {
	var thiz = this;
	
	this.map = new GMap2( jQuery("div#map").get(0) );
	this.map.setCenter( new GLatLng(34,52), 1 );
	this.map.enableScrollWheelZoom();
	this.map.enableContinuousZoom();
	this.map.addControl(new GLargeMapControl());
	
	this.map.setMapType(G_PHYSICAL_MAP);
	
	this.mouseoverlistener= function(marker, point) {
		if( this && this.isEnabled ){
			thiz.setImage(this.entityId, "http://maps.cupmanager.net/map_icons/"+this.iconId+"_"+thiz.glow_suffix+".png");
		}
	};
	
	this.mouseoutlistener= function(marker, point) {
		if( this && this.isEnabled ){
			thiz.setImage(this.entityId, "http://maps.cupmanager.net/map_icons/"+this.iconId+".png");
		}
	};
	
	this.clicklistener= function(marker, point) {
		if( this && this.isEnabled ){
			var club = thiz.clubs.get( this.entityId );
			if (thiz.linkClubs) {
				thiz.map.openInfoWindow( point, 
					thiz.getClubPopupHtml(club)
				);
			}
		}
	};
	
	jQuery("#hiddenClubs").columnize({columns:3, target:"#clubs"});
	
	jQuery(".buttonLink a").click(function() {
		
		jQuery(".selectedButtonLink").removeClass("selectedButtonLink");
		jQuery(this).closest(".buttonLink").addClass("selectedButtonLink");
		
		var href = jQuery(this).attr("href").substr(1);
		if (href.indexOf("category_") == 0) {
			href = href.substr(9);
		}
		
		if (href=="all") {
			thiz.doFilter(this, null);
		} else {
			thiz.doFilter(this, parseInt(href));
		}
		
		return false;
	});
	
	
	jQuery("#clubPopupCloseBtn").click(function(){ tb_remove() });
	
	if (jQuery(".buttonLink a[href='#all']").length > 0) {
		this.doFilter(jQuery(".buttonLink a[href='#all']").get(), null);
	}
	
	jQuery("#mapItem").click();
} // End of init()

ReggedClubs.prototype.setClubs = function(clubs) {
	var minLat = 10000;
	var minLng = 10000;
	var maxLat = -10000;
	var maxLng = -10000;
	// clubs = [ { name:"", teams:{"288":12, "289":11}, id:12238, lat:1, lng:12, nationCode:"SE" } ]
	for (var i=0; i<clubs.length; i++)
	{
		var club = clubs[i];
		this.clubTeams.put(club, new List());
		this.clubs.put(club.id, club);
		this.mapAlfaClub(club.name.toUpperCase().charAt(0), club);
		
		var lat = parseFloat(club.lat);
		var lng = parseFloat(club.lng);
		if ( lat < -0.5 || lat > 0.5 || lng < -0.5 || lng > 0.5 )
		{
			if ( lat > maxLat ) { maxLat = lat; }
			if ( lat < minLat ) { minLat = lat; }
			if ( lng > maxLng ) { maxLng = lng; }
			if ( lng < minLng ) { minLng = lng; }
			
			this.addClubMarker( club.id );
		}
		
		for (catId in club.teams)
		{
			var count = club.teams[catId];
			for (var j=0; j<count; j++)
			{
				var team = {
					id: 0,
					categoryId: catId,
					name: club.name,
					club: club
				};
				
				this.clubTeams.get(club).add(team);
				this.mapCategoryTeam(catId, team);
			}
		}
	}
	
	// Center around markers
	var sw = new GLatLng(minLat,minLng);
	var ne = new GLatLng(maxLat,maxLng);
	var bounds = new GLatLngBounds(sw, ne);
	
	this.map.setCenter(bounds.getCenter(), this.map.getBoundsZoomLevel(bounds));
	
}


jQuery(document).unload(
  function() {
    GUnload();
  }
);


ReggedClubs.prototype.mapCategoryTeam = function(categoryId, team)
{
	if (!this.categories.containsKey(categoryId))
		this.categories.put( categoryId, new List() );
	this.categories.get(categoryId).add(team);
}
ReggedClubs.prototype.mapAlfaClub = function(alfa, club)
{
	if (!this.alfaClubs.containsKey(alfa))
		this.alfaClubs.put( alfa, new List() );
	this.alfaClubs.get(alfa).add(club);
}

///////


ReggedClubs.prototype.showClubPopup = function(clubId)
{
	var club = this.clubs.get(clubId);
	jQuery("#clubPopup h2").html( club.name );
	jQuery("#clubPopup_nation").html( club.nation );
	jQuery("#clubPopup_city").html( club.city );
	jQuery("#clubPopup_shirtcolor").html( club.shirtcolor+" " );
	
	jQuery("#clubLink").attr("href", "club/" + club.id);
	
	var teams = this.clubTeams.get(club);
	jQuery("#clubPopup_teams").html( teams.size()+" " );
	
	var categoryTeams = new Map();
	var categoryNames = new Map();
	for ( var i=0; i<teams.size(); i++ )
	{
		var cat = teams.get(i).categoryId;
		if ( !categoryTeams.containsKey(cat) )
			categoryTeams.put(cat, 0);
		categoryTeams.put( cat, categoryTeams.get(cat) + 1 );
		categoryNames.put( cat, jQuery("#categoryLink_"+cat).html() );
	}
	
	var cats = categoryTeams.keys();
	cats.sort(function(a,b) {
		if ( categoryNames.get(a).toLowerCase() < categoryNames.get(b).toLowerCase() ) 
			return -1;
		if ( categoryNames.get(a).toLowerCase() > categoryNames.get(b).toLowerCase() ) 
			return 1;
		return 0;
	});
	var teamlist = jQuery("#clubPopup_teamlist");
	teamlist.html("");
	for ( var i=0; i<cats.length; i++ )
	{
		var catId = cats[i];
		var count = categoryTeams.get(catId);
		var catName = categoryNames.get(catId);
		
		teamlist.append("<label>"+catName+": "+count+"</label><br/>");
	} 
	tb_show('Club', '#TB_inline?height=300&width=300&inlineId=clubPopup&modal=true', '');
	return false;
}

///////


ReggedClubs.prototype.filterCategory = function(id)
{
	this.filteredCategory = id;
}
ReggedClubs.prototype.refresh = function()
{
	var clubs = this.getTeamsClubs(this.getVisibleTeams());
	this.filterMap(clubs);
	
	this.rebuildClubs(clubs);
	
	//rebuildClubsOLD(clubs);
	//spalta();
}

ReggedClubs.prototype.doFilter = function(a, id)
{
	var thiz = this;
	jQuery("a.selected").removeClass("selected");
	jQuery(a).addClass("selected");
	jQuery(a).addClass("working");
	jQuery("#registeredHeader").html( jQuery(a).html().toLowerCase() );
	setTimeout( function() {
		thiz.filterCategory(id);
		thiz.refresh();
		jQuery(a).removeClass("working");
	}, 10);
	return false;
}



ReggedClubs.prototype.getVisibleTeams = function()
{
	var teams = new List();
	var catKeys = this.categories.keys();
	for ( var i=0; i<catKeys.length; i++ )
	{
		var key = catKeys[i];
		
		if ( this.filteredCategory == key || this.filteredCategory == null )
		{
			var catTeams = this.categories.get(key);
			teams.addAll(catTeams);
		}
	}
	return teams;
}

ReggedClubs.prototype.getTeamsClubs = function(teams)
{
	var clubs = new List();
	for ( var i=0; i<teams.size(); i++)
	{
		var team = teams.get(i);
		if ( !clubs.contains(team.club) )
			clubs.add( team.club );
	}
	return clubs;
}

ReggedClubs.prototype.filterMap = function(clubs)
{
	var markerKeys = this.markers.keys();
	var clubIds = new Set();
	for ( var i=0; i<clubs.size(); i++ )
	{
		clubIds.add( clubs.get(i).id );
	}
	
	for ( var i=0; i<markerKeys.length; i++ )
	{
		var clubId = markerKeys[i];
		if ( !clubIds.contains(clubId) )
			this.markers.get(clubId).hide();
		else
			this.markers.get(clubId).show();
	}
}


ReggedClubs.prototype.rebuildClubsOLD = function(visibleClubs)
{
	var div = jQuery("#teamList");
	div.html("");
	var alfas = alfaClubs.keys().sort();
	
	for ( var i=0; i<alfas.length; i++ )
	{
		var alfa = alfas[i];
		
		var visibleAlfaClubs = new List();
		var clubs = alfaClubs.get(alfa);
		for ( var j=0; j<clubs.size(); j++ )
		{
			var c = clubs.get(j);
			if ( visibleClubs.contains(c) )
			{
				visibleAlfaClubs.add(c);
			}
		}
		
		if ( visibleAlfaClubs.size() > 0 )
		{
			visibleAlfaClubs.sort(function(a,b) {
				if ( a.name.toLowerCase() < b.name.toLowerCase() ) 
					return -1;
				if ( a.name.toLowerCase() > b.name.toLowerCase() ) 
					return 1;
				return 0;
			});
			
			div.append("<h2>"+alfa+"</h2>");
			
			for ( var j=0; j<visibleAlfaClubs.size(); j++ )
			{
				var c = visibleAlfaClubs.get(j);
				div.append("<a href=\"registered/Club\">"+c.name+"</a><br/>");
			}
		}
	}
}



ReggedClubs.prototype.rebuildClubs = function(visibleClubs)
{
	var catId = this.filteredCategory;
	if (catId == null) {
		jQuery("#hiddenClubs a").css("display", "block");
	} else {
		jQuery("#hiddenClubs a:not(.cat_"+catId+")").hide();
		jQuery("#hiddenClubs a.cat_"+catId).css("display", "block");
	}
	
	jQuery("#hiddenClubs").columnize({columns:3, target:"#clubs"});
	
	jQuery("#clubs h2").each(function() {
		var next = jQuery(this).nextAll(":visible").eq(0);
		if ( next.is("h2") || next.length==0 ) {
			jQuery(this).hide();
		}
	});
}

ReggedClubs.prototype.getClubPopupHtml = function(club)
{
	var html = "";
	
	html += "<h4>"+club.name+"</h4>";
	
	html += '<a href="'+pageLoader.getHashedLink(getBaseUrl()+"result/club/"+club.id)+'">';
	
	html += '<img style="padding-right:3px; float:left;" title="'+club.nation+'" src="http://static.cupmanager.net/images/flags_iso/48/'+club.nationCode.toLowerCase()+'.png"/>'; 
	
	html += 'Go to the page for '+club.name+'</a>';
	
	return html;
}

ReggedClubs.prototype.spalta = function()
{
	var teamList = jQuery("#teamList");
	var spalter = new Array( jQuery("#spalt1"), jQuery("#spalt2"), jQuery("#spalt3")  );
	jQuery(".spalt").html("");
	var children = teamList.children();
	var perSpalt = Math.ceil( children.length / spalter.length );
	
	for ( var i=0; i<children.length; i++ )
	{
		var j = Math.floor( i / perSpalt );
		var el = children.get(i);
		
		if (el.tagName.toLowerCase() == "h2" 
			&& i % perSpalt == perSpalt - 1
			&& j < spalter.length-1)
		{
			j++;
		}
		
		var spalt = spalter[ j ];
		spalt.append( el );
	}
	
	teamList.html("");
}

///

ReggedClubs.prototype.addClubMarker = function(id)
{
	var club = this.clubs.get(id);
	this.addMarker(club.id, new GLatLng(club.lat, club.lng), {title: club.name} );
}

ReggedClubs.prototype.addMarker = function(id, point, options)
{
	if(this.markers.containsKey(id))
	{
		this.removeMarker(id);
	}
	
	var iconId = "simple";
	
	if ( !options )
		options = {};
	
	if( options && options.icon )
	{
		iconId = options.icon;
		options.icon = this.getIcon(iconId);
	} else {
		options.icon = this.getIcon(iconId);
	}
	
	marker = new GMarker(point, options);
	marker.entityId = id;
	marker.iconId = iconId;
	marker.isEnabled = true;
	this.markers.put(id,marker);
	GEvent.addListener(marker,"mouseover", this.mouseoverlistener);
	GEvent.addListener(marker,"mouseout", this.mouseoutlistener);
	GEvent.addListener(marker,"click", this.clicklistener);
	
	this.map.addOverlay(marker);
}

ReggedClubs.prototype.removeMarker = function(id) { 	
	this.map.removeOverlay(this.markers.get(id));
}

ReggedClubs.prototype.setImage = function(id, url) {
	this.markers.get(id).setImage(url);
}

ReggedClubs.prototype.getIcon = function(iconId){
	var icon = new GIcon();
	icon.image = "http://maps.cupmanager.net/map_icons/"+iconId+".png";
	icon.shadow = "http://maps.cupmanager.net/map_icons/"+iconId+"_shadow.png";
	icon.iconSize = new GSize(32.0, 32.0);
	icon.shadowSize = new GSize(49.0, 32.0);
	icon.iconAnchor = new GPoint(15.0, 32.0);
	icon.infoWindowAnchor = new GPoint(16.0, 16.0);

	return icon;
}


var RealTimeSearch = function(title, serviceName) {
	this.currentQuery = "";
	this.running = false;
	this.delay = 0;
	this.timeoutHandle = null;
	
	this.serviceName = serviceName || "search";
	
	this.searchDomains = new List();
	
	this.addSearchDomain(CupMan.wr.otherIds.noEdSc, title);
}

RealTimeSearch.prototype.init = function() {
	this.searchBox = jQuery("#searchBox");
	this.submit = jQuery("#searchsubmit");
    
	this.resultArea = jQuery("#searchResultArea");
	this.tempArea = jQuery("<div/>");
	
	var instance = this;
	this.searchBox.keyup(function(e){
		if(e.keyCode == 13 || !e.keyCode) {
			instance.delayedSearch( jQuery(this).val() );
		}
	});
	
	if( this.submit )
	{
		this.submit.click(function(e){
            instance.delayedSearch( jQuery("#searchBox").val() );
            return false;
		});
	}
}


RealTimeSearch.prototype.addSearchDomain = function(ids, title) {
	this.searchDomains.add( {ids: ids, title: title} );
}


RealTimeSearch.prototype.delayedSearch = function(query) {
	if ( query == "" ) {
		this.resultArea.html("");
		this.hideSpinner();
	} else {
		if ( this.currentQuery != query ) {
			var instance = this;
			this.showSpinner();
			clearTimeout(this.timeoutHandle);
			this.timeoutHandle = setTimeout( function(){
				instance.performSearch(query);
			}, this.delay );
		} else {
			this.hideSpinner();
		}
	}
}

RealTimeSearch.prototype.performSearch = function(query) {
	if ( query == "" ) {
		this.resultArea.html("");
		this.hideSpinner();
	} else {
		if ( this.currentQuery != query || true ) {
			this.currentQuery = query;
			this.ajaxSearchCall(query);
		} else {
			this.hideSpinner();
		}
	}
}

RealTimeSearch.prototype.ajaxSearchCall = function(query) {
	var instance = this;
	
	instance.tempArea.html("");
	
	var icount = this.searchDomains.size();
	
	for (var i=0; i<icount; i++)
	{
		var domain = this.searchDomains.get(i);
		
		CupMan.callService(this.serviceName+"/" + encodeURIComponent(query), {
			success: function(i,title) {
				return function(html) {
					
					var div = jQuery("<div/>");
					div.append("<h2 class='searchTitle'>"+title+"</h2>");
					div.append(html);
					div.addClass("searchDomain_"+i);
					
					if (div.find(".empty").size() == 0) {
						instance.tempArea.append(div);
					}
					
					icount--;
					if (icount == 0) {
						instance.searchComplete();
					}
				}
			}(i, domain.title),
			error: function(root, err, a, b, c) {
				console.log(err, a, b, c);
			}
		}, {ids: domain.ids});
	}
}

RealTimeSearch.prototype.searchComplete = function() {
	this.hideSpinner();
	var forQuery = this.tempArea.find("span.searchQuery").attr("query");
	
	// if ( forQuery == this.searchBox.val() ) 
	{
		this.resultArea.html("");
		this.tempArea.children().appendTo( this.resultArea );
		this.setupMaps();
		this.setupDropdowns();
		this.attachTracker();
		
		this.resultArea.find(".searchResultBox").each(function(){
			if ( jQuery(this).height() < 30 ) {
				jQuery(this).height(30);
			}
		});
		
		if (typeof pageLoader != "undefined") {
			pageLoader.hashLinks();
		}
	}
}

RealTimeSearch.prototype.attachTracker = function() {
	var thiz = this;
	this.resultArea.find("a").click(function() {
		if (pageLoader && pageLoader['pageTracker']) {
			//console.log("Search", "Search", thiz.searchBox.val());
			pageLoader.pageTracker._trackEvent("Search", "Search", thiz.searchBox.val());
		}
	});
}

RealTimeSearch.prototype.setupMaps = function() {
	var maps = this.resultArea.find(".searchResultMap");
	
	var thiz = this;
	maps.each(function() {
		var mapEl = jQuery('<div class="gmap"></div>').appendTo( jQuery(this) );
		mapEl.width("100%");
		mapEl.height(300);
		var gmap = new CupMan.Map( mapEl );
		
		jQuery(this).children("span").each(function() {
			var el = jQuery(this);
			gmap.addMarker(0, el.attr("name"), "Arena", el.attr("lat"), el.attr("lng"));
		});
		
		gmap.fit();
		gmap.setZoom(14);
	});
}

RealTimeSearch.prototype.setupDropdowns = function() {
	var thiz = this;
	var menus = this.resultArea.find(".searchResultDropdownMenus");
	var container = this.resultArea.find(".searchResultDropdownContainer");
	
	menus.find(".searchResultDropdownMenu a").click(function() {
		var link = jQuery(this);
		var menus = link.parents(".searchResultDropdownMenus");
		var container = menus.siblings(".searchResultDropdownContainer");
		
		var index = link.parents(".searchResultDropdownMenu").attr("index");
		var boxes = container.find(".searchResultDropdownBox");
		boxes.hide();
		var box = container.find(".searchResultDropdownBox[index='"+index+"']");
		box.show();
		
		if (!link.hasClass("expanded")) {
			menus.find(".searchResultDropdownMenu a").removeClass("expanded");
			
			container.animate({height: box.height() + 25}, 200, function(){
				link.addClass("expanded");
			});
		} else {
			container.animate({height: 0}, 200, function(){
				link.removeClass("expanded");
			});
		}
		
		return false;
	});
}

RealTimeSearch.prototype.showSpinner = function() {
	this.searchBox.addClass("searching");
}
RealTimeSearch.prototype.hideSpinner = function() {
	this.searchBox.removeClass("searching");
}
var MenuManager = function() {
	this.element = null;
	this.menuHandlers = new Map();
}

MenuManager.prototype.init = function() {
	var el = this.element = jQuery("<div/>");
	el.hide();
	jQuery(document.body).append( el );
	
	el.addClass("popupMenu");
	
	var thiz = this;
	jQuery(document.body).click(function(ev) {
		
		var isHandledType = false;
		var clicked = jQuery(ev.target);
		
		var types = thiz.menuHandlers.keys();
		for (var i=0; i<types.length; i++) {
			var type = types[i];
			
			if ( clicked.is("."+type) ) {
				isHandledType = true;
			}
		}
		
		if ( !isHandledType ) {
			thiz.hideDropDown();
		}
	});
}

MenuManager.prototype.setMenuHandler = function(type, func) {
	this.menuHandlers.put(type, func);
	this.attach();
}

MenuManager.prototype.attach = function(container) {
	if (!container) {
		container = document.body;
	}
	container = jQuery(container)
	
	var types = this.menuHandlers.keys();
	for (var i=0; i<types.length; i++) {
		var type = types[i];
		this.attachToType(container, type);
	}
}

MenuManager.prototype.attachToType = function(container, type) {
	
	var func = this.menuHandlers.get(type);
		
	var thiz = this;
	container.find("."+type).unbind("click").click(function() {
		var el = jQuery(this);
		if ( !el.is("."+type+"Pressed") ) {
			var doThis = thiz.generateDropDown(func, el);
			if (doThis) {
				thiz.dropDown(el, type);
			}
		} else {
			thiz.hideDropDown();
		}
		
		return false;
	}).blur(function() {
		// Stupid Safari & Chrome
		//thiz.hideDropDown();
	});
}

MenuManager.prototype.generateDropDown = function(func, srcElement) {
	var thiz = this;
	
	var items = func(srcElement);
	
	if (items.length == 0) {
		return false;
	}
	
	this.element.html("");
	
	for (var i=0; i<items.length; i++) {
		var item = items[i];
		
		var menuItem = jQuery('<a href="'+item.url+'"> &#8227; '+item.title+'</a>').appendTo(this.element);
		menuItem.addClass("menuItem");
		if (item.onclick) {
			menuItem.click( function() {
				thiz.hideDropDown();
				return item.onclick();
			} );
		}
		
		menuItem.hover(function() {
			jQuery(this).addClass("menuItemHover");
		}, function() {
			jQuery(this).removeClass("menuItemHover");
		});
	}
	
	return true;
}

MenuManager.prototype.dropDown = function(sourceElement, type) {
	
	clearTimeout(this.hideTimeout);
	this.hideTimeout = null;
	
	var pos = sourceElement.offset();
	var height = sourceElement.outerHeight();
	
	this.element.css("left", pos.left);
	this.element.css("top", pos.top + height-1);
	
	var thiz = this;
	this.element.slideDown(200, function() {
	});
	
	if (this.currentSourceElement) {
		
		var types = this.menuHandlers.keys();
		for (var i=0; i<types.length; i++) {
			var _type = types[i];
			this.currentSourceElement.removeClass(_type+"Pressed");
		}
		
		this.currentSourceElement.css("position", "static").css("z-index", "");
		
		//thiz.element.width( 150 );
		/*
		// thiz.element.width("auto");
		if (thiz.element.outerWidth() < 150) {
			thiz.element.width( 150 );
		} else {
			thiz.element.width("auto");
		}
		* */
	}
	
	sourceElement.addClass(type+"Pressed");
	sourceElement.css("position", "relative").css("z-index", "1000");
	this.currentSourceElement = sourceElement;
}

MenuManager.prototype.hideDropDown = function() {
	var thiz = this;
	
	var _el = this.currentSourceElement;
	
	this.hideTimeout = setTimeout(function() {
		thiz.element.hide();
		
		if (_el) {
			var types = thiz.menuHandlers.keys();
			for (var i=0; i<types.length; i++) {
				var _type = types[i];
				_el.removeClass(_type+"Pressed");
			}
		}
		
		clearTimeout(thiz.hideTimeout);
		thiz.hideTimeout = null;
	}, 200);
}

var menuManager = new MenuManager();
jQuery(function() {
	menuManager.init();
	
	addOnLoad(function() {
		menuManager.attach();	
	});
	
});



/*
 * SubscriptionType = { classId, identifier, name };
 */

var SubscribeManager = function() {
	this.el = null;
}

SubscribeManager.prototype.init = function() {
	var thiz = this;
	
	var el = jQuery("#subscriptionDialog");
	if (el.length > 0) {
		this.el = el;
		
		jQuery("#page1_phoneNr").keyup(function() {
			var phone = jQuery(this).val();
			var startsWithCountryCode = new RegExp("^\\+\\d").test( phone );
			thiz.showError(null);
			if (!startsWithCountryCode) {
				thiz.showError(".errorNoCountryCode");
			}
		});
		
		jQuery("#page1_nextBtn").click(function() {
			thiz.phone = jQuery("#page1_phoneNr").val();
			var startsWithCountryCode = new RegExp("^\\+\\d").test( thiz.phone );
			thiz.showError(null);
			if (!startsWithCountryCode) {
				thiz.showError(".errorNoCountryCode");
				return false;
			}
			
			var data = {
				test:		true, 
				address:	thiz.phone, 
				request:	"2 "+thiz.currentType.identifier,
				method:		"SMS"
				};
			
			CupMan.callService( "SubscribeService", {
				data: data, 
				success: function(obj){
					thiz.setPage(2);
				}, 
				error: function(root,msg) {
					thiz.showError(".errorBadNumber");
				}
			});
			
		});
		
		jQuery("#page2_nextBtn").click(function() {
			var code = jQuery("#page2_code").val();
			
			var data = {
				test:		false, 
				address:	thiz.phone, 
				request:	"2 "+thiz.currentType.identifier,
				method:		"SMS",
				code:		code
				};
				
			CupMan.callService( "SubscribeService", {
				data: data, 
				success: function(obj){
					var text = obj.message;
					el.find(".dialogPage3 p").html(text);
					thiz.setPage(3);
				}, 
				error: function(root,err) {
					thiz.showError(".errorBadCode");
				}
			});
			
		});
		
		jQuery("#page3_closeBtn").click(function() {
			jQuery.modal.close();
		});
	}
}

SubscribeManager.prototype.showError = function(which) {
	this.el.find(".error").hide();
	this.el.find(which).show();
}

SubscribeManager.prototype.setPage = function(pageNr) {
	this.el.find(".dialogPage").hide();
	this.el.find(".dialogPage"+pageNr).show();
}

SubscribeManager.prototype.popup = function(type) {
	var thiz = this;
	
	this.popdown();
	
	this.currentType = type;
	
	this.setPage(1);
	
	this.el.find("h1 span").html( type.name );
	window.scrollTo(0,0);
	this.el.modal({close:true, persist:true});
	
}

SubscribeManager.prototype.popdown = function() {
	jQuery.modal.close();
	this.currentType = null;
}

var subscribeManager = null;

jQuery(function() {
	subscribeManager = new SubscribeManager();
	
	addOnLoad(function() {
		subscribeManager.init();
	});
});


/* jTemplates 0.7.5 (http://jtemplates.tpython.com) Copyright (c) 2008 Tomasz Gloc */
eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('a(2Y.b&&!2Y.b.2Z){(9(){8 m=9(s,x,f){6.1I=[];6.1t={};6.2i=D;6.1J={};6.1a={};6.f=b.1j({1W:1d,30:1K,2j:1d,2k:1d,31:1K,32:1K},f);6.1u=(6.f.1u!==F)?(6.f.1u):(13.1X);6.Z=(6.f.Z!==F)?(6.f.Z):(13.33);6.34(s,x);a(s){6.1v(6.1a[\'1Y\'],x,6.f)}6.1a=D};m.y.2l=\'0.7.5\';m.N=1K;m.y.34=9(s,x){8 2m=/\\{#1w *(\\w*?)( .*)*\\}/g;8 1Z,1x,K;8 1y=D;8 2n=[];2o((1Z=2m.3F(s))!=D){1y=2m.1y;1x=1Z[1];K=s.2p(\'{#/1w \'+1x+\'}\',1y);a(K==-1){G j 14(\'15: m "\'+1x+\'" 2q 20 3G.\');}6.1a[1x]=s.2r(1y,K);2n[1x]=13.2s(1Z[2])}a(1y===D){6.1a[\'1Y\']=s;c}L(8 i 21 6.1a){a(i!=\'1Y\'){6.1J[i]=j m()}}L(8 i 21 6.1a){a(i!=\'1Y\'){6.1J[i].1v(6.1a[i],b.1j({},x||{},6.1J||{}),b.1j({},6.f,2n[i]));6.1a[i]=D}}};m.y.1v=9(s,x,f){a(s==F){6.1I.A(j 1e(\'\',1));c}s=s.V(/[\\n\\r]/g,\'\');s=s.V(/\\{\\*.*?\\*\\}/g,\'\');6.2i=b.1j({},6.1J||{},x||{});6.f=j 2t(f);8 q=6.1I;8 O=s.1f(/\\{#.*?\\}/g);8 16=0,K=0;8 e;8 1g=0;8 22=0;L(8 i=0,l=(O)?(O.W):(0);i<l;++i){a(1g){K=s.2p(\'{#/1z}\');a(K==-1){G j 14("15: 35 1L 36 1z.");}a(K>16){q.A(j 1e(s.2r(16,K),1))}16=K+11;1g=0;i=b.3H(\'{#/1z}\',O);2u}K=s.2p(O[i],16);a(K>16){q.A(j 1e(s.2r(16,K),1g))}8 3I=O[i].1f(/\\{#([\\w\\/]+).*?\\}/);8 2v=H.$1;37(2v){z\'3J\':++22;q.23();z\'a\':e=j 1A(O[i],q);q.A(e);q=e;R;z\'M\':q.23();R;z\'/a\':2o(22){q=q.24();--22}z\'/L\':z\'/25\':q=q.24();R;z\'25\':e=j 1k(O[i],q,6);q.A(e);q=e;R;z\'L\':e=26(O[i],q,6);q.A(e);q=e;R;z\'2w\':q.A(j 2x(O[i],6.2i));R;z\'h\':q.A(j 2y(O[i]));R;z\'2z\':q.A(j 2A(O[i]));R;z\'3K\':q.A(j 1e(\'{\',1));R;z\'3L\':q.A(j 1e(\'}\',1));R;z\'1z\':1g=1;R;z\'/1z\':a(m.N){G j 14("15: 35 2B 36 1z.");}R;38:a(m.N){G j 14(\'15: 3M 3N \'+2v+\'.\');}}16=K+O[i].W}a(s.W>16){q.A(j 1e(s.3O(16),1g))}};m.y.U=9(d,h,B,E){++E;8 $T=d,27,28;a(6.f.31){$T=6.1u(d,{29:(6.f.30&&E==1),1M:6.f.1W},6.Z)}a(!6.f.32){27=6.1t;28=h}M{27=6.1u(6.1t,{29:(6.f.2j),1M:1d},6.Z);28=6.1u(h,{29:(6.f.2j&&E==1),1M:1d},6.Z)}8 $P=b.1j({},27,28);8 $Q=B;$Q.2l=6.2l;8 17=\'\';L(8 i=0,l=6.1I.W;i<l;++i){17+=6.1I[i].U($T,$P,$Q,E)}--E;c 17};m.y.2C=9(1N,1l){6.1t[1N]=1l};13=9(){};13.33=9(3a){c 3a.V(/&/g,\'&3P;\').V(/>/g,\'&3b;\').V(/</g,\'&3c;\').V(/"/g,\'&3Q;\').V(/\'/g,\'&#39;\')};13.1X=9(d,1B,Z){a(d==D){c d}37(d.2D){z 2t:8 o={};L(8 i 21 d){o[i]=13.1X(d[i],1B,Z)}a(!1B.1M){a(d.3R("2E"))o.2E=d.2E}c o;z 3S:8 o=[];L(8 i=0,l=d.W;i<l;++i){o[i]=13.1X(d[i],1B,Z)}c o;z 2F:c(1B.29)?(Z(d)):(d);z 3T:a(1B.1M){a(m.N)G j 14("15: 3U 3V 20 3W.");M c F}38:c d}};13.2s=9(2a){a(2a===D||2a===F){c{}}8 o=2a.3X(/[= ]/);a(o[0]===\'\'){o.3Y()}8 2G={};L(8 i=0,l=o.W;i<l;i+=2){2G[o[i]]=o[i+1]}c 2G};8 1e=9(2H,1g){6.2b=2H;6.3d=1g};1e.y.U=9(d,h,B,E){8 t=6.2b;a(!6.3d){8 $T=d;8 $P=h;8 $Q=B;t=t.V(/\\{(.*?)\\}/g,9(3Z,3e){1O{8 1b=10(3e);a(1C 1b==\'9\'){8 f=b.I(B,\'1m\').f;a(f.1W||!f.2k){c\'\'}M{1b=1b($T,$P,$Q)}}c(1b===F)?(""):(2F(1b))}1P(e){a(m.N)G e;c""}})}c t};8 1A=9(J,1D){6.2c=1D;J.1f(/\\{#(?:M)*a (.*?)\\}/);6.3f=H.$1;6.1n=[];6.1o=[];6.1E=6.1n};1A.y.A=9(e){6.1E.A(e)};1A.y.24=9(){c 6.2c};1A.y.23=9(){6.1E=6.1o};1A.y.U=9(d,h,B,E){8 $T=d;8 $P=h;8 $Q=B;8 17=\'\';1O{8 2I=(10(6.3f))?(6.1n):(6.1o);L(8 i=0,l=2I.W;i<l;++i){17+=2I[i].U(d,h,B,E)}}1P(e){a(m.N)G e;}c 17};26=9(J,1D,1w){a(J.1f(/\\{#L (\\w+?) *= *(\\S+?) +40 +(\\S+?) *(?:12=(\\S+?))*\\}/)){J=\'{#25 26.3g 3h \'+H.$1+\' 2B=\'+(H.$2||0)+\' 1L=\'+(H.$3||-1)+\' 12=\'+(H.$4||1)+\' 1Q=$T}\';c j 1k(J,1D,1w)}M{G j 14(\'15: 41 42 "3i": \'+J);}};26.3g=9(i){c i};8 1k=9(J,1D,1w){6.2c=1D;6.1p=1w;J.1f(/\\{#25 (.+?) 3h (\\w+?)( .+)*\\}/);6.3j=H.$1;6.u=H.$2;6.X=H.$3||D;6.X=13.2s(6.X);6.1n=[];6.1o=[];6.1E=6.1n};1k.y.A=9(e){6.1E.A(e)};1k.y.24=9(){c 6.2c};1k.y.23=9(){6.1E=6.1o};1k.y.U=9(d,h,B,E){1O{8 $T=d;8 $P=h;8 $Q=B;8 1q=10(6.3j);8 1R=[];8 1F=1C 1q;a(1F==\'3k\'){8 2J=[];b.1c(1q,9(k,v){1R.A(k);2J.A(v)});1q=2J}8 1Q=(6.X.1Q!==F)?(10(6.X.1Q)):{};8 s=1S(10(6.X.2B)||0),e;8 12=1S(10(6.X.12)||1);a(1F!=\'9\'){e=1q.W}M{a(6.X.1L===F||6.X.1L===D){e=1S.43}M{e=1S(10(6.X.1L))+((12>0)?(1):(-1))}}8 17=\'\';8 i,l;a(6.X.1T){8 1b=s+1S(10(6.X.1T));e=(1b>e)?(e):(1b)}a((e>s&&12>0)||(e<s&&12<0)){8 1G=0;8 3l=(1F!=\'9\')?(44.45((e-s)/12)):F;8 1r,1h;L(;((12>0)?(s<e):(s>e));s+=12,++1G){1r=1R[s];a(1F!=\'9\'){1h=1q[s]}M{1h=1q(s);a(1h===F||1h===D){R}}a((1C 1h==\'9\')&&(6.1p.f.1W||!6.1p.f.2k)){2u}a((1F==\'3k\')&&(1r 21 2t)){2u}$T=1Q;8 p=$T[6.u]=1h;$T[6.u+\'$3m\']=s;$T[6.u+\'$1G\']=1G;$T[6.u+\'$3n\']=(1G==0);$T[6.u+\'$3o\']=(s+12>=e);$T[6.u+\'$3p\']=3l;$T[6.u+\'$1R\']=(1r!==F&&1r.2D==2F)?(6.1p.Z(1r)):(1r);$T[6.u+\'$1C\']=1C 1h;L(i=0,l=6.1n.W;i<l;++i){17+=6.1n[i].U($T,h,B,E)}1i $T[6.u+\'$3m\'];1i $T[6.u+\'$1G\'];1i $T[6.u+\'$3n\'];1i $T[6.u+\'$3o\'];1i $T[6.u+\'$3p\'];1i $T[6.u+\'$1R\'];1i $T[6.u+\'$1C\'];1i $T[6.u]}}M{L(i=0,l=6.1o.W;i<l;++i){17+=6.1o[i].U($T,h,B,E)}}c 17}1P(e){a(m.N)G e;c""}};8 2x=9(J,x){J.1f(/\\{#2w (.*?)(?: 46=(.*?))?\\}/);6.1p=x[H.$1];a(6.1p==F){a(m.N)G j 14(\'15: 47 3i 2w: \'+H.$1);}6.3q=H.$2};2x.y.U=9(d,h,B,E){8 $T=d;1O{c 6.1p.U(10(6.3q),h,B,E)}1P(e){a(m.N)G e;}};8 2y=9(J){J.1f(/\\{#h 1N=(\\w*?) 1l=(.*?)\\}/);6.u=H.$1;6.2b=H.$2};2y.y.U=9(d,h,B,E){8 $T=d;8 $P=h;8 $Q=B;1O{h[6.u]=10(6.2b)}1P(e){a(m.N)G e;h[6.u]=F}c\'\'};8 2A=9(J){J.1f(/\\{#2z 48=(.*?)\\}/);6.2K=10(H.$1);6.2L=6.2K.W;a(6.2L<=0){G j 14(\'15: 2z 49 4a 4b\');}6.2M=0;6.2N=-1};2A.y.U=9(d,h,B,E){8 2O=b.I(B,\'1U\');a(2O!=6.2N){6.2N=2O;6.2M=0}8 i=6.2M++%6.2L;c 6.2K[i]};b.18.1v=9(s,x,f){a(s.2D===m){c b(6).1c(9(){b.I(6,\'1m\',s);b.I(6,\'1U\',0)})}M{c b(6).1c(9(){b.I(6,\'1m\',j m(s,x,f));b.I(6,\'1U\',0)})}};b.18.4c=9(1H,x,f){8 s=b.2P({1s:1H,1V:1d}).3r;c b(6).1v(s,x,f)};b.18.4d=9(2Q,x,f){8 s=jQuery(\'#\'+2Q).2H();a(s==D){s=jQuery(\'#\'+2Q).3s();s=s.V(/&3c;/g,"<").V(/&3b;/g,">")}s=b.4e(s);s=s.V(/^<\\!\\[4f\\[([\\s\\S]*)\\]\\]>$/3t,\'$1\');s=s.V(/^<\\!--([\\s\\S]*)-->$/3t,\'$1\');c b(6).1v(s,x,f)};b.18.4g=9(){8 1T=0;b(6).1c(9(){a(b.I(6,\'1m\')){++1T}});c 1T};b.18.4h=9(){b(6).3u();c b(6).1c(9(){b.3v(6,\'1m\')})};b.18.2C=9(1N,1l){c b(6).1c(9(){8 t=b.I(6,\'1m\');a(t===F){a(m.N)G j 14(\'15: m 2q 20 3w.\');M c}t.2C(1N,1l)})};b.18.2R=9(d,h){c b(6).1c(9(){8 t=b.I(6,\'1m\');a(t===F){a(m.N)G j 14(\'15: m 2q 20 3w.\');M c}b.I(6,\'1U\',b.I(6,\'1U\')+1);b(6).3s(t.U(d,h,6,0))})};b.18.4i=9(1H,h,C){8 Y=6;C=b.1j({2S:\'4j\',1V:1K,2T:1d},C);b.2P({1s:1H,2S:C.2S,I:C.I,3x:C.3x,1V:C.1V,2T:C.2T,3y:C.3y,4k:\'4l\',4m:9(d){8 r=b(Y).2R(d,h);a(C.2d){C.2d(r)}},4n:C.4o,4p:C.4q});c 6};8 2e=9(1s,h,2f,2g,19,C){6.3z=1s;6.1t=h;6.3A=2f;6.3B=2g;6.19=19;6.3C=D;6.2U=C||{};8 Y=6;b(19).1c(9(){b.I(6,\'2V\',Y)});6.2W()};2e.y.2W=9(){6.3D();a(6.19.W==0){c}8 Y=6;b.4r(6.3z,6.3B,9(d){8 r=b(Y.19).2R(d,Y.1t);a(Y.2U.2d){Y.2U.2d(r)}});6.3C=4s(9(){Y.2W()},6.3A)};2e.y.3D=9(){6.19=b.3E(6.19,9(o){a(b.4t.4u){8 n=o.2X;2o(n&&n!=4v){n=n.2X}c n!=D}M{c o.2X!=D}})};b.18.4w=9(1s,h,2f,2g,C){c j 2e(1s,h,2f,2g,6,C)};b.18.3u=9(){c b(6).1c(9(){8 2h=b.I(6,\'2V\');a(2h==D){c}8 Y=6;2h.19=b.3E(2h.19,9(o){c o!=Y});b.3v(6,\'2V\')})};b.1j({2Z:9(s,x,f){c j m(s,x,f)},4x:9(1H,x,f){8 s=b.2P({1s:1H,1V:1d}).3r;c j m(s,x,f)},4y:9(1l){m.N=1l}})})(b)}',62,283,'||||||this||var|function|if|jQuery|return|||settings||param||new|||Template||||node||||_name|||includes|prototype|case|push|element|options|null|deep|undefined|throw|RegExp|data|oper|se|for|else|DEBUG_MODE|op|||break|||get|replace|length|_option|that|f_escapeString|eval||step|TemplateUtils|Error|jTemplates|ss|ret|fn|objs|_templates_code|tmp|each|false|TextNode|match|literalMode|cval|delete|extend|opFOREACH|value|jTemplate|_onTrue|_onFalse|_template|fcount|ckey|url|_param|f_cloneData|setTemplate|template|tname|lastIndex|literal|opIF|filter|typeof|par|_currentState|mode|iteration|url_|_tree|_templates|true|end|noFunc|name|try|catch|extData|key|Number|count|jTemplateSID|async|disallow_functions|cloneData|MAIN|iter|not|in|elseif_level|switchToElse|getParent|foreach|opFORFactory|_param1|_param2|escapeData|optionText|_value|_parent|on_success|Updater|interval|args|updater|_includes|filter_params|runnable_functions|version|reg|_template_settings|while|indexOf|is|substring|optionToObject|Object|continue|op_|include|Include|UserParam|cycle|Cycle|begin|setParam|constructor|toString|String|obj|val|tab|arr|_values|_length|_index|_lastSessionID|sid|ajax|elementName|processTemplate|type|cache|_options|jTemplateUpdater|run|parentNode|window|createTemplate|filter_data|clone_data|clone_params|escapeHTML|splitTemplates|No|of|switch|default||txt|gt|lt|_literalMode|__a1|_cond|funcIterator|as|find|_arg|object|_total|index|first|last|total|_root|responseText|html|im|processTemplateStop|removeData|defined|dataFilter|timeout|_url|_interval|_args|timer|detectDeletedNodes|grep|exec|closed|inArray|ppp|elseif|ldelim|rdelim|unknown|tag|substr|amp|quot|hasOwnProperty|Array|Function|Functions|are|allowed|split|shift|__a0|to|Operator|failed|MAX_VALUE|Math|ceil|root|Cannot|values|has|no|elements|setTemplateURL|setTemplateElement|trim|CDATA|hasTemplate|removeTemplate|processTemplateURL|GET|dataType|json|success|error|on_error|complete|on_complete|getJSON|setTimeout|browser|msie|document|processTemplateStart|createTemplateURL|jTemplatesDebugMode'.split('|'),0,{}));

// version 1.4.0
// http://welcome.totheinter.net/columnizer-jquery-plugin/
// created by: Adam Wulf adam.wulf@gmail.com

(function($){
 
 $.fn.columnize = function(options) {

	var defaults = {
		// default width of columnx
		width: 400,
		// optional # of columns instead of width
		columns : false,
		// true to build columns once regardless of window resize
		// false to rebuild when content box changes bounds
		buildOnce : false,
		// an object with options if the text should overflow
		// it's container if it can't fit within a specified height
		overflow : false,
		// this function is called after content is columnized
		doneFunc : function(){},
		// if the content should be columnized into a 
		// container node other than it's own node
		target : false,
		// re-columnizing when images reload might make things
		// run slow. so flip this to true if it's causing delays
		ignoreImageLoading : true,
		// should columns float left or right
		float : "left",
		// ensure the last column is never the tallest column
		lastNeverTallest : false
	};
	var options = $.extend(defaults, options);

    return this.each(function() {
	    var $inBox = options.target ? $(options.target) : $(this);
		var maxHeight = $(this).height();
		var $cache = $('<div></div>'); // this is where we'll put the real content
		var lastWidth = 0;
		var columnizing = false;
		$cache.append($(this).children(".visible").clone(true));
	    
	    // images loading after dom load
	    // can screw up the column heights,
	    // so recolumnize after images load
	    if(!options.ignoreImageLoading && !options.target){
	    	if(!$inBox.data("imageLoaded")){
		    	$inBox.data("imageLoaded", true);
		    	if($(this).find("img").length > 0){
		    		// only bother if there are
		    		// actually images...
			    	var func = function($inBox,$cache){ return function(){
				    	if(!$inBox.data("firstImageLoaded")){
				    		$inBox.data("firstImageLoaded", "true");
					    	$inBox.empty().append($cache.children().clone(true));
					    	$inBox.columnize(options);
				    	}
			    	}}($(this), $cache);
				    $(this).find("img").one("load", func);
				    $(this).find("img").one("abort", func);
				    return;
		    	}
	    	}
	    }
	    
		$inBox.empty();
		
		columnizeIt();
		
		if(!options.buildOnce){
			$(window).resize(function() {
				if(!options.buildOnce && $.browser.msie){
					if($inBox.data("timeout")){
						clearTimeout($inBox.data("timeout"));
					}
					$inBox.data("timeout", setTimeout(columnizeIt, 200));
				}else if(!options.buildOnce){
					columnizeIt();
				}else{
					// don't rebuild
				}
			});
		}
		
		/**
		 * return a node that has a height
		 * less than or equal to height
		 *
		 * @param putInHere, a dom element
		 * @$pullOutHere, a jQuery element
		 */
		function columnize($putInHere, $pullOutHere, $parentColumn, height){
			while($parentColumn.height() < height &&
				  $pullOutHere[0].childNodes.length){
				$putInHere.append($pullOutHere[0].childNodes[0]);
			}
			
			if($putInHere[0].childNodes.length == 0) return;
            
			
			// now we're too tall, undo the last one
			var kids = $putInHere[0].childNodes;
			var lastKid = kids[kids.length-1];
			$putInHere[0].removeChild(lastKid);
			var $item = $(lastKid);
			
			
			if($item[0].nodeType == 3){
				// it's a text node, split it up
				var oText = $item[0].nodeValue;
				var counter2 = options.width / 18;
				if(options.accuracy)
				counter2 = options.accuracy;
				var columnText;
				var latestTextNode = null;
				while($parentColumn.height() < height && oText.length){
					if (oText.indexOf(' ', counter2) != '-1') {
						columnText = oText.substring(0, oText.indexOf(' ', counter2));
					} else {
						columnText = oText;
					}
					latestTextNode = document.createTextNode(columnText);
					$putInHere.append(latestTextNode);
					
					if(oText.length > counter2){
						oText = oText.substring(oText.indexOf(' ', counter2));
					}else{
						oText = "";
					}
				}
				if($parentColumn.height() >= height && latestTextNode != null){
					// too tall :(
					$putInHere[0].removeChild(latestTextNode);
					oText = latestTextNode.nodeValue + oText;
				}
				if(oText.length){
					$item[0].nodeValue = oText;
				}else{
					return false; // we ate the whole text node, move on to the next node
				}
			}
			
			if($pullOutHere.children().length){
				$pullOutHere.prepend($item);
			}else{
				$pullOutHere.append($item);
			}
			
			return $item[0].nodeType == 3;
		}
		
		function split($putInHere, $pullOutHere, $parentColumn, height){
			if($pullOutHere.children().length){
				$cloneMe = $pullOutHere.children(":first");
				$clone = $cloneMe.clone(true);
				if($clone.attr("nodeType") == 1 && !$clone.hasClass("dontend")){ 
					$putInHere.append($clone);
					if($clone.is("img") && $parentColumn.height() < height + 20){
						$cloneMe.remove();
					}else if(!$cloneMe.hasClass("dontsplit") && $parentColumn.height() < height + 20){
						$cloneMe.remove();
					}else if($clone.is("img") || $cloneMe.hasClass("dontsplit")){
						$clone.remove();
					}else{
						$clone.empty();
						if(!columnize($clone, $cloneMe, $parentColumn, height)){
							if($cloneMe.children().length){
								split($clone, $cloneMe, $parentColumn, height);
							}
						}
						if($clone.get(0).childNodes.length == 0){
							// it was split, but nothing is in it :(
							$clone.remove();
						}
					}
				}
			}
		}
		
		
		function singleColumnizeIt() {
			if ($inBox.data("columnized") && $inBox.children().length == 1) {
				return;
			}
			$inBox.data("columnized", true);
			$inBox.data("columnizing", true);
			
			$inBox.empty();
			$inBox.append($("<div class='first last column' style='width:98%; padding: 3px; float: " + options.float + ";'></div>")); //"
			$col = $inBox.children().eq($inBox.children().length-1);
			$destroyable = $cache.clone(true);
			if(options.overflow){
				targetHeight = options.overflow.height;
				columnize($col, $destroyable, $col, targetHeight);
				// make sure that the last item in the column isn't a "dontend"
				if(!$destroyable.children().find(":first-child").hasClass("dontend")){
					split($col, $destroyable, $col, targetHeight);
				}
				
				while(checkDontEndColumn($col.children(":last").length && $col.children(":last").get(0))){
					var $lastKid = $col.children(":last");
					$lastKid.remove();
					$destroyable.prepend($lastKid);
				}

				var html = "";
				var div = document.createElement('DIV');
				while($destroyable[0].childNodes.length > 0){
					var kid = $destroyable[0].childNodes[0];
					for(var i=0;i<kid.attributes.length;i++){
						if(kid.attributes[i].nodeName.indexOf("jQuery") == 0){
							kid.removeAttribute(kid.attributes[i].nodeName);
						}
					}
					div.innerHTML = "";
					div.appendChild($destroyable[0].childNodes[0]);
					html += div.innerHTML;
				}
				var overflow = $(options.overflow.id)[0];
				overflow.innerHTML = html;

			}else{
				$col.append($destroyable);
			}
			$inBox.data("columnizing", false);
			
			if(options.overflow){
				options.overflow.doneFunc();
			}
			
		}
		
		function checkDontEndColumn(dom){
			if(dom.nodeType != 1) return false;
			if($(dom).hasClass("dontend")) return true;
			if(dom.childNodes.length == 0) return false;
			return checkDontEndColumn(dom.childNodes[dom.childNodes.length-1]);
		}
		
		function columnizeIt() {
			if(lastWidth == $inBox.width()) return;
			lastWidth = $inBox.width();
			
			var numCols = Math.round($inBox.width() / options.width);
			if(options.columns) numCols = options.columns;
//			if ($inBox.data("columnized") && numCols == $inBox.children().length) {
//				return;
//			}
			if(numCols <= 1){
				return singleColumnizeIt();
			}
			if($inBox.data("columnizing")) return;
			$inBox.data("columnized", true);
			$inBox.data("columnizing", true);
			
			$inBox.empty();
			$inBox.append($("<div style='width:" + (Math.round(100 / numCols) - 2)+ "%; padding: 3px; float: " + options.float + ";'></div>")); //"
			$col = $inBox.children(":last");
			$col.append($cache.clone());
			maxHeight = $col.height();
			$inBox.empty();
			
			var targetHeight = maxHeight / numCols;
			var firstTime = true;
			var maxLoops = 3;
			var scrollHorizontally = false;
			if(options.overflow){
				maxLoops = 1;
				targetHeight = options.overflow.height;
			}else if(options.height && options.width){
				maxLoops = 1;
				targetHeight = options.height;
				scrollHorizontally = true;
			}
			
			for(var loopCount=0;loopCount<maxLoops;loopCount++){
				$inBox.empty();
				var $destroyable;
				try{
					$destroyable = $cache.clone(true);
				}catch(e){
					// jquery in ie6 can't clone with true
					$destroyable = $cache.clone();
				}
				$destroyable.css("visibility", "hidden");
				// create the columns
				for (var i = 0; i < numCols; i++) {
					/* create column */
					var className = (i == 0) ? "first column" : "column";
					var className = (i == numCols - 1) ? ("last " + className) : className;
					$inBox.append($("<div class='" + className + "' style='width:" + (Math.round(100 / numCols) - 2)+ "%; float: " + options.float + ";'></div>")); //"
				}
				
				// fill all but the last column (unless overflowing)
				var i = 0;
				while(i < numCols - (options.overflow ? 0 : 1) || scrollHorizontally && $destroyable.children().length){
					if($inBox.children().length <= i){
						// we ran out of columns, make another
						$inBox.append($("<div class='" + className + "' style='width:" + (Math.round(100 / numCols) - 2)+ "%; float: " + options.float + ";'></div>")); //"
					}
					var $col = $inBox.children().eq(i);
					columnize($col, $destroyable, $col, targetHeight);
					// make sure that the last item in the column isn't a "dontend"
					if(!$destroyable.children().find(":first-child").hasClass("dontend")){
						split($col, $destroyable, $col, targetHeight);
					}else{
//						alert("not splitting a dontend");
					}
					
					while(checkDontEndColumn($col.children(":last").length && $col.children(":last").get(0))){
						var $lastKid = $col.children(":last");
						$lastKid.remove();
						$destroyable.prepend($lastKid);
					}
					i++;
				}
				if(options.overflow && !scrollHorizontally){
					var IE6 = false /*@cc_on || @_jscript_version < 5.7 @*/;
					var IE7 = (document.all) && (navigator.appVersion.indexOf("MSIE 7.") != -1);
					if(IE6 || IE7){
						var html = "";
						var div = document.createElement('DIV');
						while($destroyable[0].childNodes.length > 0){
							var kid = $destroyable[0].childNodes[0];
							for(var i=0;i<kid.attributes.length;i++){
								if(kid.attributes[i].nodeName.indexOf("jQuery") == 0){
									kid.removeAttribute(kid.attributes[i].nodeName);
								}
							}
							div.innerHTML = "";
							div.appendChild($destroyable[0].childNodes[0]);
							html += div.innerHTML;
						}
						var overflow = $(options.overflow.id)[0];
						overflow.innerHTML = html;
					}else{
						$(options.overflow.id).empty().append($destroyable.children().clone(true));
					}
				}else if(!scrollHorizontally){
					// the last column in the series
					$col = $inBox.children().eq($inBox.children().length-1);
					while($destroyable.children().length) $col.append($destroyable.children(":first"));
					
					
					var afterH = $col.height();
					var diff = afterH - targetHeight;
					var totalH = 0;
					var min = 10000000;
					var max = 0;
					var lastIsMax = false;
					$inBox.children().each(function($inBox){ return function($item){
						var h = $inBox.children().eq($item).height();
						lastIsMax = false;
						totalH += h;
						if(h > max) {
							max = h;
							lastIsMax = true;
						}
						if(h < min) min = h;
					}}($inBox));

					var avgH = totalH / numCols;
					if(options.lastNeverTallest && lastIsMax){
						// the last column is the tallest
						// so allow columns to be taller
						// and retry
						targetHeight = targetHeight + 30;
						if(loopCount == maxLoops-1) maxLoops++;
					}else if(max - min > 30){
						// too much variation, try again
						targetHeight = avgH + 30;
					}else if(Math.abs(avgH-targetHeight) > 20){
						// too much variation, try again
						targetHeight = avgH;
					}else {
						// solid, we're done
						loopCount = maxLoops;
					}
				}else{
					// it's scrolling horizontally, fix the width/classes of the columns
					$inBox.children().each(function(i){
						$col = $inBox.children().eq(i);
						$col.width(options.width + "px");
						if(i==0){
							$col.addClass("first");
						}else if(i==$inBox.children().length-1){
							$col.addClass("last");
							
							
                    
						}else{
							$col.removeClass("first");
							$col.removeClass("last");
						}
					});
					$inBox.width($inBox.children().length * options.width + "px");
				}
				$inBox.append($("<br style='clear:both;'>"));
			}
			$inBox.find('.column').find(':first.removeiffirst').remove();
			$inBox.find('.column').find(':last.removeiflast').remove();
			$inBox.data("columnizing", false);
            
           
			if(options.overflow){
				options.overflow.doneFunc();
			}
			options.doneFunc();
		}
    });
 };
})(jQuery);