/**
 *	Definition of Map component
 *	(see example of implementation below)
 *
 *	NOTE: this does not support JAGGED area mapping (only squared dimensions)
 */

// namespace for Map component & declaration of a constant variable (for a standard unit of mearurement)
Map = new Object();

Map.UNIT = 'px';
Map.USE_TOOLTIP = true;

// the div that contains all areas
Map.Container = function(coord, size) {
	this.DOM_MapObject = document.createElement('div');	
	this.components = new Array();	
	this.coordinates = coord ? coord : { 'x':0, 'y':0 };
	this.size = size ? size : { 'width':0, 'height':0 };
	this.paint();
};

// sets the initial style rules the containing <img> (Map.Container instance)
Map.Container.prototype.paint = function() {	
	with(this.DOM_MapObject.style) {
		width				= this.size['width'] + Map.UNIT;
		height			= this.size['height'] + Map.UNIT;
		marginLeft	= this.coordinates['x'] + Map.UNIT;
		marginTop		= this.coordinates['y'] + Map.UNIT;
		background	= 'transparent';
		position		=	'absolute';
		//zIndex			=	'10000';
	}	
};

// adds an area to the map and returns a reference to the area
// 'src' is the image (this component looks for the src file PLUS '_o' at the end of the file when you rollover the area)
// 'coord' is a hash (like {'x':0,'y':0} ) we will use for the margin-left and margin-top
// 'size' is a hash containging 'width' and 'height' which we use for the area's width and height
// 'isStatic' is a boolean indicating whether the area is interactive or not (for example, central park graphic is not interactive)
Map.Container.prototype.addComponent = function(src, coord, size, isStatic) {
	this.components.push(
		(area = new Map.Component(src, coord, size,
			isStatic ? isStatic : false,
			this.components.length
		))
	); return area;
};

// use this function to append the main map <img> to some HTML object (or just document.body)
// takes an html object as a parameter, so use sometihng like document.getElementById(...), document.body, etc.
Map.Container.prototype.attachTo = function(DOM_ParentObject) {
	if(this.DOM_MapObject && DOM_ParentObject)
		DOM_ParentObject.appendChild(this.DOM_MapObject);
};

// call this method on a Map instance to load the style rules (coordinates, dimensions, etc) for each area (or Map.Component) within the main Map object
Map.Container.prototype.setLayout = function() {
	if(this.components.length == 0 || !this.DOM_MapObject) return;
	for(var i = 0; i < (components = this.components).length; i++) {
		var component = components[i];
		components[i].DOM_AreaObject.src = component.source;
		style = components[i].DOM_AreaObject.style;
		style.cursor			=	components[i].DOM_AreaObject.isStatic ? 'default' : 'pointer';
		style.position		=	'absolute';
		//style.background	= "url('" + component.source + "') no-repeat";
		style.width				= component.size['width'] + Map.UNIT;
		style.height			= component.size['height'] + Map.UNIT;
		style.marginLeft	= component.coordinates['x'] + Map.UNIT;
		style.marginTop		= component.coordinates['y'] + Map.UNIT;
		this.DOM_MapObject.appendChild(component.DOM_AreaObject);
	}
};

// this is for each area of the Map; creations of this object are done implicitly in the Map.addComponent() function
Map.Component = function(src, coord, size, isStatic, id) {
	this.id = id;
	this.source	= src	? src	:	null;
	this.coordinates = coord ? coord : { 'x':0, 'y':0 };
	this.size = size ? size : { 'width':0, 'height':0 };	
	this.DOM_AreaObject = document.createElement("img");
	//this.DOM_AreaObject = document.createElement("div");
	this.DOM_AreaObject.clicked = false;
	this.DOM_AreaObject.isStatic = isStatic;
	this.DOM_AreaObject.tooltip = null;
	this.DOM_AreaObject.text = "";
	this.DOM_AreaObject.areas = [];
	this.DOM_AreaObject.id = 'map-area_' + this.id;
	if(!isStatic) {
		this.DOM_AreaObject.onmouseover = Map.Component.onmouseover;
		this.DOM_AreaObject.onmouseout = Map.Component.onmouseout;
		this.DOM_AreaObject.onclick = Map.Component.onmouseclick;
	}
};

