/*****************************************************************************
*
* File     : CensusExtentPanel.js
* 
* Project  : WMS Viewer Client
* 
* Contents : This is a custom panel for US Census that loads a list of 
* predefined BBOXes in a "boundaries.xml" file.
*
* Author: Milan Trninic
*
* Copyright 1999-2005 Galdos Systems, Inc.
* All rights reserved.
* 
***|***************************|***********************|*******************|*/

/************************************************************************
*
*	Global declarations
*
*
*************************************************************************/
var EMPTY_LIST_ITEM_ZONE = "Select a Zone";
var EMPTY_LIST_ITEM_EXTENT = "Select an Extent";
var EMPTY_LIST_ITEM_LAYER = "Select a Layer";
var EMPTY_LIST_ITEM_FEATURE = "Select a Feature";
var EMPTY_LIST_ITEM_SRS = "Select a SRS";

/************************************************************************
*
*	function:	CensusCensusExtentPanel
*
*	purpose:	Constructor
*
*************************************************************************/
function CensusExtentPanel()
{
	// superclass
	var uiElement = document.getElementById("censusExtentPanel");
	this._superClass = StackedPanel;
	this._superClass(uiElement);
	
	// method assignments
	this.init = CensusExtentPanel.init;
	this.loadBoundary = CensusExtentPanel.loadBoundary;
	this.loadEmptyBoundary = CensusExtentPanel.loadEmptyBoundary;
	this.initBoundaries = CensusExtentPanel.initBoundaries;
	this.getBoundingBox = CensusExtentPanel.getBoundingBox;
	this.setBoundingBox = CensusExtentPanel.setBoundingBox;
	this.getOriginalBoundingBox = CensusExtentPanel.getOriginalBoundingBox;
	this.sendHarvestRequest = CensusExtentPanel.sendHarvestRequest;
	this.handleHarvestResponse = CensusExtentPanel.handleHarvestResponse;
	this.getXmlHttpObject = CensusExtentPanel.getXmlHttpObject;
	this.addAll = CensusExtentPanel.addAll;
	
	this.srsChanged = CensusExtentPanel.srsChanged;
	this.srsChangedAdapter = CensusExtentPanel.srsChangedAdapter;	
	this.zoneChanged = CensusExtentPanel.zoneChanged;
	this.zoneChangedAdapter = CensusExtentPanel.zoneChangedAdapter;
	this.extentChanged = CensusExtentPanel.extentChanged;
	this.extentChangedAdapter = CensusExtentPanel.extentChangedAdapter;
	this.layerChanged = CensusExtentPanel.layerChanged;
	this.layerChangedAdapter = CensusExtentPanel.layerChangedAdapter;
	this.featureChanged = CensusExtentPanel.featureChanged;
	this.featureChangedAdapter = CensusExtentPanel.featureChangedAdapter;
	this.getBoundaries = CensusExtentPanel.getBoundaries;
	
	this.clearZoneList = CensusExtentPanel.clearZoneList;
	this.clearExtentList = CensusExtentPanel.clearExtentList;
	this.clearLayerList = CensusExtentPanel.clearLayerList;
	this.clearFeatureList = CensusExtentPanel.clearFeatureList;
	this.clearSRSList = CensusExtentPanel.clearSRSList;
	this.clearBBOXList = CensusExtentPanel.clearBBOXList;

	// instance field declarations
	this._superClass;
	this._srsList;
	this._bboxes;
	this._minxUI;
	this._minyUI;
	this._maxxUI;
	this._maxyUI;
	this._xmlhttp;	
	
	this._zoneList;
	this._extentList;
	this._layerList;
	this._featureList;
	this._descriptionUI;
	this._currentBoundary;
	this._originalExtent;

	// initialization
	this.init();
}

