#include "c.h" 
#include "strings.h"
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/param.h>
#include "tcl.h"
#include "tclInt.h"
#include "tclUnix.h"

/* Postgres/libpq includes */

#include "tmp/libpq-fe.h"
#include "tmp/libpq-fs.h"

extern char query_buffer[];  /* Max postgres buffer size */
extern char dbnamebuffer[];  /* database name */
extern char *lastquery; /* last string passed to PQexec */
extern PortalBuffer *current_portal;
extern char *current_portal_name; /* most recent portal name used */

/* PQ_RetrieveCmd --
 *
 *	Allows use of conventional POSTGRES PostQUEL syntax
 *      inside tcl/tk for retrieves
 *
 * Results:
 *	A standard Tcl result.
 *
 *----------------------------------------------------------------------
 */

	/* ARGSUSED */
int
PGTK_RetrieveCmd(dummy, interp, argc, argv)
    ClientData dummy;			/* Not used. */
    Tcl_Interp *interp;			/* Current interpreter. */
    int argc;				/* Number of arguments. */
    char **argv;			/* Argument strings. */
{

  char *result, *tmp, c;
  int i = 0, j = 0;
  bool InAComment = false;

  if (argc < 2) {
    Tcl_AppendResult(interp, "wrong # args: should be a normal POSTQUEL retrieve command", (char *) NULL);
    return TCL_ERROR;
  }

  if (dbnamebuffer[0] == '\0') {
    strcpy(dbnamebuffer,getenv("USER"));
    fprintf(stderr,"No database set: assumining database is %s\n", 
	    dbnamebuffer);
    PQsetdb(dbnamebuffer);
    tmp = Tcl_SetVar(interp, "CURRENTDATABASE", dbnamebuffer,
		     TCL_GLOBAL_ONLY);
  }

  sprintf(query_buffer,"retrieve "); 

  for (i = 1; i < argc; i++) {
    strcat (query_buffer," ");
    strcat (query_buffer, argv[i]);
  }

  lastquery = Tcl_SetVar(interp, "LASTQUERY", argv[1], TCL_GLOBAL_ONLY );

  /* ship it off to Postgres */
  result = PQexec(query_buffer);


  /* check the results and set Tcl return string */
  switch(result[0]) {
        case 'A':
        case 'P':
            Tcl_AppendResult(interp, &(result[1]), (char *) NULL);
	    current_portal_name = Tcl_SetVar(interp, "CURRENTPORTAL", 
					     &(result[1]),
					     TCL_GLOBAL_ONLY);
	    return (Tcl_VarEval(interp, "PGTKtuplelist ", 
				current_portal_name, (char *)NULL));
            break;

        case 'E':
            Tcl_AppendResult(interp, "Postgres Fatal Error: ", 
			     &(result[1]), (char *) NULL);
            return TCL_ERROR;
            break;

        case 'C':
            Tcl_AppendResult(interp, &(result[1]), (char *) NULL);
	    return TCL_OK;
            break;

        case 'I':
            PQFlushI(1);
            Tcl_AppendResult(interp, &(result[0]), (char *) NULL);
            break;

        case 'R':
            Tcl_AppendResult(interp, "Postgres Error: ", &(result[1]), (char *) NULL);
            return TCL_ERROR;
            break;

        default:
            Tcl_AppendResult(interp, "Unknown Postgres Return Code: ", 
			     &(result[0]), (char *) NULL);
	  }
  
  return TCL_OK;
}

/* PGTK_APostQuelCmd --
 *
 *	Allows use of conventional POSTGRES PostQUEL syntax
 *      inside tcl/tk for appends, replaces, and deletes
 *
 * Results:
 *	A standard Tcl result.
 *
 *----------------------------------------------------------------------
 */

	/* ARGSUSED */
