/*******************************************************************************
*                                                                       
*N  {geom_spatial_ops.c}  -- demonstrates spatial operations between shapes  
*   
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*P  Purpose:
*    This sample C program demonstrates different spatial operations between shapes 
*
*    The following spatial operations will be demonstated in this sample:
*
*      (1) Differce using SE_shape_difference();
*      (2) Symmetrical_Difference using SE_shape_symmetrical_difference();
*      (3) Intersect using SE_shape_intersect();
*      (4) Overlay using SE_shape_overlay();
*      (5) Union using SE_shape_union();
*    
*E                                                                 
*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
* How to compile:: 
*	 Please refer section "Build C Samples" in the SDE sample
*
*E
*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
* Usage:
*     geom_spatial_ops {server} {instance} {database} {user} {password}
*
*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*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 "sdetype.h"
#include "sdeerno.h"

typedef enum {
  SP_DIFF/*SE_shape_difference*/,
  SP_SYMDIFF/*SE_shape_symmetrical_difference*/,
  SP_INTERSECT/*SE_shape_intersect*/,
  SP_OVERLAY/*SE_shape_overlay*/,
  SP_UNION/*SE_shape_union*/
} SP_OPERATION;

/* 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_excute_sp_operation(SE_SHAPE  *shps,short num_of_shp,SP_OPERATION op);

LONG main(int argc, char *argv[])
{
	CHAR   			*server, 
       	       		*user, 
					*passwd, 
					*database,
					*instance;
	SE_CONNECTION 	conn;
	SE_ERROR 		error;
	SE_COORDREF     coordref;
	SE_SHAPE        shps[4];
	SE_ENVELOPE		env;
	int				i;
	LONG			result;
	CHAR			shp_desc[512];
	LONG			shp_size;

	if(argc<6){
		printf("Usage %s <server> <instance> <database> <user> <password>",argv[0]);
		exit(1);
	}
	server=argv[1];
	instance=argv[2];
	database=argv[3];
	user=argv[4];
	passwd=argv[5];

  	result = SE_connection_create( server, instance, database, user, passwd, &error, &conn );
	check_rc_return_on_failure (conn,NULL,result,"SE_connection_create");

	/*prepare four shapes*/
	result = SE_coordref_create (&coordref);
	check_rc_return_on_failure (NULL,NULL,result,"SE_coordref_create");
	result = SE_coordref_set_xy (coordref,0.0,0.0,100.0);
	check_rc_return_on_failure (NULL,NULL,result,"SE_coordref_set_xy");
	for(i=0;i<4;i++){
		result = SE_shape_create (coordref,&shps[i]);
		check_rc_return_on_failure (NULL,NULL,result,"SE_shape_create");
	}
	/*******************************************************************
      In this sample, we will use following polygons to show the demos 
			|--------|
			|  P3    |
			|	 |---|---|
			|----|---|   |
			|  P2|	 |   |
			|	 |   | P4|
			|----|---|   |
			|  P1|___|___|
			|	   	   |
			|----------|
	********************************************************************/
	/* Initialize test polygons*/
	printf("Prepare Test Shapes:\n\n");
	env.minx=100.0;
	env.miny=100.0;
	env.maxx=300.0;
	env.maxy=300.0;
    result = SE_shape_generate_rectangle(&env,shps[0]);
	env.minx=100.0;
	env.miny=300.0;
	env.maxx=300.0;
	env.maxy=500.0;
    result = SE_shape_generate_rectangle(&env,shps[1]);
	env.minx=100.0;
	env.miny=500.0;
	env.maxx=300.0;
	env.maxy=700.0;
    result = SE_shape_generate_rectangle(&env,shps[2]);
	env.minx=200.0;
	env.miny=200.0;
	env.maxx=400.0;
	env.maxy=600.0;
    result = SE_shape_generate_rectangle(&env,shps[3]);
	for(i=0;i<4;i++)
	{
		result=SE_shape_get_text_size(shps[i],&shp_size);
		result=SE_shape_as_text (shps[i],shp_size+1,shp_desc);
		printf(" Poly%d:\n  %s\n",i+1,shp_desc);
	}

	//Perform the tests
	for(i=SP_DIFF;i<SP_UNION;i++)
		S_excute_sp_operation(shps,4,i);

	return SE_SUCCESS;

}

