/*******************************************************************************
*                                                                       
*N  {geom_spatial_rel.c}  -- demonstrates the relationship between shapes; and the  
*                       usage of spatial filter in spatial queries
*   
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*P  Purpose:
*    This sample C program demonstrates the relationship between shapes and 
*    the usage of spatial filter in spatial query
*    
*   Sample high level overview:
*   
*   Show shape relationships and query the polygon layer with different filters;
*     (1) Point filter;
*     (2) Line filter;
*     (3) Polygon filter;
*   
*  The following sptial relationship will be checked:
*
*     SE_shape_is_containing()
*     SE_shape_is_containing();
*     SE_shape_is_within();
*     SE_shape_is_touching();
*     SE_shape_is_crossing();
*     SE_shape_is_overlapping();
*     SE_shape_is_equal();

*  The following filters will be demostrated:
*
 *	  SM_ENVP            : Envelopes overlap
 *	  SM_CP              : Common point 
 *	  SM_LCROSS          : Line cross 
 *	  SM_COMMON          : Common edge/line
 *	  SM_CP_OR_LCROSS    : Common point or line cross 
 *	  SM_AI_OR_ET        : Edge touch or area intersect 
 *	  SM_AI              : Area intersect 
 *	  SM_PC              : Primary contained in secondary
 *	  SM_SC              : Secondary contained in primary
 *	  SM_IDENTICAL       : Identical
*E                                                                 
*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
* How to compile:: 
*	 Please refer section "Build C Samples" in the SDE sample
*
*E
*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
* Usage:
*     geom_spatial_rel {server} {instance} {database} {user} {password} {keywords}  
*
*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*X  Legalese:
*
* Copyright � 2007 ESRI
*
* All rights reserved under the copyright laws of the United States and 
* applicable international laws, treaties, and conventions.
*
* You may freely redistribute and use this sample code, with or without 
* modification, provided you include the original copyright notice and use 
* restrictions.  
*
* Disclaimer:  THE SAMPLE CODE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED 
* WARRANTIES, INCLUDING THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ESRI OR 
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
* OR BUSINESS INTERRUPTION) SUSTAINED BY YOU OR A THIRD PARTY, HOWEVER CAUSED 
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 
* TORT ARISING IN ANY WAY OUT OF THE USE OF THIS SAMPLE CODE, EVEN IF ADVISED 
* OF THE POSSIBILITY OF SUCH DAMAGE.
* 
* For additional information, contact:
* Environmental Systems Research Institute, Inc.
* Attn: Contracts and Legal Services Department
* 380 New York Street
* Redlands, California, 92373
* USA
* 
* email: contracts@esri.com
*
*E
****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include "sdetype.h"
#include "sdeerno.h"

typedef enum {
  SP_FILTER_POINT,
  SP_FILTER_LINE,
  SP_FILTER_POLYGON
} SP_FILTER_SHPTYPE;

/* Function macros */
#define check_rc_return_on_failure(c,s,rc,f) \
	{if(rc!= SE_SUCCESS) {check_rc_(c,s,rc,f,__LINE__,__FILE__);return SE_FAILURE; }}
/* Local Function Prototypes */
void check_rc_(SE_CONNECTION Connection, SE_STREAM Stream, LONG rc, 
				 char *comment, LONG line_no, char* file_name) ;
static LONG S_create_layer (SE_CONNECTION, const CHAR *,const CHAR*,LONG,const CHAR *);
static LONG S_populate_sample_layer (SE_CONNECTION ,const CHAR *,const CHAR*);
static LONG S_populate_line_layer (SE_CONNECTION ,const CHAR *,const CHAR*);
static LONG S_populate_point_layer (SE_CONNECTION,const CHAR *,const CHAR* );
static LONG S_prepare_filter_shape(SE_CONNECTION, CHAR*,CHAR*,SP_FILTER_SHPTYPE,SE_SHAPE*);
static LONG S_apply_filters(SE_CONNECTION, const CHAR *,const CHAR*,CHAR*, SE_FILTER);
static LONG S_execute_queries(SE_CONNECTION,CHAR *,CHAR* );
static LONG S_query_layer(SE_CONNECTION, const CHAR *,const CHAR*,const CHAR*,SE_FILTER*,BOOL);

