/*
============================================================
File: searchtool.js
Description: Javascript utilities for town selection control
History:
	2/1/2006: created
============================================================
*/

var oLeft, oRight, oState;
var isIE = navigator.appName=="Microsoft Internet Explorer"?true:false;
var oAllCities = new Array();
var globalState;
var gOrphans;
var searchMode = 0;	// 0:one list, don't retain selections
					// 1:one list, retain selections
					// 2:two lists
var sInit = false;

// CITY OBJECT

function City()
{
	this.city="";
	this.state="";
	this.selected=true;
	this.isParent=false;
}

// INITIALIZATION
			
// make sure objects are on page & set search mode
function initsearch(state, left, right)
{
	oState = document.getElementById(state);
	oLeft = document.getElementById(left);

	if(oState && oLeft)
	{
		// if two lists, change search mode
		if( right != null && right.length > 0)
		{
			oRight = document.getElementById(right);
			if(!oRight) return;
			searchMode = 2;
		}
		else if(oLeft.type != "select-multiple")
		{
			searchMode = 1;
		}
		sInit = true;
		populateCityList(oState.value);
	}
}

function populateCityList(strState)
{
	setCursor("wait");
	globalState = strState;
	window.setTimeout('_populateCityList()',1);
}

function setCursor(val)
{
	document.body.style.cursor=val;
	if(oLeft) oLeft.style.cursor=val;
}

// set focus to the main window
function setFocus()
{
	window.focus();
}

// add cities to select list
function _populateCityList()
{ 
	if(!sInit) return;
	var oCity;
	var objList = oLeft;
	var option, objChild;
	var lastParent, displayText;
	var strState = globalState;
	//if(searchMode==1)
	//{
	//	savePrefs();
	//}
	// clear list
	if(objList && objList.options.length > 0)
	{
		objList.options.length = 0;
	}
	//if(searchMode != 1) objList.focus();
	// populate list
	if(objList && strState.length > 0 && oAllCities[strState].length > 0)
	{
		if(searchMode==1)
		{
			option = newOption("","");
			objList.appendChild(option);
		}
		lastParent = null;
		for(var i=0; i<oAllCities[strState].length; i++)
		{
			if(oAllCities[strState][i].isParent)
			{
				lastParent = oAllCities[strState][i];
			}
			if(!oAllCities[strState][i].selected || searchMode != 2)
			{
				oCity = oAllCities[strState][i];
				if(!isChild(oCity.city) || lastParent == null || cityValue(lastParent.city) != parentOf(oCity.city))
					displayText = oCity.city;
				else
					displayText = cityText(oCity.city);
				option = newOption(displayText, cityValue(oCity.city));
				//option.selected = (searchMode == 1 && oCity.selected);
				objList.appendChild(option);
			}
		}
	}
	setCursor("default");
	// set focus to first field in the form
	setFocus();
}

//save the selected items when switching between states
function savePrefs()
{
	//not implemented - only applies to searchmode 1 which is not used
}

// toggle the selected attribute of a city object
// return value is a delimited list of neighborhoods if any
function setSelected(strCity)
{
	var st = getStateFromValue(strCity);
	var ar = oAllCities[st];
	var sFixList = "";
	if(st && ar)
	{
		for(var i=0; i<ar.length; i++)
		{
			if(cityValue(ar[i].city)==strCity)
			{
				ar[i].selected=!ar[i].selected;
				if(ar[i].isParent)
				{
					for(var j=i+1; j<ar.length; j++)
					{
						if(isChild(ar[j].city) && parentOf(ar[j].city) == cityValue(ar[i].city))
						{
							ar[j].selected = !ar[j].selected;
							sFixList += sFixList.length > 0 ? "|" + ar[j].city : ar[j].city;
						}
						else
						{
							break;
						}
					}
				}
				break;
			}
		}
	}
	return sFixList;
}

// extract the state from the value
function getStateFromValue(val)
{
	var str = cityValue(val).split(":")[0];
	if( str.length >= 2 )
		return str.substr(str.length-2,2);
	else
		return "";
}

// return text to be displayed (city or neighborhood)
function cityText(s)
{
	var pos = s.indexOf(":");
	return pos > -1 ? "....." + s.substring(pos+1) : s;
}

// return value from displayed text (strip off "(All Areas)" if present)
function cityValue(s)
{
	var pos = s.indexOf(" (All Areas)");
	return pos > -1 ? s.substring(0,pos) : s;
}

// does the given value contain a town:area
function isChild(val)
{
	return val.indexOf(":") > -1;
}

// return only the parent town if area is present
function parentOf(val)
{
	var pos = val.indexOf(":");
	return pos > -1 ? val.substring(0,pos) : val;
}

// create new select list option
function newOption(txt, val)
{
	var option = document.createElement("OPTION");
	option.innerHTML = txt;
	option.value = val;
	return option;
}

