/*
	File:	sat_svcs.c
	Author:	T.E. Carone

	These are the actual TUXEDO services yet they are only designed to extract the
		data from the TUXEDO buffer, place it in a C structure, call a
		function that actually contains the service logic, and then take
		the results and send them back to the client.

	This separation is commonly done with Tuxedo.  In a three-tier environment it
		is important to have a marshaling function like this one.  It allows
		the developer to insert functionality into the TUXEDO services without
		modifying the service logic.  For example, security exits or
		performance hooks could be inserted here.


	TUXEDO passes the pointer "rqst" that points to the TUXEDO-supplied C structure
		called TPSVCINFO.  The TPSVCINFO data structure is defined as
		follows:

		char		name[32];	Name of service invoked.
		long		flags;		Transaction and reply status.
		char		*data;		The contents of the input buffer.
		long		len;		The length of the input buffer.
		int		cd;		Not used presently.
		long		appkey;		Application-dependent security code.
		CLIENTID	cltid;		TUXEDO-defined client identifier.

	The contents of the input buffer supplied by the client are pointed to by the
		structure element "data".  The length of the input buffer supplied by
		the client is set to the structure element "len".
*/

#include <stdio.h>
#include <malloc.h>
#include <string.h>

/*
	Include the Tuxedo-supplied header file.
*/
#include <atmi.h>

/*
	Include the header file for all three services.
*/
#include <sat.h>


/*------------------------------------------------------------------------------------
	This service retrieves the information for a particular satellite from the
		Oracle database.
*/
void GetTheSatellite(TPSVCINFO *rqst)
{

/*
	Declare the pointers to the input and output structures sent to the function
		that carries out the GetTheSatellite service logic.
*/
	struct GTS_IN	*pGTS_IN;
	struct GTS_OUT	*pGTS_OUT;

/*
	Declare the pointer to the TUXEDO buffer that is returned to the client.  It
		can be argued that this pointer is superfluous as it could be replaced by
		*pGTS_OUT.  However, it is common that the information passed to the
		service logic function is always a subset of that needed by the entire
		service (e.g., security information).  Therefore, it is useful to have
		two structures, one for use internally by the service and one as the
		TUXEDO buffer.
*/
	struct SVC_GTS_OUT	*psvc_GTS;

/*
	Declare a function return code.
*/
	int	iRetCode;

/*
	Retrieve the contents of the input buffer sent by the client from the
		TUXEDO-defined structure TPSVCINFO.
*/
	pGTS_IN = (struct GTS_IN *) malloc(sizeof(struct GTS_IN));
	pGTS_OUT = (struct GTS_OUT *) malloc(sizeof(struct GTS_OUT));
	pGTS_IN = (struct GTS_IN *) rqst->data;

/*
	Invoke the function that queries the Oracle database containing the
		satellite data.
*/
	iRetCode = iGetTheSatellite(pGTS_IN, pGTS_OUT);

/*
	Check to see that query was successful.  If not then this service returns a
		TPFAIL value to the client thereby aborting the transaction.
*/
	if (iRetCode == SAT_FAIL){
		free(pGTS_IN);
		free(pGTS_OUT);
		tpreturn((int) TPFAIL, 0L, (char *) NULL, 0L, (long) SAT_TUXEDO_FLAGS);
	}

/*
	Allocate the output buffer that will be returned to the client.
*/
	psvc_GTS = (struct SVC_GTS_OUT *)tpalloc("VIEW", "SVC_GTS_OUT",
			sizeof(struct SVC_GTS_OUT));

/*
	If there is an error allocating the pointer to the output structure then
		return a TPFAIL to the client.  This will result in the transaction
		being aborted.
*/
	if (psvc_GTS == NULL){
		free(pGTS_IN);
		free(pGTS_OUT);
		tpreturn((int) TPFAIL, 0L, (char *) NULL, 0L, (long) SAT_TUXEDO_FLAGS);
	}
/*
	The query was successful so move the information into the output buffer
		and return the information on the satellite selected to the client.
*/
	psvc_GTS = (struct SVC_GTS_OUT *) pGTS_OUT;
	free(pGTS_IN);
	free(pGTS_OUT);
	tpreturn((int) TPSUCCESS, 0L , (char *) psvc_GTS,
			(long) sizeof(struct SVC_GTS_OUT),
			(long) SAT_TUXEDO_FLAGS);
}