LONG main(int argc, char *argv[]){
	CHAR   			*server, 
       	       		*user, 
					*passwd, 
					*database,
					*instance,
					*keyword;
	SE_CONNECTION 	conn;
	SE_ERROR 		error;
	LONG			result;
	CHAR			lay_name[SE_MAX_TABLE_LEN+1],
					shapecol[SE_MAX_COLUMN_LEN+1];
	LONG			layer_type;

	/*check input parmerters*/
	if(argc<7){
		printf("Usage %s <server> <instance> <database> <user> <password> <keyword>",argv[0]);
		exit(1);
	}

	server=argv[1];
	instance=argv[2];
	database=argv[3];
	user=argv[4];
	passwd=argv[5];
	keyword=argv[6];

	/*Connect to SDE server*/
  	result = SE_connection_create( server, instance, database, user, passwd, &error, &conn );
	check_rc_return_on_failure (conn,NULL,result,"SE_connection_create");
	printf("\nconnected to %s:%s as %s.\n\n",argv[1],argv[2], argv[4]);

	/*Prepare three sample layers*/
	strcpy(lay_name,"SAMPLE_SP_POLY");
	strcpy(shapecol,"SHAPE");
	printf("***************************************************\n");
	printf("Prepare Sample Layer:                              \n");
	printf("***************************************************\n\n");

	/*Create and populate a polygon layer*/
	printf("\n  Create a smaple layer...\n");
	layer_type=SE_AREA_TYPE_MASK|SE_NIL_TYPE_MASK|SE_MULTIPART_TYPE_MASK;
	result=S_create_layer(conn,lay_name,shapecol,layer_type,keyword);
	if(result!=SE_SUCCESS)
		return result;
	printf("\n  Populated the sample layer...\n");
	result=S_populate_sample_layer(conn,lay_name,shapecol);
	if(result!=SE_SUCCESS)
		return result;
	
	/*Query the sample layer*/
	printf("\n***************************************************\n");
	printf("Execute Queries:                                     \n");
	printf("***************************************************\n\n");
	result=S_execute_queries(conn,lay_name,shapecol);

	/*Free resources*/
	result = SE_table_delete(conn,lay_name);
	SE_connection_free(conn);

	return SE_SUCCESS;

}

/***********************************************************************
*
*N  {S_create_layer}  -  create a SDE layer with provided specification
*
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
*P  Purpose:
*     create a layer to store sample data
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
*A  Parameters:
*     <connection>  ==  (SE_CONNECTION) The connection handle.
*     <table  >     ==  (CHAR*) the result layer name
*     <spatailcol>  ==  (CHAR*) the spatial column name
*     <layertype>   ==  (LONG) layer type mask
*     <keyword >    ==  (CHAR*) the keyword for layer creation
*E
***********************************************************************/
static LONG S_create_layer (SE_CONNECTION connection, const CHAR *table,const CHAR* spatailcol,
					 LONG layertype,const CHAR *keyword)
{
	SE_LAYERINFO        layer;
	SHORT               number_of_columns;
	SE_COLUMN_DEF       column_definitions[2];
	SE_COORDREF         coordref;
	LONG                result;
	SE_REGINFO          registration;
	CHAR				rowidcol[SE_MAX_COLUMN_LEN];

	/* Create the base table. */

	//init base table column names
	number_of_columns = 1;
	strcpy(column_definitions[0].column_name,"SHPNAME");
	column_definitions[0].sde_type = SE_STRING_TYPE;
	column_definitions[0].size = 10;
	column_definitions[0].decimal_digits = -1;
	column_definitions[0].nulls_allowed = FALSE;

	//Delete the table if it existed
	result = SE_table_delete(connection,table);
	if(result!=SE_TABLE_NOEXIST)
		check_rc_return_on_failure (connection,NULL,result,"SE_table_delete");

	//Create the table
	result = SE_table_create (connection,table,number_of_columns,
							column_definitions,keyword);
	check_rc_return_on_failure (connection,NULL,result,"SE_table_create");

	/* Add an SDE maintained rowid */
	result = SE_reginfo_create (&registration);
	check_rc_return_on_failure (connection,NULL,result,"SE_reginfo_create");
	result = SE_registration_get_info (connection,table,registration);
	check_rc_return_on_failure (connection,NULL,result,"SE_registration_get_info");
	result = SE_reginfo_set_creation_keyword (registration,keyword);
	check_rc_return_on_failure (connection,NULL,result,"SE_reginfo_set_creation_keyword");
	strcpy(rowidcol,"ROWIDCOL");
	result = SE_reginfo_set_rowid_column (registration,rowidcol,
							   SE_REGISTRATION_ROW_ID_COLUMN_TYPE_SDE);
	check_rc_return_on_failure (connection,NULL,result,"SE_reginfo_set_rowid_column");
	result = SE_registration_alter (connection,registration);
	check_rc_return_on_failure (connection,NULL,result,"SE_registration_alter");

	/* Add the spatial column to the table */
	result = SE_coordref_create (&coordref);
	check_rc_return_on_failure (connection,NULL,result,"SE_coordref_create");
	result = SE_coordref_set_xy (coordref,0.0,0.0,10.0);
	check_rc_return_on_failure (connection,NULL,result,"SE_coordref_set_xy");
	result = SE_layerinfo_create (coordref,&layer);
	check_rc_return_on_failure (connection,NULL,result,"SE_layerinfo_create");
	result = SE_layerinfo_set_grid_sizes (layer,1000.0,0.0,0.0);
	check_rc_return_on_failure (connection,NULL,result,"SE_layerinfo_set_grid_sizes");
	result = SE_layerinfo_set_shape_types (layer,layertype);
	check_rc_return_on_failure (connection,NULL,result,"SE_layerinfo_set_shape_types");
	result = SE_layerinfo_set_spatial_column (layer,table,spatailcol);
	check_rc_return_on_failure (connection,NULL,result,"SE_layerinfo_set_spatial_column");
	result = SE_layerinfo_set_creation_keyword (layer,keyword);
	check_rc_return_on_failure (connection,NULL,result,"SE_layerinfo_set_creation_keyword");
	result = SE_layer_create (connection,layer,20,10);
	check_rc_return_on_failure (connection,NULL,result,"SE_layer_create");

	SE_reginfo_free(registration);
	SE_coordref_free(coordref);
	SE_layerinfo_free(layer);

	return(SE_SUCCESS);

}           