/************************************************************************
*
*	function:	init
*
*	purpose:	initializes the globals
*
*************************************************************************/
function CensusExtentPanel.init()
{
	// Enable data transfer
	this._uiElement.setAttribute("dataTransfer", this);
	
	// Zones
	var zoneListUI = document.getElementById("zone");
	this._zoneList = new JsList(zoneListUI);
	this._zoneList.attachEvent("onchange", CensusExtentPanel.zoneChangedAdapter);
	
	// Extent
	var extentListUI = document.getElementById("extent");
	this._extentList = new JsList(extentListUI);
	this._extentList.attachEvent("onchange", CensusExtentPanel.extentChangedAdapter);
	
	// Layers
	var layerListUI = document.getElementById("layer");
	this._layerList = new JsList(layerListUI);
	this._layerList.attachEvent("onchange", CensusExtentPanel.layerChangedAdapter);
	
	// Features
	var featureListUI = document.getElementById("feature");
	this._featureList = new JsList(featureListUI);	
	this._featureList.attachEvent("onchange", CensusExtentPanel.featureChangedAdapter);
	
	// SRS
	var srsListUI = document.getElementById("censusSrsName");
	this._srsList = new JsList(srsListUI);
	this._srsList.attachEvent("onchange", CensusExtentPanel.srsChangedAdapter);
	
	this._bboxes = new Hashtable();

	this._minxUI = document.getElementById("censusMinx");
	this._minyUI = document.getElementById("censusMiny");
	this._maxxUI = document.getElementById("censusMaxx");
	this._maxyUI = document.getElementById("censusMaxy");
	
	this._descriptionUI = document.getElementById("extentDescription");
	this.initBoundaries();		
}

/************************************************************************
*
*	function:	initBoundaries
*
*	purpose:	Load the boundaries list
*
*************************************************************************/
function CensusExtentPanel.initBoundaries() {
	var timer = _log.timerStart();
	var doc = new ActiveXObject("msxml2.DOMDocument.3.0");
	doc.async = false;
	doc.load("conf/boundaries.xml");
	_log.timerEnd("Loaded boundaries into DOM.", timer);
	doc.setProperty("SelectionLanguage", "XPath");
	doc.setProperty("SelectionNamespaces",
		"xmlns='http://www.galdosinc.com/fps' xmlns:fps='http://www.galdosinc.com/fps'");
	this._boundaries = new Hashtable();
	var nodes = doc.getElementsByTagName("Boundary");
	
	for (var index = 0; index < nodes.length; index++) {
		var node = nodes.item(index);
		var wms = node.getAttribute("wms");
		var boundary = new Boundary(node);
		this._boundaries.put(wms, boundary)
	}
	_log.timerEnd("Initialized boundaries.", timer);
}

/************************************************************************
*
*	function:	loadEmptyBoundary
*
*	purpose:	Loads the message when no boundary is defined.
*
*************************************************************************/
function CensusExtentPanel.loadEmptyBoundary() {
	this.clearZoneList(true);
	this.clearExtentList(true);
	this.clearLayerList(true);
	this.clearFeatureList(true);
	this.clearSRSList(true);
	this.clearBBOXList(true);
	this._descriptionUI.value = "No boundaries configured";
}

/************************************************************************
*
*	function:	loadBoundary
*
*	purpose:	Loads the Boundary for display
*
*************************************************************************/
function CensusExtentPanel.loadBoundary(boundary) {
	this._currentBoundary = boundary;
	
	// Zones
	this.clearZoneList(false);
	var zones = this._currentBoundary.getBoundaryZones();
	for (var index = 0; index < zones.getSize(); index++) {
		this._zoneList.addItem(zones.get(index));
	}
	this.clearExtentList(true);
	this.clearLayerList(true);
	this.clearFeatureList(true);
	this.clearSRSList(true);
	this.clearBBOXList(true);
}

/************************************************************************
*
*	function:	getBoundaries
*
*	purpose:	Get the list of Boundaries.
*
*************************************************************************/
function CensusExtentPanel.getBoundaries() {
	return this._boundaries;
}

/************************************************************************
*
*	function:	getBoundingBox
*
*	purpose:	
*
*************************************************************************/
function CensusExtentPanel.getBoundingBox()
{
	var srs = this._srsList.getSelectedItem();
	var spaceInd = srs.indexOf(" ");
	var srsName = srs.substr(0, spaceInd)
	var minx = this._minxUI.value;
	var miny = this._minyUI.value;
	var maxx = this._maxxUI.value;
	var maxy = this._maxyUI.value;

	var bbox = null;
	try
	{
		bbox = new BoundingBox(minx, miny, maxx, maxy, srsName);
	}
	catch (exception)
	{
		
	}
	return bbox;
}

