<?php
#
# select.php (c) 2007 Dan "Ducky" Little
# Write for the GeoMOOSE project, sponsored by the OpenMNND Organization
# PHP Translation of the Perl script select.pl
#

# Make the PHP Script Shut Up, but still give something useful if there
# is a legit error or parsing bug.
error_reporting(E_ERROR | E_PARSE);

# Include the GeoMOOSE PHP Library Utilities
include('Configuration.php');
include('geomoose_php_util.php');

# Get in the information from the request
$coordinates = $_REQUEST['coords'];
$title = $_REQUEST['title'];
$shapeType = $_REQUEST['shape'];
$buffer = $_REQUEST['buffer'];
$layer = $_REQUEST['layer'];
$output = $_REQUEST['output'];
$identifyMap = $_REQUEST['map'];
$selectMap = $_REQUEST['select'];

# Check for some vitals
if(!isset($layer)) {
	appError('Layer value is not set or invalid: '.$layer);
}
if(!isset($output)) {
	$output = $DEFAULT_OUTPUT;
}

# Check the CGI for the layer/column Delimiter,
# If it's not found, then use the default.
$delim = $_REQUEST['delim'];
if(!isset($delim)) {
	$delim = $DEFAULT_DELIM;
}
# This splits the input layer sting into the Layer Name and the Column Containing the ID's for the layer
list($layer, $queryColumn) = explode($delim, $layer);

# This checks for the existance of the select mapfile.
# If it does not exist the application quits with an error message.
if(!file_exists($selectMap)) {
	appError('Could not find: '.$selectMap);
}

# This checks to see what "shape" is being passed to the script to query against.
if($shapeType == "point") {
	$shapeType = MS_SHAPE_POINT;
} elseif($shapeType == 'circle') {
} elseif($shapeType == 'line') {
	$shapeType = MS_SHAPE_LINE;
	if(empty($buffer)) {
		$buffer = 1;	# Makes the line work if there is no buffer specified or the buffer = 0
	}
} else {
	$shapeType = MS_SHAPE_POLYGON;
}


# Convert the coordinates to a new shape object
# This takes the coordinates from the CGI and adds them to a Shape for querying.
$shape = ms_newShapeObj($shapeType);
$coords = array();
$coords = explode(' ', $coordinates);
$line = ms_newLineObj();
foreach ($coords as $coord) {
	list($x, $y) = explode(',',$coord);
	$line->addXY($x,$y);
}
$shape->add($line);	# This adds the line with all the coordinates from the CGI
#$shape->setBounds();	# This initalizes the shape.

# Buffer as desired.
if(isset($buffer)) {
	$shape = $shape->buffer($buffer);	# Mapscript using GEOS to bufffer the shape
	if(!isset($shape)) { 			# Check to make sure the function returned a valid shape, if not, error.
		appError("Buffering Failed. Buffer size: $buffer. Verify mapscript was linked with GEOS and that the buffer is a positive-real number.");
	}
}

# Create a new Coordinate string based on any potential buffering.
# This is needed because after the object has been buffered it will have a new coordinate string.
# This information is passed back to the GeoMOOSE client so that it can set the "mapshape" parameter
# which displays the layer highlighting.
$coordString = '';
for($line = 0; $line < $shape->{numlines}; $line++) {
	$lineObj = $shape->line($line);
	for($point = 0; $point < $lineObj->{numpoints}; $point++) {
		$pointObj = $lineObj->point($point);
		$coordString = $coordString.$pointObj->{x}.' '.$pointObj->{y}.' ';
	}
}

# Set up the query to perform the select, with the buffer and all!
# If the Map does not open correctly, error out.
$queryMap = ms_newMapObj($selectMap) or appError('Could not open mapfile: '.$selectMap."\n".'Please verify the Map file is valid.');

# This section of code searches for the query layer.
# If a layer is not the query layer, it is turned off so that errorneous/extraneous results are not
# also returned.  This also helps speed queries so that multiple large datasets are not simultaneously queried.
$queryLayerFound = false;	# Set an error condition in case we do not find the layer
for($l = 0; $l < $queryMap->{numlayers}; $l++) {
	$queryLayer = $queryMap->getLayer($l);
	$queryLayer->set('status', MS_OFF);		# Turn the layer off
	if($queryLayer->{name} == $layer) {		# If it's the layer we're trying to search...
		$queryLayer->set('status',MS_ON);	# Turn it on!
		$queryLayerFound = true;		# "Unset" the Error Condition
	}
}

if(!$queryLayerFound) {	# If they layer is not found in the mapfile, error out.
	appError("The Query Layer '$layer' could not be found in the mapfile ($selectMap).");
}
# Perform the Query.
$queryResultCheck = $queryMap->queryByShape($shape);
if($queryResultCheck == MS_FAILURE) {		# If the query fails, error out.
	# Check to see if the Map has any pointers to an empty file
	$empty = $queryMap->web->empty;
	# If it's set then show that HTML instead. :D
	if(isset($empty) and $empty != '') {
		readfile($empty);
		exit(0);		
	} else {
		appError('Query Failed to return any results!');
	}
}