/***********************************************************************
*
*N  {S_populate_sample_layer} - populate the sample polygon layer
*
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
*P  Purpose:
*     populated the polygon sample layer
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
*A  Parameters:
*     <connection>  ==  (SE_CONNECTION) The connection handle.
*     <table  >     ==  (CHAR*) the result layer name
*     <spatailcol>  ==  (CHAR*) the spatial column name
*E
***********************************************************************/
static LONG S_populate_sample_layer (SE_CONNECTION  handle,
                       const CHAR *table,const CHAR* spatialcol)
{
	SE_STREAM       stream;
	LONG            result,i;
	SHORT           number_of_columns;
	CHAR            **base_columns;
	SE_LAYERINFO    layer;
	SE_COORDREF     coordref;
	SE_SHAPE        shape,tmpshape;
	SE_ENVELOPE     rectangle,tmprect;
	CHAR            shpname[10];
    SHORT           shpname_ind,shpdesc_ind,shape_ind;

	/* Init column names for insert */
	base_columns = (CHAR **) malloc (2 * sizeof(CHAR *));
	for(i=0;i<2;i++)
		base_columns[i]=(CHAR *) malloc (SE_MAX_COLUMN_LEN);
	strcpy(base_columns[0], "SHPNAME");
	strcpy(base_columns[1] ,spatialcol);

	/*Init a shape object*/
	result = SE_layerinfo_create (NULL,&layer);
	check_rc_return_on_failure (handle,NULL,result,"SE_layerinfo_create");
	result = SE_coordref_create (&coordref);
	check_rc_return_on_failure (handle,NULL,result,"SE_coordref_create");
	result = SE_layer_get_info (handle,table,spatialcol,layer);
	check_rc_return_on_failure (handle,NULL,result,"SE_layer_get_info");
	result = SE_layerinfo_get_coordref (layer,coordref);
	check_rc_return_on_failure (handle,NULL,result,"SE_layerinfo_get_coordref");
	result = SE_shape_create (coordref,&shape);
	check_rc_return_on_failure (handle,NULL,result,"SE_shape_create");
	result = SE_shape_create (coordref,&tmpshape);
	check_rc_return_on_failure (handle,NULL,result,"SE_shape_create");

	//Start transation
	result = SE_connection_start_transaction (handle);
	check_rc_return_on_failure (handle,NULL,result,"SE_connection_start_transaction");

	//Prepare an insert stream
	result = SE_stream_create (handle,&stream);
	check_rc_return_on_failure (handle,NULL,result,"SE_stream_create");
	number_of_columns =2;
	result = SE_stream_insert_table (stream,table,number_of_columns,
								   (const CHAR **)base_columns);
	check_rc_return_on_failure (NULL,stream,result,"SE_stream_insert_table");
	result = SE_stream_set_write_mode (stream,TRUE);
	check_rc_return_on_failure (NULL,stream,result,"SE_stream_set_write_mode");
	result = SE_stream_bind_input_column (stream,1,shpname,&shpname_ind);
	check_rc_return_on_failure (NULL,stream,result,"SE_stream_bind_input_column");
	result = SE_stream_bind_input_column (stream,2,shape,&shape_ind);
	check_rc_return_on_failure (NULL,stream,result,"SE_stream_bind_input_column");

	/* Perform the inserts. */
	shpname_ind   = SE_IS_NOT_NULL_VALUE;
	shpdesc_ind      = SE_IS_NOT_NULL_VALUE;
	shape_ind   = SE_IS_NOT_NULL_VALUE;

	//insert shp1
	rectangle.minx = 2000.0;
	rectangle.miny = 2000.0;
	rectangle.maxx = 4000.0;
	rectangle.maxy = 4000.0;
	strcpy(shpname,"POLY1");
	result = SE_shape_generate_rectangle (&rectangle,shape);
	check_rc_return_on_failure (handle,NULL,result,"SE_shape_generate_rectangle");
	result = SE_stream_execute (stream);
	check_rc_return_on_failure (NULL,stream,result,"SE_stream_execute");

	//insert shp2
	rectangle.minx = 2000.0;
	rectangle.miny = 4000.0;
	rectangle.maxx = 4000.0;
	rectangle.maxy = 6000.0;
	strcpy(shpname,"POLY2");
	result = SE_shape_generate_rectangle (&rectangle,shape);
	check_rc_return_on_failure (handle,NULL,result,"SE_shape_generate_rectangle");
	result = SE_stream_execute (stream);
	check_rc_return_on_failure (NULL,stream,result,"SE_stream_execute");

	//insert shp3
	rectangle.minx = 5000.0;
	rectangle.miny = 6000.0;
	rectangle.maxx = 6000.0;
	rectangle.maxy = 8000.0;
	strcpy(shpname,"POLY3");
	result = SE_shape_generate_rectangle (&rectangle,shape);
	check_rc_return_on_failure (handle,NULL,result,"SE_shape_generate_rectangle");
	result = SE_stream_execute (stream);
	check_rc_return_on_failure (NULL,stream,result,"SE_stream_execute");

	//insert shp4
	rectangle.minx = 6000.0;
	rectangle.miny = 9000.0;
	rectangle.maxx = 10000.0;
	rectangle.maxy = 10000.0;
	strcpy(shpname,"POLY4");
	result = SE_shape_generate_rectangle (&rectangle,shape);
	check_rc_return_on_failure (handle,NULL,result,"SE_shape_generate_rectangle");
	result = SE_stream_execute (stream);
	check_rc_return_on_failure (NULL,stream,result,"SE_stream_execute");

	//insert shp5
	rectangle.minx = 6000.0;
	rectangle.miny = 10000.0;
	rectangle.maxx = 10000.0;
	rectangle.maxy = 12000.0;
	tmprect.minx = 4000.0;
	tmprect.miny = 8000.0;
	tmprect.maxx = 5000.0;
	tmprect.maxy = 10000.0;
	strcpy(shpname,"POLY5");
	result = SE_shape_generate_rectangle (&rectangle,shape);
	check_rc_return_on_failure (handle,NULL,result,"SE_shape_generate_rectangle");
	result = SE_shape_generate_rectangle (&tmprect,tmpshape);
	check_rc_return_on_failure (handle,NULL,result,"SE_shape_generate_rectangle");
	//add second part to target shape
	result = SE_shape_add_part (tmpshape, shape);
	check_rc_return_on_failure (handle,NULL,result,"SE_shape_add_part");
	result = SE_stream_execute (stream);
	check_rc_return_on_failure (NULL,stream,result,"SE_stream_execute");

	//insert shp6
	rectangle.minx = 10000.0;
	rectangle.miny = 10000.0;
	rectangle.maxx = 12000.0;
	rectangle.maxy = 12000.0;
	tmprect.minx = 9000.0;
	tmprect.miny = 9000.0;
	tmprect.maxx = 10000.0;
	tmprect.maxy = 10000.0;
	strcpy(shpname,"POLY6");
	result = SE_shape_generate_rectangle (&rectangle,shape);
	check_rc_return_on_failure (handle,NULL,result,"SE_shape_generate_rectangle");
	result = SE_shape_generate_rectangle (&tmprect,tmpshape);
	check_rc_return_on_failure (handle,NULL,result,"SE_shape_generate_rectangle");
	//add second part to target shape
	result = SE_shape_add_part (tmpshape, shape);
	result = SE_stream_execute (stream);
	check_rc_return_on_failure (NULL,stream,result,"SE_stream_execute");

	//insert shp7
	rectangle.minx = 10000.0;
	rectangle.miny = 6000.0;
	rectangle.maxx = 12000.0;
	rectangle.maxy = 10000.0;
	tmprect.minx = 8000.0;
	tmprect.miny = 6000.0;
	tmprect.maxx = 9000.0;
	tmprect.maxy = 7000.0;
	strcpy(shpname,"POLY7");
	result = SE_shape_generate_rectangle (&rectangle,shape);
	check_rc_return_on_failure (handle,NULL,result,"SE_shape_generate_rectangle");
	result = SE_shape_generate_rectangle (&tmprect,tmpshape);
	check_rc_return_on_failure (handle,NULL,result,"SE_shape_generate_rectangle");
	//add second part to target shape
	result = SE_shape_add_part (tmpshape, shape);
	result = SE_stream_execute (stream);
	check_rc_return_on_failure (NULL,stream,result,"SE_stream_execute");

	//insert shp8
	rectangle.minx = 2000.0;
	rectangle.miny = 4000.0;
	rectangle.maxx = 9000.0;
	rectangle.maxy = 9000.0;
	strcpy(shpname,"POLY8");
	result = SE_shape_generate_rectangle (&rectangle,shape);
	check_rc_return_on_failure (handle,NULL,result,"SE_shape_generate_rectangle");
	result = SE_shape_generate_rectangle (&rectangle,shape);
	check_rc_return_on_failure (handle,NULL,result,"SE_shape_generate_rectangle");
	result = SE_stream_execute (stream);
	check_rc_return_on_failure (NULL,stream,result,"SE_stream_execute");

	//insert shp9: small polygon
	rectangle.minx = 9995.0;
	rectangle.miny = 3995.0;
	rectangle.maxx = 10005.0;
	rectangle.maxy = 4005.0;
	strcpy(shpname,"POLY9");
	result = SE_shape_generate_rectangle (&rectangle,shape);
	check_rc_return_on_failure (handle,NULL,result,"SE_shape_generate_rectangle");
	result = SE_shape_generate_rectangle (&rectangle,shape);
	check_rc_return_on_failure (handle,NULL,result,"SE_shape_generate_rectangle");
	result = SE_stream_execute (stream);
	check_rc_return_on_failure (NULL,stream,result,"SE_stream_execute");

	//flush the insert stream
	result = SE_stream_flush_buffered_writes (stream);
	check_rc_return_on_failure (NULL,stream,result,"SE_stream_flush_buffered_writes");

	result = SE_stream_free(stream);
	check_rc_return_on_failure (NULL,stream,result,"SE_stream_free");

	//commit the transation
	result = SE_connection_commit_transaction (handle);
	check_rc_return_on_failure (handle,NULL,result,"SE_connection_commit_transaction");

	SE_coordref_free(coordref);
	SE_shape_free(shape);
	SE_layerinfo_free(layer);
	free(base_columns);
	return(SE_SUCCESS);
}

