/*******************************************************************************
*                                                                       
*N  {unic_sample.c}  --  Example of Unicode-Enabled SDE C Application.
*	    Since SDE_UNICODE is defined, CHAR is mapped to SE_WCHAR in the sample 
*                                                                       
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
* How to compile:: 
*       This program provides programming examples of Unicode enabled  
*       ArcSDE C client application. IBM ICU library is used to manipulate
*       UNICODE characters in this sample. For more information about ICU,
*       please visit http://www-306.ibm.com/software/globalization/icu/index.jsp
*
*
*     1. Add {ibm ICU installation directory}/lib to your library paths
*	  2. Add {ibm ICU installation directory}/include to your include paths
*     3. Add {$SDEHOME}/lib to your library paths;
*     4. Compile and link with icuuc.lib and other needed SDE libraries
*E
*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
* Usage:
*     unic_sample {server} {instance} {database} {user} {password} {keywords}  
*
*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*X  Legalese:
*
* Copyright � 2006 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
****************************************************************************/
#ifndef SDE_UNICODE
#define SDE_UNICODE
#endif

#include <stdlib.h>
#include <stdio.h>
#include "sdetype.h"
#include "sdeerno.h"
#include "unicode/ustring.h"

/* Function macros */
#define check_rc(c,s,rc,f) \
	{if(rc!= SE_SUCCESS) {check_rc_(c,s,rc,f,__LINE__,__FILE__);}}
#define check_rc_return_on_failure(c,s,rc,f) \
	{if(rc!= SE_SUCCESS) {check_rc_(c,s,rc,f,__LINE__,__FILE__);return rc; }}

static LONG S_create_layer(SE_CONNECTION ,CHAR *,CHAR *,LONG);
static void check_rc_(SE_CONNECTION, SE_STREAM, LONG,const char *,LONG, const char* ) ;


/***********************************************************************
*P  Purpose:
*     Demostrating how to create Unicode C API application.
*     (1) connect to SDE server
*     (2) create a empty layer
*E
***********************************************************************/
int main( int argc, char *argv[]) {

	CHAR   			server[SE_MAX_SERVER_LEN], 
       	       		user[32], 
       	       		passwd[SE_MAX_PASSWORD_LEN], 
					database[SE_MAX_DATABASE_LEN],
					instance[SE_MAX_INSTANCE_LEN],
					keyword[SE_MAX_KEYWORD_LEN],
					layer_name[SE_MAX_TABLE_LEN];
	LONG			rc,layer_mask;
	SE_CONNECTION 	conn;
	SE_ERROR 		error;
	SE_LAYERINFO	layer = NULL;

  	if( argc != 7 ) { 
    		printf("ERROR, Usage: %s {server} {instance} {database} {user} {passwd} {storage keyword}\n", argv[0]);
    		exit(-1);
 	}
    
	//Get arguments from the command line
	u_uastrcpy(server,argv[1]);
	u_uastrcpy(instance,argv[2]);
	u_uastrcpy(database,argv[3]);
	u_uastrcpy(user,argv[4]);
	u_uastrcpy(passwd,argv[5]);
	u_uastrcpy(keyword,argv[6]);

	//Initialize a ArcSDE connection
	printf("creating a connection to server......\n");
	rc = SE_connection_create( server, instance, database, user, passwd, &error, &conn );
	if(rc!=SE_SUCCESS){
		check_rc(conn, NULL, rc, "SE_connection_create");
		exit(-1);
	}
	printf("\tConnection created!\n");

    //Create a polygon layer named SAMPLE_LAYER
	printf("\nCreate a layer named SAMPLE_LAYER...\n");
	u_uastrcpy(layer_name,"SAMPLE_LAYER");
	layer_mask=SE_AREA_TYPE_MASK | SE_NIL_TYPE_MASK;
    rc=S_create_layer(conn,layer_name,keyword,layer_mask);
	if(rc==SE_SUCCESS)
		printf("\tSample Layer created!\n");
	else{
		printf("\nUNABLE TO CREATE THE SAMPLE LAYER!\n");
		SE_connection_free(conn);
		return -1;
	}
 
	//Free resource
	SE_connection_free(conn);
	return 0;
}