/************************************************************************
*
*	function:	setBoundingBox
*
*	purpose:	Only sets the numbers in the UI. Used for visual zoom and pan
*
*************************************************************************/
function CensusExtentPanel.setBoundingBox(bbox)
{
	this._minxUI.value = bbox.getMinX();
	this._minyUI.value = bbox.getMinY();
	this._maxxUI.value = bbox.getMaxX();
	this._maxyUI.value = bbox.getMaxY();
}

/************************************************************************
*
*	function:	getOriginalBoundingBox
*
*	purpose:	
*
*************************************************************************/
function CensusExtentPanel.getOriginalBoundingBox()
{
	return this._originalExtent;
}

/************************************************************************
*
*	function:	sendHarvestRequest
*
*	purpose:	
*
*************************************************************************/
function CensusExtentPanel.sendHarvestRequest(wmsAddress, handler)
{
	// TODO: Remove this call to save time
	this._xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
	this._xmlhttp.onreadystatechange = handler;
	this._xmlhttp.open("GET", "fpsPortal", true);
	this._xmlhttp.send();
}

/************************************************************************
*
*	function:	handleHarvestResponse
*
*	purpose:	
*
*************************************************************************/
function CensusExtentPanel.handleHarvestResponse()
{
	this.loadBoundary(this._currentBoundary);
}

/************************************************************************
*
*	function:	getXmlHttpObject
*
*	purpose:	
*
*************************************************************************/
function CensusExtentPanel.getXmlHttpObject()
{
	return this._xmlhttp;
}

/************************************************************************
*
*	function:	zoneChanged
*
*	purpose:	Load the new extents when the zone is changed.
*
*************************************************************************/
function CensusExtentPanel.zoneChanged() {
	// Clear list(s)
	this.clearExtentList(false);
	this.clearLayerList(true);
	this.clearFeatureList(true);
	this.clearSRSList(true);
	this.clearBBOXList(true);	
	
	var zone = this._zoneList.getSelectedItem();
	if (zone != EMPTY_LIST_ITEM_ZONE) {		
		// Start msg
		this._descriptionUI.value = "Loading extents for " + zone + ".";
	
		var extents = this._currentBoundary.getBoundaryExtents(zone);
		for (var index = 0; index < extents.getSize(); index++) {
			this._extentList.addItem(extents.get(index));
		}
		
		this._extentList.enable();
		
		// End msg
		this._descriptionUI.value = zone + " extends loaded.";	
	}
	else {
		this._extentList.disable();
	}
}

/************************************************************************
*
*	function:	extentChanged
*
*	purpose:	Load the new layers when the extent is changed.
*
*************************************************************************/
function CensusExtentPanel.extentChanged() {
	// Clear lists
	this.clearLayerList(false);
	this.clearFeatureList(true);
	this.clearSRSList(true);	
	this.clearBBOXList(true);

	var extent = this._extentList.getSelectedItem();	
	if (extent != EMPTY_LIST_ITEM_EXTENT) {		
		// Start msg
		this._descriptionUI.value = "Loading layers for for " + zone + " " + extent + ".";
		
		var zone = this._zoneList.getSelectedItem();
		
		var layers = this._currentBoundary.getBoundaryLayers(zone, extent);
		for (var index = 0; index < layers.getSize(); index++) {
			this._layerList.addItem(layers.get(index));
		}

		this._layerList.enable();	

		// End msg
		this._descriptionUI.value = zone + " " + extent + " layers loaded."
	}
	else {
		this._layerList.disable();
	}	
}