/***********************************************************************
*
*N  {S_query_layer} - perform the queries.
*
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
*P  Purpose:
*     Query the layer, and showing either relationships between the filter
*     shape and each feature in the layer;or the result the spatial query. 
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
*A  Parameters:
*     <connection>  ==  (SE_CONNECTION) The connection handle.
*     <table  >     ==  (CHAR*) the result layer name
*     <spatailcol>  ==  (CHAR*) the spatial column name
*     <where  >     ==  (CHAR*) the where clause
*     <shpfilter>   ==  (SE_FILTER*) the spatial filter to be used
*     <queryrelations> == (BOOL) TRUE to print relationship between the
 *                         shape in shpfilter and each feature in test layer;
*                          False to apply the filter and do the spatial query
*E
***********************************************************************/
static LONG S_query_layer(SE_CONNECTION  connection, const CHAR *table,const CHAR* spatialcol,
				     const CHAR* where,SE_FILTER* shpfilter,BOOL queryrelations){

	LONG			result,num_of_column,rowid;
	CHAR			**columns;
	CHAR            shpname[10];
    SHORT           shpname_ind,rowid_ind,shape_ind;
	CHAR			byclause[128];
	SE_LAYERINFO    layer;
	SE_COORDREF     coordref;
	SE_SHAPE        shape;
	SE_QUERYINFO    qinfo;
	SE_STREAM		query_stream;
	BOOL			iscontaining, iswithin,istouching,iscrossing,isoverlapping,isequal;
	LONG			returned_shps_count=0,i;
	BOOL			matched=TRUE;

	if(shpfilter==NULL){
		printf("Invalid filter.\n");
		return SE_FAILURE;
	}

	//prepare a shape object
	result = SE_layerinfo_create (NULL,&layer);
	check_rc_return_on_failure (connection,NULL,result,"SE_layerinfo_create");
	result = SE_coordref_create (&coordref);
	check_rc_return_on_failure (connection,NULL,result,"SE_coordref_create");
	result = SE_layer_get_info (connection,table,spatialcol,layer);
	check_rc_return_on_failure (connection,NULL,result,"SE_layer_get_info");
	result = SE_layerinfo_get_coordref (layer,coordref);
	check_rc_return_on_failure (connection,NULL,result,"SE_layerinfo_get_coordref");
	result = SE_shape_create (coordref,&shape);
	check_rc_return_on_failure (connection,NULL,result,"SE_shape_create");

	//prepare a query  stream
	result=SE_stream_create(connection, &query_stream);
	check_rc_return_on_failure (connection,NULL,result,"SE_stream_create");

	columns = (CHAR **) malloc (4 * sizeof(CHAR *));
	for(i=0;i<3;i++)
		columns[i]=(CHAR *) malloc (SE_MAX_COLUMN_LEN);
	strcpy(columns[0], "ROWIDCOL");
	strcpy(columns[1], "SHPNAME");
	strcpy(columns[2],spatialcol);
	num_of_column=3;
	result = SE_queryinfo_create(&qinfo);
	check_rc_return_on_failure (connection,NULL,result,"SE_queryinfo_create");
	result = SE_queryinfo_set_tables (qinfo, 1, &table, NULL);
	check_rc_return_on_failure (connection,NULL,result,"SE_queryinfo_set_tables");
	result = SE_queryinfo_set_columns (qinfo, num_of_column, (const CHAR**)columns);
	check_rc_return_on_failure (connection,NULL,result,"SE_queryinfo_set_columns");
	result = SE_queryinfo_set_where_clause(qinfo,where);
	check_rc_return_on_failure (connection,NULL,result,"SE_queryinfo_set_where_clause");
	strcpy(byclause,"order by SHPNAME");
	result = SE_queryinfo_set_by_clause(qinfo,byclause);
	check_rc_return_on_failure (connection,NULL,result,"SE_queryinfo_set_by_clause");
	result = SE_stream_query_with_info (query_stream,qinfo);
	check_rc_return_on_failure (NULL,query_stream,result,"SE_stream_query_with_info");

    /*Apply spatial filter if needed:
	  If queryrelations is true, we will only check spatial relationships betwee the 
	  filter shape and each feature in the layer. 
    */
	if(!queryrelations){
		result = SE_stream_set_spatial_constraints (query_stream,SE_OPTIMIZE,FALSE,(SHORT)1,shpfilter);
	    if(result==SE_DBMS_DOES_NOT_SUPPORT){
		    printf("\tDBMS NOT SUPPORTED.\n");
			SE_shape_free(shape);
			SE_layerinfo_free(layer);
			SE_queryinfo_free(qinfo);
			SE_stream_free(query_stream);
			free(columns);
			return result;
	    }
		check_rc_return_on_failure (NULL,query_stream,result,"SE_stream_set_spatial_constraints");
	}

	//binding output
	result = SE_stream_bind_output_column (query_stream,1,&rowid,&rowid_ind);
	check_rc_return_on_failure (NULL,query_stream,result,"SE_stream_bind_output_column");
	result = SE_stream_bind_output_column (query_stream,2,shpname,&shpname_ind);
	check_rc_return_on_failure (NULL,query_stream,result,"SE_stream_bind_output_column");
	result = SE_stream_bind_output_column (query_stream,3,shape,&shape_ind);
	check_rc_return_on_failure (NULL,query_stream,result,"SE_stream_bind_output_column");
	result = SE_stream_execute (query_stream);
	check_rc_return_on_failure (NULL,query_stream,result,"SE_stream_execute");

	if(queryrelations){
		printf("%-10s %-10s %-10s %-10s %-10s %-10s %-10s\n",
					"SHPNAME","CONTAIN","WITHIN","TOUCH","CROSS","OVERLAP","EQUAL");
		printf("======================================================================\n");
	}else
		printf("\tReturned Shapes:");

	returned_shps_count=0;
	while(result==SE_SUCCESS){
	   result = SE_stream_fetch (query_stream);
	   if(result!=SE_FINISHED){
		   check_rc_return_on_failure (NULL,query_stream,result,"SE_stream_fetch");

		   if(queryrelations){//checking spatial relationships only, 
			   iscontaining=SE_shape_is_containing(shape, shpfilter->filter.shape);
			   iswithin=SE_shape_is_within (shape,shpfilter->filter.shape);
			   istouching=SE_shape_is_touching(shape,shpfilter->filter.shape);
			   iscrossing=SE_shape_is_crossing(shape,shpfilter->filter.shape);
			   isoverlapping=SE_shape_is_overlapping(shape,shpfilter->filter.shape);
			   isequal=SE_shape_is_equal(shape,shpfilter->filter.shape);
			   printf("%-10s ",shpname);
			   printf("%-10s ",iscontaining?"YES":"NO");
			   printf("%-10s ",iswithin?"YES":"NO");
			   printf("%-10s ",istouching?"YES":"NO");
			   printf("%-10s ",iscrossing?"YES":"NO");
			   printf("%-10s ",isoverlapping?"YES":"NO");
			   printf("%-10s \n",isequal?"YES":"NO");
		   }else{
			   returned_shps_count++;
			   printf("%s ",shpname);
		   }
	   }//end if(result!=SE_FINISHED)
	}//end while	

	if(!queryrelations){
		if(returned_shps_count==0)
			printf("No Feature selected\n");
		else
			printf("\n");
	}
	//clean up
	SE_coordref_free(coordref);
	SE_shape_free(shape);
	SE_layerinfo_free(layer);
	SE_queryinfo_free(qinfo);
	SE_stream_free(query_stream);
	free(columns);

	return (SE_SUCCESS);
}