int
PGTK_APostQuelCmd(dummy, interp, argc, argv)
    ClientData dummy;			/* Not used. */
    Tcl_Interp *interp;			/* Current interpreter. */
    int argc;				/* Number of arguments. */
    char **argv;			/* Argument strings. */
{

  char *result, *tmp, c;
  int i = 0, j = 0;
  bool InAComment = false;

  if (argc < 2) {
    Tcl_AppendResult(interp, "wrong # args: should be a normal POSTQUEL ",argv[1], " command", (char *) NULL);
    return TCL_ERROR;
  }

  if (dbnamebuffer[0] == '\0') {
    strcpy(dbnamebuffer,getenv("USER"));
    fprintf(stderr,"No database set: assumining database is %s\n", 
	    dbnamebuffer);
    PQsetdb(dbnamebuffer);
    tmp = Tcl_SetVar(interp, "CURRENTDATABASE", dbnamebuffer,
		     TCL_GLOBAL_ONLY);
  }

  /* handle the command name clashes */
  if (strcmp(argv[0],"pappend") == 0 || strcmp(argv[0],"pgappend") == 0 )
    sprintf(query_buffer,"append "); 
  else  if (strcmp(argv[0],"pdestroy") == 0 || strcmp(argv[0],"pgdestroy") == 0 )
    sprintf(query_buffer,"destroy "); 
  else  if (*argv[0] == 'P' && *(argv[0]+1) == 'Q') 
    sprintf(query_buffer,"%s ", (argv[0]+2)); 
  else
    sprintf(query_buffer,"%s ",argv[0]); 

  for (i = 1; i < argc; i++) {
    strcat (query_buffer," ");
    strcat (query_buffer, argv[i]);
  }

  /* ship it off to Postgres */
  result = PQexec(query_buffer);

  /* check the results and set Tcl return string */
  switch(result[0]) {
        case 'A':
        case 'P':
            Tcl_AppendResult(interp, &(result[1]), (char *) NULL);
            break;

        case 'E':
            Tcl_AppendResult(interp, "Postgres Fatal Error: ", 
			     &(result[1]), (char *) NULL);
            return TCL_ERROR;
            break;

        case 'C':
            Tcl_AppendResult(interp, &(result[1]), (char *) NULL);
            break;

        case 'I':
            PQFlushI(1);
            Tcl_AppendResult(interp, &(result[0]), (char *) NULL);
            break;

        case 'R':
            Tcl_AppendResult(interp, "Postgres Error: ", 
			     &(result[1]), (char *) NULL);
            return TCL_ERROR;
            break;

        default:
            Tcl_AppendResult(interp, "Unknown Postgres Return Code: ", 
			     &(result[0]), (char *) NULL);
	  }

  
  return TCL_OK;
}
  

/* PGTK_XActCmd --
 *
 *	Allows use of conventional POSTGRES PostQUEL syntax
 *      inside tcl/tk for begin, end and abort
 *
 * Results:
 *	A standard Tcl result.
 *
 *----------------------------------------------------------------------
 */

	/* ARGSUSED */