/*------------------------------------------------------------------------------------
	This service calculates a new position for a particular satellite given a
		new future date and time.
*/
void CalcNewSatellitePosition(TPSVCINFO *rqst)
{

/*
	Declare the pointers to the input and output structures sent to the function
		that carries out the CalcNewSatellitePosition service logic.
*/
	struct CNSP_IN	*pCNSP_IN;
	struct CNSP_OUT	*pCNSP_OUT;

/*
	Declare the pointer to the TUXEDO buffer that is returned to the client.
*/
	struct SVC_CNSP_OUT	*psvc_CNSP;

/*
	Declare a function return code.
*/
	int	iRetCode;

/*
	Retrieve the contents of the input buffer sent by the client from the
		TUXEDO-defined structure TPSVCINFO.
*/
	pCNSP_IN = (struct CNSP_IN *) malloc(sizeof(struct CNSP_IN));
	pCNSP_OUT = (struct CNSP_OUT *) malloc(sizeof(struct CNSP_OUT));
	pCNSP_IN = (struct CNSP_IN *) rqst->data;

/*
	Invoke the function that calculates the new position of the satellite.  This
		function is a C wrapper around the FORTRAN function SGP8.  SGP8 is
		a model for near-Earth satellites and can be found in
		pub/space/spacetrk.for at archive.afit.af.mil.  There is an LaTeX
		document there explaining SGP8, its deep-space version (SDP8), and its
		predecessors.  The function iCalcNewSatellitePosition is not included
		herein.
*/
	iRetCode = iCalcNewSatellitePosition(pCNSP_IN, pCNSP_OUT);

/*
	Check to see that the program execution was successful.  If not then
		this service returns a TPFAIL value to the client thereby aborting
		the transaction.
*/
	if (iRetCode == SAT_FAIL){
		free(pCNSP_IN);
		free(pCNSP_OUT);
		tpreturn((int) TPFAIL, 0L, (char *) NULL, 0L, (long) SAT_TUXEDO_FLAGS);
	}

/*
	Allocate the output buffer.
*/
	psvc_CNSP = (struct SVC_CNSP_OUT *)tpalloc("VIEW", "SVC_CNSP_OUT",
			sizeof(struct SVC_CNSP_OUT));

/*
	If there is an error allocating the pointer to the output structure then
		return a TPFAIL to the client.  This will result in the transaction
		being aborted.
*/
	if (psvc_CNSP == NULL)
		free(pCNSP_IN);
		free(pCNSP_OUT);
		tpreturn((int) TPFAIL, 0L, (char *) NULL, 0L, (long) SAT_TUXEDO_FLAGS);

/*
	The calculation was successful so move the new position information into the
		output buffer return to the client.
*/
	psvc_CNSP = (struct SVC_CNSP_OUT *) pCNSP_OUT;
	free(pCNSP_IN);
	free(pCNSP_OUT);
	tpreturn((int) TPSUCCESS, 0L , (char *) psvc_CNSP,
			(long) sizeof(struct SVC_CNSP_OUT), (long) SAT_TUXEDO_FLAGS);
}