/***********************************************************************
*
*N  {S_prepare_filter_shape} -- Prepare a shape for the spatial filter
*
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
*P  Purpose:
*     Prepare a shape for the spatial filter
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
*A  Parameters:
*     <connection>  ==  (SE_CONNECTION) The connection handle.
*     <table  >     ==  (CHAR*) the result layer name
*     <spcol>       ==  (CHAR*) the spatial column name
*     <fshptype  >  ==  (CHAR*) filter shape type
*     <shape>       ==  (OUT:SE_SHAPE*) the result shape
*E
***********************************************************************/
static LONG S_prepare_filter_shape(SE_CONNECTION conn, CHAR* table,CHAR* spcol,SP_FILTER_SHPTYPE fshptype,SE_SHAPE* shape){
    SE_POINT		shape_points[10];
	int				num_of_points,num_of_parts, part_offsets[10];
	SE_LAYERINFO    layer;
	SE_COORDREF     coordref;
	LONG			result;

	//prepare the shape object
	result = SE_layerinfo_create (NULL,&layer);
	check_rc_return_on_failure (conn,NULL,result,"SE_layerinfo_create");
	result = SE_coordref_create (&coordref);
	check_rc_return_on_failure (conn,NULL,result,"SE_coordref_create");
	result = SE_layer_get_info (conn,table,spcol,layer);
	check_rc_return_on_failure (conn,NULL,result,"SE_layer_get_info");
	result = SE_layerinfo_get_coordref (layer,coordref);
	check_rc_return_on_failure (conn,NULL,result,"SE_layerinfo_get_coordref");
	result = SE_shape_create (coordref,shape);
	check_rc_return_on_failure (conn,NULL,result,"SE_shape_create");

	shape_points[0].x=2000;	 shape_points[0].y=4000;
	shape_points[1].x=9000;	 shape_points[1].y=4000;
	shape_points[2].x=9000; shape_points[2].y=9000;
	shape_points[3].x=2000; shape_points[3].y=9000;
	shape_points[4].x=2000; shape_points[4].y=4000;
	num_of_points=5;
	num_of_parts=1;
	part_offsets[0]=0;

	if(fshptype==SP_FILTER_POINT){
		result = SE_shape_generate_point(num_of_points, 
					shape_points, NULL, NULL, *shape);
		check_rc_return_on_failure (conn,NULL,result,"SE_shape_generate_point");
	}else if(fshptype==SP_FILTER_LINE ){
		result = SE_shape_generate_line(num_of_points, num_of_parts,
					part_offsets, shape_points, NULL, NULL, *shape);
		check_rc_return_on_failure (conn,NULL,result,"SE_shape_generate_line");
	}else if(fshptype==SP_FILTER_POLYGON){
		result = SE_shape_generate_polygon(num_of_points, num_of_parts,
					part_offsets, shape_points, NULL, NULL, *shape);
		check_rc_return_on_failure (conn,NULL,result,"SE_shape_generate_polygon");
	}else{
		return SE_FAILURE;
	}

	SE_layerinfo_free(layer);
	SE_coordref_free(coordref);

	return SE_SUCCESS;

}