// attach area IDs and alt text to the area <img>
Map.Component.prototype.setAreas = function(areasList) {
	this.DOM_AreaObject.areas = areasList[0]; // areasList[0]: array containing the cat IDs
	if(areasList[1]) this.DOM_AreaObject.text = areasList[1]; // areasList[0]: string containing the alt text (optional)
};																							

// these are the default actions for rolling on and off the map areas (or a Map.Component - same thing)

/**
 * ROLL-OVER AND CLICK CONVENTIONS
 *
 * 1) the main image is set as a parameter to the Map.Component constructor (say, for example, 'x.gif')
 * 2) the convention is that for rollovers, the script will change the src from 'x.gif' to 'x_o.gif'
 *		- so you need an 'x.gif' and an 'x_o.gif'
 * 3) for click behavior, the script will change the src from 'x_o.gif' to 'x_c.gif'
 *		- so all together you need 3 images for one Map.Component (or "map area"):
 *			|- 'x.gif'
 *			|- 'x_o.gif'
 *			|- 'x_c.gif'
 *
 *	NOTE: you only need one .gif image for STATIC Map components (ie, central park), as there are no
 *				rollover and click behaviors for static areas
 */
 
Map.Component.onmouseover = function() {
	if(this.clicked) return;
	this.src = this.src.replace(/.gif/, "_o.gif");
	//this.style.background = this.style.background.replace(/.gif/, "_o.gif");
	Map.Component.showMapTooltip.call(this);
};

Map.Component.onmouseout = function(e) {
	if(this.clicked) return;
	this.src = this.src.replace(/_o.gif/, ".gif");
	//this.style.background = this.style.background.replace(/_o.gif/, ".gif");
	if(this.tooltip) Map.Component.hideMapTooltip.call(this);
};

Map.Component.onmouseclick = function() {
	this.clicked = !this.clicked;
	if(this.clicked) this.src = this.src.replace(/_o.gif/, "_c.gif");
	else this.src = this.src.replace(/_c.gif/, "_o.gif");
	if(Map.Component.onclick)	Map.Component.onclick.call(this);
	if(this.tooltip) Map.Component.hideMapTooltip.call(this);	
	else Map.Component.showMapTooltip.call(this);	
};

// DON'T DELETE THIS LINE! we fill in which function to use in the implementation code later
Map.Component.onclick = null;

// use this to debug an Map area's properties
Map.Component.prototype.toString = function() {
	return (
		"\t\n" +
		this.DOM_AreaObject.id + "\t" +
		this.source + "\t\t" + 
		this.size['width'] + Map.UNIT + " X " +
		this.size['height'] + Map.UNIT + "\t" +
		"(" + this.coordinates['x'] + ", " +
		this.coordinates['y'] + ")"
	);
};

Map.Component.showMapTooltip = function() {
	
	if(!this.text || !Map.USE_TOOLTIP) return;
	
	var parent = this.parentNode;
	var tooltip = (this.tooltip = document.createElement("span"));
	
	// 'text' is set in the 'Map.Component.setAreas' constructor (the object 'this' is pointing to)
	tooltip.innerHTML = this.text;
	
	// set styles and position
	with(tooltip.style) {
		position = 'absolute';
		/* findPos() (in global.js) is a cool function i found; scans the x and y offsets of all the DOM parent nodes of the specified object and aggregates all the offsets until its reaches the body and the aggregated coordinates are the actual x and y pixels of the object you're looking for on the canvas */
		left = (
			(findPos(this))[0]
			- (findPos(parent))[0]
			+ (this.width * .7)
		) + "px";
		top = (
			(findPos(this))[1]
			- (findPos(parent))[1]
			+ (this.height * .85)
		) + "px";
		width = "160px";
		fontSize = "11px";
		display = "block";
		backgroundColor = "#FFFFF1";
		border = "solid 1px #e5e5e5";
		padding = "5px";
	}
	
	parent.appendChild(tooltip);
	
	// use Animation if its included globally
	if(typeof Animation == "function") {
		tooltip.style.visibility = "hidden";
		(new Animation(tooltip)).fadeElementOpacity(1, 100, 30);
	}
	
}