// is the value in the array
function inArray(ar,s)
{
	var index = -1;
	for(var i=0; i<ar.length; i++)
	{
		if(ar[i]==s)
		{
			index=i;
			break;
		}
	}
	return index;
}

//move an item from one list to another
function moveItem(fbox,tbox)
{
	if(!sInit) return;
	var value, text, el, i, arDelete, index=-1;
	arDelete = new Array();
	var objStateCtl = oState;
	var dir;
	var parentFound;
	var sFixList, arFixList = new Array();
	var toRight=0;
	var toLeft=1;

	if(fbox&&tbox&&fbox.selectedIndex >= 0)
	{
		dir = fbox.id==oLeft.id ? toRight : toLeft;
		var orphans = new Array();
		for(var j=0; j<fbox.options.length; j++)
		{
			if( fbox.options[j].selected )
			{
				value = fbox.options[j].value;
				// figure out where to add the new option
				if(dir==toRight || (dir==toLeft && getStateFromValue(value)==objStateCtl.value))
				{
					var pos = inArray(arFixList,value);
					if( dir==toRight && pos > -1 )
					{
						arFixList.slice(pos,1);
					}
					else
					{
						parentFound = false;
						for(i=0; i<tbox.options.length; i++)
						{
							if(isChild(fbox.options[j].value) && parentOf(fbox.options[j].value) == tbox.options[i].value)
								parentFound = true;
							if(tbox.options[i].value > value) // string compare
							{
								break;
							}
						}
						// create new option element
						// add the new option to tbox
						if(dir==toLeft && isChild(fbox.options[j].value) && !parentFound)
							text = fbox.options[j].text;
						else
							text = dir==toLeft?cityText(fbox.options[j].text): !isChild(fbox.options[j].value) ? fbox.options[j].text : fbox.options[j].value;
						el = newOption(text,value);
						tbox.insertBefore(el,tbox.options[i]);
					}
				}
				//toggle selected attribute
				sFixList = setSelected(value);
				if(sFixList.length > 0)
				{
					arFixList = sFixList.split("|");
					if(dir==toLeft && getStateFromValue(value)==objStateCtl.value)
					{
						insertMissingChildren(tbox,i+1,arFixList);
						arFixList.length = 0;
					}
					else
					{
						//if moving a parent city to right box, track any children that are already there
						if(dir==toRight && arFixList.length > 0)
							orphans = orphans.concat(arFixList);
					}
				}
				// keep track of the item to be removed from fbox
				arDelete[++index] = new Array(j,sFixList);
			}
		}
		// delete the selected options from fbox, working from bottom up
		for(j=arDelete.length-1; j>=0; j--)
		{
			if(dir==toRight && arDelete[j][1].length > 0)
			{
				deleteOrphanedChildren(fbox,arDelete[j][0],arDelete[j][1].split("|"));
			}
			fbox.options[arDelete[j][0]]=null;
		}
		// if orphaned children in right box, delete them
		if(orphans.length > 0)
		{
			gOrphans = orphans;
			window.setTimeout("deleteOrphans()",1);
		}
	}
}

// add areas of a town to the select list if not already present
function insertMissingChildren(oList,index,ar)
{
	//alert("inserting " + ar.toString() + " from " + oList.id);
	var el;
	// step through array and insert values that are missing from list
	for(var i=0; i<ar.length; i++)
	{
		if(index < oList.options.length && ar[i] >= oList.options[index].value)
			break;
		el = newOption(cityText(ar[i]),cityValue(ar[i]));
		oList.insertBefore(el,oList.options[index++]);
	}
}

// remove areas of a town from select list if present
function deleteOrphanedChildren(oList,index,ar)
{
	//alert("deleting " + ar.toString() + " from " + oList.id);
	if(index >= oList.options.length) return;
	if(ar.length == 0) return;
	var i=index;
	for(; i<oList.options.length-1; i++)
	{
		if(oList.options[i].value > ar[ar.length-1])
		{
			break;
		}
	}
	for(var j=i; j>=index; j--)
	{
		if(inArray(ar,oList.options[j].value) > -1)
		{
			oList.options[j] = null;
		}
	}
}

// return a comma delimited string containing all the selected towns
function buildTownListForSearch(select)
{
	var delim = "";
	var s = "";
	for(var i=0; i<select.options.length; i++)
	{
		s += (delim + searchCity(select.options[i].value));
		delim = ",";
	}
	return s;
}

// return the town value (just the town or just the area)
function searchCity(s)
{
	var pos = s.indexOf(":");
	return pos > -1 ? s.substring(pos+1) : s;
}

// remove orphaned areas from the right select list when the parent town is moved to the left
function deleteOrphans()
{
	for(var i=oRight.options.length-1; i>=0; i--)
	{
		if(inArray(gOrphans,oRight.options[i].value) > -1)
			oRight.options[i] = null;
	}
}