/***********************************************************************
*
*N  {S_create_layer}  -  create an empty layer
*
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
*P  Purpose:
*     This function create an empty layer.
*E
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
*A  Parameters:
*   connection   <INPUT>  == the connection to SDE
*   layer_name   <INPUT>  == name of the layer to be created
*   keyword		 <INPUT>  == storage keyword
*   layer_type   <INPUT>  == layer type mask
*	RETURN return SE_SUCCESS if no error found;otherwise return the error code.	
*E
***********************************************************************/
static LONG S_create_layer(SE_CONNECTION connection,CHAR *layer_name,CHAR *keyword,LONG layer_type)
{
	SE_LAYERINFO        layer;
	SHORT               number_of_columns;
	SE_COLUMN_DEF       column_definitions[8];
	SE_COORDREF         coordref;
	LONG                result;
	SE_REGINFO          registration;
	CHAR				reg_desc[128],lay_desc[128];
	CHAR				ROWID_COL[SE_MAX_COLUMN_LEN],
						SPATIAL_COL[SE_MAX_COLUMN_LEN];

	//Initiate the ROWID and sptial column name
	u_uastrcpy(ROWID_COL,"ROWID_COL");
	u_uastrcpy(SPATIAL_COL,"SHAPE");

	/* Create the base table. */
	number_of_columns = 7;
	u_uastrcpy(column_definitions[0].column_name,"STR_COL");
	column_definitions[0].sde_type = SE_STRING_TYPE;
	column_definitions[0].size = 60;
	column_definitions[0].decimal_digits = -1;
	column_definitions[0].nulls_allowed = FALSE;

	u_uastrcpy(column_definitions[1].column_name,"INT16_COL");
	column_definitions[1].sde_type = SE_INT16_TYPE;
	column_definitions[1].size = 0;
	column_definitions[1].decimal_digits = 0;
	column_definitions[1].nulls_allowed = TRUE;

	u_uastrcpy (column_definitions[2].column_name,"INT32_COL");
	column_definitions[2].sde_type = SE_INT32_TYPE;
	column_definitions[2].size = 0;
	column_definitions[2].decimal_digits = 0;
	column_definitions[2].nulls_allowed = TRUE;

	u_uastrcpy (column_definitions[3].column_name,"FLOAT32_COL");
	column_definitions[3].sde_type = SE_FLOAT32_TYPE;
	column_definitions[3].size = 0;
	column_definitions[3].decimal_digits = 0;
	column_definitions[3].nulls_allowed = TRUE;

	u_uastrcpy (column_definitions[4].column_name,"FLOAT64_COL");
	column_definitions[4].sde_type = SE_FLOAT64_TYPE;
	column_definitions[4].size = 0;
	column_definitions[4].decimal_digits = 0;
	column_definitions[4].nulls_allowed = TRUE;

	u_uastrcpy (column_definitions[5].column_name,"DATE_COL");
	column_definitions[5].sde_type = SE_DATE_TYPE;
	column_definitions[5].size = 0;
	column_definitions[5].decimal_digits = 0;
	column_definitions[5].nulls_allowed = TRUE;

	u_uastrcpy (column_definitions[6].column_name,"BLOB_COL");
	column_definitions[6].sde_type = SE_BLOB_TYPE;
	column_definitions[6].size = 0;
	column_definitions[6].decimal_digits = 0;
	column_definitions[6].nulls_allowed = TRUE;

	//delete the table if already existed
	result = SE_table_delete(connection,layer_name);
	if(result!=SE_TABLE_NOEXIST)
		check_rc_return_on_failure (connection,NULL,result,"SE_table_delete");
	//create the base table
	result = SE_table_create (connection,layer_name,number_of_columns,
							column_definitions,keyword);
	check_rc_return_on_failure (connection,NULL,result,"SE_table_create");

	/* Alter the registration of the table to have 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,layer_name,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");

	u_uastrcpy(reg_desc,"A SAMPLE TABLE");
	result = SE_reginfo_set_description (registration,reg_desc );
	check_rc_return_on_failure (connection,NULL,result,"SE_reginfo_set_description");

	result = SE_reginfo_set_rowid_column (registration,ROWID_COL,
							   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");

	u_uastrcpy(lay_desc,"A SAMPLE LAYER");
	result = SE_layerinfo_set_description(layer,lay_desc);
	check_rc_return_on_failure (connection,NULL,result,"SE_layerinfo_set_description");

	result = SE_layerinfo_set_shape_types (layer,layer_type);
	check_rc_return_on_failure (connection,NULL,result,"SE_layerinfo_set_shape_types");

	result = SE_layerinfo_set_spatial_column (layer,layer_name,SPATIAL_COL);
	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_layerinfo_free(layer);
	return(SE_SUCCESS);
} //end of S_create_layer          

/***********************************************************************
*
*N  {check_rc_}  -  check error messages
*
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
*P  Purpose:
*     Check and print error SDE message.
*E
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
*A  Parameters:
*   connection   <INPUT>  == connection to SDE
*   stream       <INPUT>  == SDE stream 
*   rc   		 <INPUT>  == the return code to be checked
*   func_name    <INPUT>  == function name 
*	line_no      <INPUT>  == line number
*   file_name    <INPUT>  == source file name
*E
***********************************************************************/
static void check_rc_(SE_CONNECTION conn, SE_STREAM stream, LONG rc, 
                      const char *func_name,LONG line_no, const char* file_name) 
{

	SE_ERROR	error;
	CHAR		error_string [SE_MAX_MESSAGE_LENGTH];
	LONG		temp_rc;
	char		ansi_str[SE_MAX_MESSAGE_LENGTH];

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

        printf ("\n\n %s encountered a %d error: \"%s\" at line %ld in file \n%s\n",func_name, rc,ansi_str, 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 == conn) 
			{
				/* Assume this is a stream error */
				temp_rc = SE_stream_get_ext_error (stream, &error);
			}else {
				/*Assume this is a connection error */
				temp_rc = SE_connection_get_ext_error (conn, &error);
			}
			if (SE_SUCCESS == temp_rc)
			{
					u_austrcpy(ansi_str,error.err_msg1);
					printf("Extended error code: %d, extended error string:\n%s\n",
					error.ext_error,ansi_str);
			}
		} /* End SE_DB_IO_ERROR */
	} /* End if((rc */
} /*  End check_rc_ */