Map.Component.hideMapTooltip = function() {
	this.parentNode.removeChild(this.tooltip);
	this.tooltip = null;
}

// if findPos() is not included from global.js, include it here as it is a necessary function for this script
if(typeof findPos != "function") {
	function findPos(obj) {
		var curleft = curtop = 0;
		if (obj.offsetParent) {
			do {
				curleft += obj.offsetLeft;
				curtop += obj.offsetTop;
			} while (obj = obj.offsetParent);
		} return [curleft,curtop];
	}
}

/**
 *	Example implementation of Map component
 */

/*

// hard-coded, comma-seperated lists of cat IDs (and ALT text describing them) sorted by regional areas
// and one hash object just holding it all; this could be implemented any way, but you need to pass at least
// a one dimensional array of cat IDs to every component's 'setAreas()' method (2 dimensions if you want ALT text)
var areas = {
	'up'		: [[24], "Upper Manhattan (Harlem)"],
	'uws'		: [[14], "Upper West Side"],
	'ues'		: [[7], "Upper East Side"],
	'mid'		:	[[11,12,13,20,4,6,8,9], "Midtown (West Village, Chelsea, Union Square, Gramercy Park, Murray Hill, East Village)"],
	'down'	:	[[1,2,25,21,16,22], "Downtown (TriBeCa, SoHo, Battery Park, Stuyvesant Town, Financial District, Lower East Side)"]
};

// make new Map with specified margins and dimensions
var map = new Map.Container({ 'x':800, 'y':-20 }, { 'width':114, 'height':420 });
 
// add areas to the Map using specified images, margins, dimensions
// ALSO, addComponent() returns a reference to the newly added Area, so we can also call setAreas() on the 'area'
// and pass an array of cat IDs that are meant to be related to each area <img>
(map.addComponent('images/visuals/map/up.gif', { 'x':0, 'y':0 }, { 'width':107, 'height':143 })).setAreas(areas.up);
(map.addComponent('images/visuals/map/uws.gif', { 'x':0, 'y':144 }, { 'width':26, 'height':89 })).setAreas(areas.uws);
(map.addComponent('images/visuals/map/cp.gif', { 'x':27, 'y':144 }, { 'width':35, 'height':89 }, true));
(map.addComponent('images/visuals/map/ues.gif', { 'x':63, 'y':144 }, { 'width':53, 'height':89 })).setAreas(areas.ues);
(map.addComponent('images/visuals/map/mid.gif', { 'x':0, 'y':233 }, { 'width':107, 'height':54 })).setAreas(areas.mid);
(map.addComponent('images/visuals/map/down.gif', { 'x':0, 'y':288 }, { 'width':134, 'height':134 })).setAreas(areas.down);

// tell what function to use when clicking an area <img> (this JS function is usually defined in the controller file)
// basically, assign a pointer (function name; w/o parenthesis) to the function you want to use for Map.Component.onclick
// its a good idea to not directly define the function here because we can have different 'area_onClick' functions defined
// in the controller files for different pages (such as home.cfm or search.cfm), so put the function name here,
// but have it defined in an earlier include file
Map.Component.onclick = area_onClick;

// apply all style rules for the areas within the Map
map.setLayout();

// attach the entire containing Map object to some HTML element (like 'inner')
map.attachTo(document.getElementById('inner'));

*/