/***********************************************************************
*
*N  {S_prepare_filter_shape} -- Applied provided filter
*
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
*P  Purpose:
*     Excecute spatial querie using provided filter shape with different 
*     seacg method
*
*  The following filter will be demostrated:
*	SM_ENVP            :Envelopes overlap
*	SM_CP              : Common point 
*	SM_LCROSS          : Line cross 
*	SM_COMMON          : Common edge/line
*	SM_CP_OR_LCROSS    : Common point or line cross 
*	SM_AI_OR_ET        : Edge touch or area intersect 
*	SM_AI              : Area intersect 
*	SM_PC              : Primary contained in secondary
*	SM_SC              : Secondary contained in primary
*	SM_IDENTICAL       : Identical
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
*A  Parameters:
*     <connection>  ==  (SE_CONNECTION) The connection handle.
*     <table  >     ==  (CHAR*) the result layer name
*     <spatailcol>  ==  (CHAR*) the spatial column name
*     <where  >     ==  (CHAR*) the where clause
*     <shpfilter>   ==  (SE_FILTER*) the spatial filter to be used
*     <queryrelations> == (BOOL) TRUE to print relationship between the
 *                         shape in shpfilter and each feature in test layer;
*                           False to apply the filter and do the spatial query
*E
***********************************************************************/
static LONG S_apply_filters(SE_CONNECTION conn, const CHAR *table,const CHAR* shapecol,
						   CHAR* where, SE_FILTER spfilter){
    LONG result;
	printf("\nSearch Method=SM_ENVP\n");
	spfilter.method=SM_ENVP;
	result=S_query_layer(conn , table,shapecol,where,&spfilter,FALSE);

	printf("Search Method=SM_CP\n");
	spfilter.method=SM_CP;
	result=S_query_layer(conn , table,shapecol,where,&spfilter,FALSE);

	printf("Search Method=SM_LCROSS\n");
	spfilter.method=SM_LCROSS;
	result=S_query_layer(conn , table,shapecol,where,&spfilter,FALSE);

	printf("Search Method=SM_COMMON\n");
	spfilter.method=SM_COMMON;
	result=S_query_layer(conn , table,shapecol,where,&spfilter,FALSE);

	printf("Search Method=SM_CP_OR_LCROSS\n");
	spfilter.method=SM_CP_OR_LCROSS;
	result=S_query_layer(conn , table,shapecol,where,&spfilter,FALSE);

	printf("Search Method=SM_AI_OR_ET:\n");
	spfilter.method=SM_AI_OR_ET;
	result=S_query_layer(conn , table,shapecol,where,&spfilter,FALSE);

	printf("Search Method=SM_AI:\n");
	spfilter.method=SM_AI;
	result=S_query_layer(conn , table,shapecol,where,&spfilter,FALSE);

	printf("Search Method=SM_PC:\n");
	spfilter.method=SM_PC;
	result=S_query_layer(conn , table,shapecol,where,&spfilter,FALSE);

	printf("Search Method=SM_SC:\n");
	spfilter.method=SM_SC;
	result=S_query_layer(conn , table,shapecol,where,&spfilter,FALSE);

	printf("Search Method=SM_IDENTICAL:\n");
	spfilter.method=SM_IDENTICAL;
	result=S_query_layer(conn , table,shapecol,where,&spfilter,FALSE);
	return SE_SUCCESS;
}