/************************************************************************
*
*	function:	layerChanged
*
*	purpose:	Load the new features when the layer is changed.
*
*************************************************************************/
function CensusExtentPanel.layerChanged() {
	var timer = _log.timerStart();
	// Clear lists
	this.clearFeatureList(false);
	this.clearSRSList(true);
	this.clearBBOXList(true);	

	var layer = this._layerList.getSelectedItem();
	if (layer != EMPTY_LIST_ITEM_LAYER) {
		// Start msg
		this._descriptionUI.value = "Loading features for for " + zone + " " + extent + " " + layer + ".";	

		var zone = this._zoneList.getSelectedItem();
		var extent = this._extentList.getSelectedItem();
		
		var features = this._currentBoundary.getBoundaryFeatures(zone, extent, layer);
		_log.log("Number of features in the layer: " + features.getSize());
		/*
		for (var index = 0; index < features.getSize(); index++) {
			this._featureList.addItem(features.get(index));
		}
		*/
		this.addAll(features);
		
		this._featureList.enable();
		
		// End msg
		this._descriptionUI.value = zone + " " + extent + " " + layer + " features loaded.";
	}
	else {
		this._featureList.disable();
	}
	_log.timerEnd("layerList changed.", timer);
}

/************************************************************************
*
*	function:	addAll
*
*	purpose:	repopulates the features list - this is a workaround to get the 
* better performance. 
* Initially, the elements were added one by one both to drop down list and 
* internal collection. This was bad with, say, 1500 elements.
* Adding in bulk is possible for Collection, but not for drop down list (the select html 
* element). Changing innerHTML doesn't work in IE, and when you change outerHTML you get
* new select object instantiated, so all references by ID have to be updated. In the end
* we implemented this last method, but since it's quite an improvization, we did not put it into
* JsList class, but here.
*
*************************************************************************/
function CensusExtentPanel.addAll(features)
{
	var timer = _log.timerStart();
	var dropDown = this._featureList._uiElement;
	
	var outerHTML = dropDown.outerHTML;
	var splitIndex = outerHTML.indexOf("</SELECT");
	if (splitIndex == -1) splitIndex = outerHTML.indexOf("</select");
	var startPart = outerHTML.substring(0, splitIndex);
	var endPart = outerHTML.substring(splitIndex, outerHTML.length);
	
	var innerHTML = "";
	var array = features._theArray;
	for (var index = 0; index < array.length; index++)
	{
		var item = array[index];
		innerHTML += "<option value=\"" + item.toString() + "\">" + item.toString();
	}
	outerHTML = startPart + innerHTML + endPart;
	// now this will create whole new select object, so redo some initialization
	dropDown.outerHTML = outerHTML;
	
	var newObject = document.getElementById(dropDown.id);
	this._featureList._uiElement = newObject;
	this._featureList.attachEvent("onchange", CensusExtentPanel.featureChangedAdapter);
	
	// finally, add items to the collection
	this._featureList._items.addAll(features);
	_log.timerEnd("Added all.", timer);
}

/************************************************************************
*
*	function:	featureChanged
*
*	purpose:	Load the new SRS(s) when the feature is changed.
*
*************************************************************************/
function CensusExtentPanel.featureChanged()
{
	// Clear lists
	this.clearSRSList(false);
	this.clearBBOXList(true);

	var feature = this._featureList.getSelectedItem();
	if (feature != EMPTY_LIST_ITEM_FEATURE) {
		var zone = this._zoneList.getSelectedItem();
		var extent = this._extentList.getSelectedItem();
		var layer = this._layerList.getSelectedItem();	
		
		var srsTextList = this._currentBoundary.getBoundarySrsNames(zone, extent, layer, feature);
		for (var index = 0; index < srsTextList.getSize(); index++) {
			var srs = srsTextList.get(index);
			this._srsList.addItem(srs);
			// Check whether current srsName equals default
			// Syntax is slightly different, default is srsName only, srsList
			// contains (srsName + " " + srsType) so we just check the srsName portion
			if (srs.indexOf(this._currentBoundary.getDefaultSrsName() + " ") == 0) {
				this._srsList.selectItem(srs);
			}
		}

		this._srsList.enable();	
			
		// End msg
		this._descriptionUI.value = "Feature Selection Bounding Box set from "
			+ zone + " " + extent + " " + layer + " " + feature + ".";
	}
	else {
		this._srsList.disable(true);
	}
}