/*------------------------------------------------------------------------------------
	This service updates the new position for the chosen satellite.
*/
void UpdateSatellitePosition(TPSVCINFO *rqst)
{

/*
	Declare the pointers to the input and output structures sent to the function
		that carries out the UpdateSatellitePosition service logic.
*/
	struct USP_IN	*pUSP_IN;
	struct USP_OUT	*pUSP_OUT;

/*
	Declare the pointer to the TUXEDO buffer that is returned to the client.
*/
	struct SVC_USP_OUT	*psvc_USP;

/*
	Declare a function return code.
*/
	int	iRetCode;

/*
	Retrieve the contents of the input buffer sent by the client from the
		TUXEDO-defined structure TPSVCINFO.
*/
	pUSP_IN = (struct USP_IN *) malloc(sizeof(struct USP_IN));
	pUSP_OUT = (struct USP_OUT *) malloc(sizeof(struct USP_OUT));
	pUSP_IN = (struct USP_IN *) rqst->data;

/*
	Invoke the function that updates the new position of the satellite in the
		Oracle database.
*/
	iRetCode = iUpdateSatellitePosition(pUSP_IN, pUSP_OUT);

/*
	Check to see that the program execution was successful.  If not then
		this service returns a TPFAIL value to the client thereby aborting
		the transaction.
*/
	if (iRetCode == SAT_FAIL){
		free(pUSP_IN);
		free(pUSP_OUT);
		tpreturn((int) TPFAIL, 0L, (char *) NULL, 0L, SAT_TUXEDO_FLAGS);
	}

/*
	Allocate the UpdateSatellitePosition output buffer.
*/
	psvc_USP = (struct SVC_USP_OUT *)tpalloc("VIEW", "SVC_USP_OUT",
			sizeof(struct SVC_USP_OUT));

/*
	If there is an error allocating the pointer to the output structure then
		return a TPFAIL to the client.  This will result in the transaction
		being aborted.
*/
	if (psvc_USP == NULL){
		free(pUSP_IN);
		free(pUSP_OUT);
		tpreturn((int) TPFAIL, 0L, (char *) NULL, 0L, SAT_TUXEDO_FLAGS);
	}

/*
	The database update was successful so move the new position information into the
		output buffer and return this information to the client.
*/
	psvc_USP = (struct SVC_USP_OUT *) pUSP_OUT;
	free(pUSP_IN);
	free(pUSP_OUT);
	tpreturn((int) TPSUCCESS, 0L , (char *) psvc_USP,
			(long) sizeof(struct SVC_USP_OUT), (long) SAT_TUXEDO_FLAGS);
}




/*
	File:	sat_gts.pc
	Author: T.E. Carone

	This file that is pre-compiled by the Oracle Pro*C/C++ Precompiler into
		sat_gts.c.  It contains the function iGetTheSatellite.  The function
		reads the NORAD orbital information from the database using the name of
		the satellite as the primary key.

*/

EXEC SQL INCLUDE SQLCA;

/*

	This is where the host variables are declared.  All are double precision
		and represent 13 perturbation elements as defined by NORAD.  Their
		precise definition can be found with the data in pub/space at
		archive.afit.af.mil.

	SAT_NAME is the name of the satellite.

	NORAD_PARAMn (n = 1-13) are the 13 perturbation elements.

	SQLSTATE is a host variable which contains a status indicator that is populated
		by Oracle during the query and is returned to the program for error
		processing.

*/

EXEC SQL BEGIN DECLARE SECTION;

DCL	SAT_NAME	CHAR(20);

DCL	NORAD_PARM1	DOUBLE PRECISION;
DCL	NORAD_PARM2	DOUBLE PRECISION;
DCL	NORAD_PARM3	DOUBLE PRECISION;
DCL	NORAD_PARM4	DOUBLE PRECISION;
DCL	NORAD_PARM5	DOUBLE PRECISION;
DCL	NORAD_PARM6	DOUBLE PRECISION;
DCL	NORAD_PARM7	DOUBLE PRECISION;
DCL	NORAD_PARM8	DOUBLE PRECISION;
DCL	NORAD_PARM9	DOUBLE PRECISION;
DCL	NORAD_PARM10	DOUBLE PRECISION;
DCL	NORAD_PARM11	DOUBLE PRECISION;
DCL	NORAD_PARM12	DOUBLE PRECISION;
DCL	NORAD_PARM13	DOUBLE PRECISION;

DCL	SQLSTATE	CHAR(5);

EXEC SQL END DECLARE SECTION;