/***********************************************************************
*
*N  {S_execute_queries} -- Exceute different spatial query againt the 
*                          the target layer.
*
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
*P  Purpose:
*     Funtion to execute different spatial querys against the target layer
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
*A  Parameters:
*     <connection>  ==  (SE_CONNECTION) The connection handle.
*     <table  >     ==  (CHAR*) the result layer name
*     <shapecol>    ==  (CHAR*) the spatial column name
*E
***********************************************************************/
static LONG S_execute_queries(SE_CONNECTION conn,CHAR *table,CHAR* shapecol){
	SE_FILTER       spfilter;
	SE_SHAPE		shape;
	CHAR			where[256];
	LONG			result;

	shape=NULL;
	strcpy(where,"");

	strcpy(spfilter.table,table);
	strcpy(spfilter.column,shapecol);
	spfilter.filter_type = SE_SHAPE_FILTER;
	spfilter.truth = TRUE;

	/*Case 1. Demo point filter */
	printf("Case 1. Point Filter...\n");
	result=S_prepare_filter_shape(conn,table,shapecol,SP_FILTER_POINT,&shape);
	spfilter.filter.shape = shape;

	//show ther relation between the filter shape and features in the layer
	printf("Relationship between filter shape and features in the layer:\n");
	result=S_query_layer(conn , table,shapecol,where,&spfilter,TRUE);
	if(result!=SE_SUCCESS)
		return result;

	//apply different search methods
	result=S_apply_filters(conn,table,shapecol,where,spfilter);
	if(result!=SE_SUCCESS)
		return result;
	SE_shape_free(shape);

	/*Case 2. Demo Line filter */
	printf("\nCase 2. Line Filter...\n");
	result=S_prepare_filter_shape(conn,table,shapecol,SP_FILTER_LINE,&shape);
	spfilter.filter.shape = shape;

	//show ther relation between the filter shape and features in the layer
	printf("Relationship between filter shape and features in the layer:\n");
	result=S_query_layer(conn , table,shapecol,where,&spfilter,TRUE);
	if(result!=SE_SUCCESS)
		return result;

	//apply different search methods
	result=S_apply_filters(conn,table,shapecol,where,spfilter);
	if(result!=SE_SUCCESS)
		return result;
	SE_shape_free(shape);

	/*Case 3. Demo Polygon filter*/
	printf("\nCase 3. Polygon Filter...\n");
	result=S_prepare_filter_shape(conn,table,shapecol,SP_FILTER_POLYGON,&shape);
	spfilter.filter.shape = shape;

	//show ther relation between the filter shape and features in the layer
	printf("Relationship between filter shape and features in the layer:\n");
	result=S_query_layer(conn , table,shapecol,where,&spfilter,TRUE);
	if(result!=SE_SUCCESS)
		return result;

	//apply different search methods
	result=S_apply_filters(conn,table,shapecol,where,spfilter);
	if(result!=SE_SUCCESS)
		return result;
	SE_shape_free(shape);

	return SE_SUCCESS;
}