/************************************************************************
*
*	function:	srsChanged
*
*	purpose:	Load the new BBOX when the SRS is changed.
*
*************************************************************************/
function CensusExtentPanel.srsChanged()
{		
	var srs = this._srsList.getSelectedItem();
	if (srs != EMPTY_LIST_ITEM_SRS) {
		var spaceInd = srs.indexOf(" ");
		var srsName = srs.substr(0, spaceInd);
		var zone = this._zoneList.getSelectedItem();
		var extent = this._extentList.getSelectedItem();
		var layer = this._layerList.getSelectedItem();
		var feature = this._featureList.getSelectedItem();
		
		var bbox = this._currentBoundary.getBoundaryBbox(zone, extent, layer, feature, srsName);
		this._minxUI.value = bbox.getMinX();
		this._minyUI.value = bbox.getMinY();
		this._maxxUI.value = bbox.getMaxX();
		this._maxyUI.value = bbox.getMaxY();
		
		this._minxUI.disabled = false;
		this._minyUI.disabled = false;
		this._maxxUI.disabled = false;
		this._maxyUI.disabled = false;
		
		this._originalExtent = bbox;
	}
	else {
		this.clearBBOXList(true);
		this._originalExtent = null;
	}
}

/************************************************************************
*
*	function:	disableZOne
*
*	purpose:	Clear and disable the Zone control.
*
*************************************************************************/
function CensusExtentPanel.clearZoneList(disable) {
	this._zoneList.removeAllItems();
	this._zoneList.addItem(EMPTY_LIST_ITEM_ZONE);
	if (disable) {
		this._zoneList.disable();		
	}
}

/************************************************************************
*
*	function:	disableExtent
*
*	purpose:	Clear and disable the Extent control.
*
*************************************************************************/
function CensusExtentPanel.clearExtentList(disable) {
	this._extentList.removeAllItems();
	this._extentList.addItem(EMPTY_LIST_ITEM_EXTENT);
	if (disable) {
		this._extentList.disable();		
	}
}

/************************************************************************
*
*	function:	disableLayer
*
*	purpose:	Clear and disable the Layer control.
*
*************************************************************************/
function CensusExtentPanel.clearLayerList(disable)
{
	this._layerList.removeAllItems();
	this._layerList.addItem(EMPTY_LIST_ITEM_LAYER);	
	if (disable) {
		this._layerList.disable();
	}
}

/************************************************************************
*
*	function:	disableFeature
*
*	purpose:	Clear and disable the Feature control.
*
*************************************************************************/
function CensusExtentPanel.clearFeatureList(disable) {
	this._featureList.removeAllItems();
	this._featureList.addItem(EMPTY_LIST_ITEM_FEATURE);
	if (disable) {
		this._featureList.disable();	
	}
}

/************************************************************************
*
*	function:	disableSRS
*
*	purpose:	Clear and disable the SRS control.
*
*************************************************************************/
function CensusExtentPanel.clearSRSList(disable) {
	this._srsList.removeAllItems();
	this._srsList.addItem(EMPTY_LIST_ITEM_SRS);
	if (disable) {
		this._srsList.disable();	
	}
}

/************************************************************************
*
*	function:	disableBBOX
*
*	purpose:	Clear and disable the BBOX control.
*
*************************************************************************/
function CensusExtentPanel.clearBBOXList(disable) {
	this._minxUI.value = "";
	this._minyUI.value = "";
	this._maxxUI.value = "";
	this._maxyUI.value = "";

	if (disable) {
		this._minxUI.disabled = true;
		this._minyUI.disabled = true;
		this._maxxUI.disabled = true;
		this._maxyUI.disabled = true;
	}
}

/************************************************************************
*
*	function:	Event handler adapters
*
*	purpose:	
*
*************************************************************************/
function CensusExtentPanel.zoneChangedAdapter(){target(event, CensusExtentPanel).zoneChanged(event);}
function CensusExtentPanel.extentChangedAdapter(){target(event, CensusExtentPanel).extentChanged(event);}
function CensusExtentPanel.layerChangedAdapter(){target(event, CensusExtentPanel).layerChanged(event);}
function CensusExtentPanel.featureChangedAdapter(){target(event, CensusExtentPanel).featureChanged(event);}
function CensusExtentPanel.srsChangedAdapter(){target(event, CensusExtentPanel).srsChanged(event);}