/***********************************************************************
*
*N  {S_excute_sp_operation}  -  execute specified spatial operation
*
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
*P  Purpose:
*     execute specified spatial operation
*E
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
*A  Parameters:
*     <shps>		==  (SE_SHAPE*) A list of shapes
*     <num_of_shp > ==  (short) number of shapes in the shps list
*     <SP_OPERATION>==  (SP_OPERATION) define the type of operation
*E
***********************************************************************/
static LONG S_excute_sp_operation(SE_SHAPE  *shps,short num_of_shp,SP_OPERATION op)
{
	int				i,j,r;
	SE_COORDREF     coordref;
	SE_SHAPE        shp=NULL,primary_remainder=NULL,secondary_remainder=NULL;
	SE_SHAPE		*new_shapes;/*a shape array*/
	LONG			result,num_result_shapes;
	CHAR			shp_desc[512];
	LONG			shp_size;

	//we are assuming all shapes are in same coordref
	result = SE_coordref_create (&coordref);
	check_rc_return_on_failure (NULL,NULL,result,"SE_coordref_create");
	result= SE_shape_get_coordref(shps[0],coordref);
	check_rc_return_on_failure (NULL,NULL,result,"SE_shape_get_coordref");
	result = SE_shape_create (coordref,&shp);
	check_rc_return_on_failure (NULL,NULL,result,"SE_shape_create");
	result = SE_shape_create (coordref,&primary_remainder);
	check_rc_return_on_failure (NULL,NULL,result,"SE_shape_create");
	result = SE_shape_create (coordref,&secondary_remainder);
	check_rc_return_on_failure (NULL,NULL,result,"SE_shape_create");

	printf("\n******************************************************************");
	switch(op){
	  case SP_DIFF/*SE_shape_difference*/:
		  printf("\n* Shape Difference                                                ");
		  break;
	  case SP_SYMDIFF/*SE_shape_symmetrical_difference*/:
		  printf("\n* Shape Symmetrical Difference                                    ");
		  break;
	  case SP_INTERSECT/*SE_shape_intersect*/:
		  printf("\n* Shape Intersect                                                 ");
		  break;
	  case SP_OVERLAY/*SE_shape_overlay*/:
		  printf("\n* Shape Overlay                                                   ");
		  break;
	  case SP_UNION/*SE_shape_union*/:
		  printf("\n* Shape Union                                                     ");
		  break;
	}
	printf("\n******************************************************************\n");

	for(i=0;i<num_of_shp;i++)
	{
		for(j=0;j<num_of_shp;j++)
		{
			switch(op){
			  case SP_DIFF/*SE_shape_difference*/:
				  printf("\nResult of (POLY%d DIFF POLY%d):",i+1,j+1);
				  result=SE_shape_difference (shps[i],shps[j],shp);
				  check_rc_return_on_failure (NULL,NULL,result,"SE_shape_difference");
				  if(SE_shape_is_nil (shp))
					  printf(" NIL shape\n");
				  else{
					  result=SE_shape_get_text_size(shp,&shp_size);
					  result=SE_shape_as_text (shp,shp_size+1,shp_desc);
					  printf("\n %s\n",shp_desc);
				  }
				  break;
			  case SP_SYMDIFF/*SE_shape_symmetrical_difference*/:
				  printf("\nResult of (POLY%d SYMDIFF POLY%d):",i+1,j+1);
				  result=SE_shape_symmetrical_difference (shps[i],shps[j],shp);
				  check_rc_return_on_failure (NULL,NULL,result,"SE_shape_symmetrical_difference");
				  if(SE_shape_is_nil (shp))
					  printf(" NIL shape\n");
				  else{
					  result=SE_shape_get_text_size(shp,&shp_size);
					  result=SE_shape_as_text (shp,shp_size+1,shp_desc);
					  printf("\n %s\n",shp_desc);
				  }
				  break;
			  case SP_INTERSECT/*SE_shape_intersect*/:
				  printf("\nResult of (POLY%d INTERSECT POLY%d):",i+1,j+1);
				  result=SE_shape_intersect (shps[i],shps[j],&num_result_shapes,&new_shapes);
				  check_rc_return_on_failure (NULL,NULL,result,"SE_shape_intersect");
				  if(num_result_shapes==0)
					  printf("Nothing generated\n");
				  else{
					  for(r=0;r<num_result_shapes;r++)
					  {
						  result=SE_shape_get_text_size(new_shapes[r],&shp_size);
						  result=SE_shape_as_text (new_shapes[r],shp_size+1,shp_desc);
						  printf("\n %s\n",shp_desc);
					  }
				  }
				  SE_shape_free_array (num_result_shapes,new_shapes);
				  break;
			  case SP_OVERLAY/*SE_shape_overlay*/:
				  printf("\nResult of (POLY%d OVERLAY POLY%d):\n",i+1,j+1);
				  result=SE_shape_overlay (shps[i],shps[j],&num_result_shapes,primary_remainder,&new_shapes,secondary_remainder);
				  check_rc_return_on_failure (NULL,NULL,result,"SE_shape_overlay");
				  if(SE_shape_is_nil (primary_remainder))
					  printf(" Primary_remainder:NIL shape\n");
				  else{				  
					  result=SE_shape_get_text_size(primary_remainder,&shp_size);
					  result=SE_shape_as_text (primary_remainder,shp_size+1,shp_desc);
					  printf(" Primary_remainder:\n  %s\n",shp_desc);
				  }

				  printf(" Common shapes:");
				  if(num_result_shapes==0)
					  printf(" No common shape\n");
				  else{
					  for(r=0;r<num_result_shapes;r++)
					  {
						  result=SE_shape_get_text_size(new_shapes[r],&shp_size);
						  result=SE_shape_as_text (new_shapes[r],shp_size+1,shp_desc);
						  printf("\n   %s\n",shp_desc);
					  }
				  }
				  SE_shape_free_array (num_result_shapes,new_shapes);

				  if(SE_shape_is_nil (secondary_remainder))
					  printf(" Secondary_remainder:NIL shape\n");
				  else{	
					  result=SE_shape_get_text_size(secondary_remainder,&shp_size);
					  result=SE_shape_as_text (secondary_remainder,shp_size+1,shp_desc);
					  printf(" Secondary_remainder\n  %s\n",shp_desc);
				  }

				  break;
			  case SP_UNION/*SE_shape_union*/:
				  printf("\nResult of (POLY%d UNION POLY%d):",i+1,j+1);
				  result=SE_shape_union (shps[i],shps[j],shp);
				  if(SE_shape_is_nil (shp))
					  printf(" NIL shape\n");
				  else{
					  check_rc_return_on_failure (NULL,NULL,result,"SE_shape_union");
					  result=SE_shape_get_text_size(shp,&shp_size);
					  result=SE_shape_as_text (shp,shp_size+1,shp_desc);
					  printf("\n %s\n",shp_desc);
				  }
				  break;
			}
		}
	}

	SE_coordref_free(coordref);
	SE_shape_free(shp);

	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 */

	} 
}