# Cycle through the results of the query and build an array containing the results.
$resultContents = array();
for($l = 0; $l < $queryMap->{numlayers}; $l++) {		# Cycle through the layers
	$queryLayer = $queryMap->getLayer($l);		# Get they layer object from the map.
	if($queryLayer->{name} == $layer) {			# Check to make sure it's our layer of interest.
#		$queryResults = $queryLayer->getResults();	# Get the results from the query.
		$queryColumns = array();				# Hash table to hold the column names.

		$queryLayer->open();				# Open the layer for operation.

		# This loop deserves from definition.
		# What this look is doing is creating a assosciative array (hash table) containing the shapefile
		# indexes of the column names
		# Example:  
		# 	A layer could contain the following columns: 0 - ID, 1 - OWNER, 2 - CITY
		# 	This loop would create an associative array that has the indexes of {'ID','OWNER','CITY'} and the corresponding values {0,1,2}
		# 	Ergo, $queryColumns{'OWNER'} will return 0
		for($item = 0; $item < $queryLayer->{numitems}; $item++) {
			$queryColumns{$queryLayer->getItem($item)} = $item;
		}

		if($queryLayer->getNumResults() > 0) {  # Check to make sure we have SOME results
			#			for($result = 0; $result < $queryResults->{numresults}; $result++) {	# Loop through the results
			for($result = 0; $result < $queryLayer->getNumResults(); $result++) {
				# Get the member of the result set
				$queryResult = $queryLayer->getResult($result);
				# Get the feature from that result.
				# I left getFeature in here, as getShape will be deprecated for getFeature
				#$queryFeature = $queryLayer->getFeature($queryResult->{shapeindex}, $queryResult->{tileindex}); 
				$queryFeature = $queryLayer->getShape($queryResult->{tileindex}, $queryResult->{shapeindex}); 
				# Here's where the array from before becomes very handy.  The column *name* is passed
				# into the CGI, so we need to result the shapefile-column index and the name,
				# which is query %queryColumns does! So now, we can just pull the ID column from the object.
				$v = $queryFeature->{values}[$queryColumn];
				# And put that ID onto the stack of results...
				array_push($resultContents, $v);
			}
		} else {
			appError('No Query Results on Selected Layer');
		}

		$queryLayer->close(); # Close the layer
	}
}

# Process the query template from the mapfile and return it to the user
# This way the results are displayed exactly as they are definied in the mapfile.
$template = $queryMap->processQueryTemplate(array(), array());

if($output == 'xml') {
	header('Content-type: text/xml');
	# Return the XML that tells GeoMOOSE what to do!
	#
	# By passing "mapbook fragments" back to GeoMOOSE we can change the behavior and 
	# definition of the maps being displayed.  $layer contains the mapbook name of the 
	# layer we were selecting-against.  The "<param.../>" line will set the mapshape parameter for
	# the layer we selected against.
	print "<return>";
	printf("<map title='Highlight' default='true'>", $layer);
	printf("	<file>%s</file>", $identifyMap);
	$strippedLayer = preg_replace("/ /",'',$layer);
	printf("	<param name='layers' value='%s'/>", $strippedLayer);
	printf("	<param name='qlayer' value='%s'/>", $strippedLayer);
	printf("	<param name='mapshape' value='%s'/>", $coordString);

	# This takes the ID's from the results stack and puts it inside the layer.
	foreach ($resultContents as $id) {
		#	print "\t\t<selected id='$id'/>\n";
		printf("	<selected id='%s'/>", $id);
	}

	print "\t</map>";

	# Print some header information.
	print '<results title="Select Results">';
	print '		<header><col value="Selected Objects:"/></header>';
	print "		<row><col value='".count($resultContents)."'/></row>";
	print '</results>';


	print $template;

	print "</return>";	# End the XML Page.
} elseif($output == 'html') {
	header('Content-type: text/html');
	## HTML OUTPUT
	# This is a HTML/XML trick that uses XML namespaces in order to embed a GeoMOOSE
	# mapbook into a HTML document.
	print '<html xmlns:moose="http://geomoose.org/">';
	print "<head>\n";
	print "<moose:mapbook>\n";
	#	print "<moose:map title="'.$layer.'" default="true">\n";
	printf("<moose:map title='Highlight' default='true'>\n",$layer);
	printf("	<moose:file>%s</moose:file>", $identifyMap);
	$strippedLayer = preg_replace("/ /",'',$layer);
	printf("	<moose:param name='layers' value='%s'/>", $strippedLayer);
	printf("	<moose:param name='qlayer' value='%s'/>", $strippedLayer);
#	print "	<moose:param name='mapshape' value='".$coordString."'/>\n";
	printf ("<moose:param name='mapshape' value='%s'/>\n", $coordString);
	foreach ($resultContents as $id) {
		printf("	<moose:selected id='%s'/>\n", $id);
	}
	print "</moose:map>\n";
	print "</moose:mapbook>\n";
	print "</head>";
	print "<body>";
	print "<![CDATA[";
	print $template;
	print "]]>";
	print "</body>";
	print "</html>";
} else {
	appError('Unrecognized output option: '.$output);
}

exit; # End the Program!
?>