int iGetTheSatellite(struct GTS_IN *inbuf, GTS_OUT *outbuf)
{
	strcpy(SAT_NAME, inbuf->NameOfSatellite);
	EXEC SQL SELECT SATELLITE.PARM1,
			SATELLITE.PARM2,
			SATELLITE.PARM3,
			SATELLITE.PARM4,
			SATELLITE.PARM5,
			SATELLITE.PARM6,
			SATELLITE.PARM7,
			SATELLITE.PARM8,
			SATELLITE.PARM9,
			SATELLITE.PARM10,
			SATELLITE.PARM11,
			SATELLITE.PARM12,
			SATELLITE.PARM13
		INTO	:NORAD_PARM1,
			:NORAD_PARM2,
			:NORAD_PARM3,
			:NORAD_PARM4,
			:NORAD_PARM5,
			:NORAD_PARM6,
			:NORAD_PARM7,
			:NORAD_PARM8,
			:NORAD_PARM9,
			:NORAD_PARM10,
			:NORAD_PARM11,
			:NORAD_PARM12,
			:NORAD_PARM13,
		FROM	SATELLITE
		WHERE	SATELLITE.NAME = :SAT_NAME;
/*
	If the value of SQLSTATE is zero then the query was successful.  The values
		of the NORAD perturbation elements are moved to the output buffer to
		be returned to the GetTheSatellite TUXEDO service.
*/
	if (strcmp(SQLSTATE,'00000') == 0){
		outbuf->p1 = NORAD_PARM1;
		outbuf->p2 = NORAD_PARM2;
		outbuf->p3 = NORAD_PARM3;
		outbuf->p4 = NORAD_PARM4;
		outbuf->p5 = NORAD_PARM5;
		outbuf->p6 = NORAD_PARM6;
		outbuf->p7 = NORAD_PARM7;
		outbuf->p8 = NORAD_PARM8;
		outbuf->p9 = NORAD_PARM9;
		outbuf->p10 = NORAD_PARM10;
		outbuf->p11 = NORAD_PARM11;
		outbuf->p12 = NORAD_PARM12;
		outbuf->p13 = NORAD_PARM13;

		return (0);
	else
		return (-1);
	}
}


/*
	File:	sat_usp.pc
	Author: T.E. Carone

	This file is pre-compiled by the Oracle Pro*C/C++ Precompiler into
		sat_usp.c.  It takes new orbital positions and updates the current
		values in the database with these new values.  A time stamp is
		set in the database to the current value of SYSDATE.

*/

EXEC SQL INCLUDE SQLCA;

/*
	This is where the host variables are declared.  All are double precision
		except for the name of the satellite.  The fields updated in the
		database are the six coordinates of the satellite (three
		position and three velocity).

	SATE_NAME is the name of the satellite.

	SAT_X_POS, SAT_Y_POS, and SAT_Z_POS are the three positions of the
		satellite.

	SAT_X_VELOCITY, SAT_Y_VELOCITY, and SAT_Z_VELOCITY are the three
		velocities of the satellite.

	SQLSTATE is the host variable which contains a status indicator that is
		populated by Oracle during the update and is returned to the
		program for error processing.
*/

EXEC SQL BEGIN DECLARE SECTION;

DCL	SAT_NAME		CHAR(20);

DCL	SAT_X_POS		DOUBLE PRECISION;
DCL	SAT_Y_POS		DOUBLE PRECISION;
DCL	SAT_Z_POS		DOUBLE PRECISION;
DCL	SAT_X_VELOCITY		DOUBLE PRECISION;
DCL	SAT_Y_VELOCITY		DOUBLE PRECISION;
DCL	SAT_Z_VELOCITY		DOUBLE PRECISION;

DCL	SQLSTATE		CHAR(5);

EXEC SQL END DECLARE SECTION;

int iUpdateSatellitePosition(struct USP_IN *inbuf, struct USP_OUT *outbuf)
{

	strcpy(SAT_NAME, inbuf->NameOfSatellite);
	EXEC SQL UPDATE SATELLITE SET
			POS_VELOCITY_TIMEDATE = SYSDATE
			X_POS = :SAT_X_POS
			Y_POS = :SAT_Y_POS
			Z_POS = :SAT_Z_POS
			X_VELOCITY = :SAT_X_VELOCITY
			Y_VELOCITY = :SAT_Y_VELOCITY
			Z_VELOCITY = :SAT_Z_VELOCITY
		WHERE	SATELLITE.NAME = :SAT_NAME;
	if (strcmp(SQLSTATE,'00000') == 0){
		outbuf->xpos = SAT_X_POS;
		outbuf->ypos = SAT_Y_POS;
		outbuf->zpos = SAT_Z_POS;
		outbuf->xvel = SAT_X_VELOCITY;
		outbuf->yvel = SAT_Y_VELOCITY;
		outbuf->zvel = SAT_Z_VELOCITY;

		return (0);

	else

		return (-1);
	}
}