/***********************************************************************
*
*N  {check_rc_}  -  check the returned code
*
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
*P  Purpose:
*     Check returned sde error code and print the error messages.
***********************************************************************/
void check_rc_(SE_CONNECTION Connection, SE_STREAM Stream, LONG rc, 
				 char *comment, LONG line_no, char* file_name) 
{

	SE_ERROR	error;
	CHAR		error_string [SE_MAX_MESSAGE_LENGTH];
	LONG		temp_rc=SE_FAILURE;


	if ((rc != SE_SUCCESS) && (rc != SE_FINISHED)) 
	{
		error_string[0] = '\0';
		SE_error_get_string (rc, error_string);

	    printf ("%s encountered a %d error:\"%s\" \nat line %ld in file %s\n",comment, rc,error_string, line_no, file_name);

		/*Print extended error info, if any */
		if ((SE_DB_IO_ERROR == rc) | (SE_INVALID_WHERE == rc) | (SE_SSA_FUNCTION_ERROR == rc)) 
		{
			if (NULL != Stream) 
			{
				/* Assume this is a stream error */
				temp_rc = SE_stream_get_ext_error (Stream, &error);
			}else if (NULL != Connection) {
				/*Assume this is a connection error */
				temp_rc = SE_connection_get_ext_error (Connection, &error);
			}
			if (SE_SUCCESS == temp_rc)
			{
					printf("Extended error code: %d, extended error string:\n%s\n",
					error.ext_error, error.err_msg1);
			}
		} /*End SE_DB_IO_ERROR */

	} 
}