int
PGTK_XActCmd(dummy, interp, argc, argv)
    ClientData dummy;			/* Not used. */
    Tcl_Interp *interp;			/* Current interpreter. */
    int argc;				/* Number of arguments. */
    char **argv;			/* Argument strings. */
{

  char *result, *tmp, c;
  int i = 0, j = 0;
  bool InAComment = false;

  if (argc != 1) {
    Tcl_AppendResult(interp, "wrong # args: should be a normal POSTQUEL ",argv[0], " command", (char *) NULL);
    return TCL_ERROR;
  }

  if (dbnamebuffer[0] == '\0') {
    strcpy(dbnamebuffer,getenv("USER"));
    fprintf(stderr,"No database set: assumining database is %s\n", 
	    dbnamebuffer);
    PQsetdb(dbnamebuffer);
    tmp = Tcl_SetVar(interp, "CURRENTDATABASE", dbnamebuffer,
		     TCL_GLOBAL_ONLY);
  }

  if (*argv[0] == 'P' && *(argv[0]+1) == 'Q') 
    sprintf(query_buffer,"%s", (argv[0]+2)); 
  else
    sprintf(query_buffer,"%s",argv[0]); 

  /* ship it off to Postgres */
  result = PQexec(query_buffer);

  /* check the results and set Tcl return string */
  switch(result[0]) {
        case 'A':
        case 'P':
            Tcl_AppendResult(interp, &(result[1]), (char *) NULL);
            break;

        case 'E':
            Tcl_AppendResult(interp, "Postgres Fatal Error: ", 
			     &(result[1]), (char *) NULL);
            return TCL_ERROR;
            break;

        case 'C':
            Tcl_AppendResult(interp, &(result[1]), (char *) NULL);
            break;

        case 'I':
            PQFlushI(1);
            Tcl_AppendResult(interp, &(result[0]), (char *) NULL);
            break;

        case 'R':
            Tcl_AppendResult(interp, "Postgres Error: ", 
			     &(result[1]), (char *) NULL);
            return TCL_ERROR;
            break;

        default:
            Tcl_AppendResult(interp, "Unknown Postgres Return Code: ", 
			     &(result[0]), (char *) NULL);
	  }

  
  return TCL_OK;
}
  


/***************************************************************************
 * Construct a list of retrieved items from the database
 **************************************************************************/
int
PGTKtuplelist(dummy, interp, argc, argv)
    ClientData dummy;			/* Not used. */
    Tcl_Interp *interp;			/* Current interpreter. */
    int argc;				/* Number of arguments. */
    char **argv;			/* Argument strings. */
{

    char nbuffer[20];
    int rule;
    PortalBuffer *p;
    int j,k,g,m,n,t,x;
    int temp, temp1;
    char *arg1, *arg2 ;
    char n_groups[40], fields[8192], tuplebuff[8192];
    char *valptr;

    if (argc == 1) {
       /* set some defaults if no portal specified */
       arg1 = "blank";
    }
    else arg1 = argv[1];

    p = current_portal = PQparray(arg1);

    if (p == NULL) {
      Tcl_AppendResult(interp, "ERROR: No Portal named ", arg1, 
		       " found. Was fetch done?", (char *) NULL);
      return TCL_ERROR;
    }

    g = PQngroups (p);

    t = 0;
    temp = 0;

    for (k =0; k < g; k++) {
	n = PQntuplesGroup(p,k);  /* zero based index.  */
	m = PQnfieldsGroup(p,k);

        if (n == 0) { /* no results */
          Tcl_AppendElement(interp, "0 items retrieved", 0);
          return TCL_OK;
        }

	if ( m > 0 ) {  /* only print tuples with at least 1 field.  */
                /* set the field names element */
		sprintf(fields,"%d {FIELDS %d}", n, m);
		for (x=0; x < m; x++) {
		  strcat(fields," ");
		  sprintf(tuplebuff,"{%s %d}",PQfname(p,t,x), PQftype(p,t,x));
		  strcat(fields, tuplebuff);
		}

		Tcl_AppendElement(interp,fields, 0);


		/* get the tuples */
		for (x = 0; x < n; x++) {
		  tuplebuff[0] = '\0';
		  for (j = 0; j < m; j++) {
		    valptr = PQgetvalue(p,t+x,j);
		    if (valptr == NULL) valptr = "(null)";
		    if (strchr(valptr, ' ') != NULL) {
		      sprintf(fields,"{%s}",valptr);
		      strcat(tuplebuff,fields);
		    }
		    else {
		      strcat(tuplebuff,valptr);
		    }
		    if (j+1 != m)
		      strcat(tuplebuff," ");
		  }
		  Tcl_AppendElement(interp,tuplebuff, 0);
		}
		t += n;
	      }
      }
    
    return TCL_OK;
  }


