/*#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 *#+	Mumps Compiler Run-Time Support Functions
 *#+	Copyright (c) A.D. 2001, 2002, 2003, 2010, 2011
 *#+    by Kevin C. O'Kane
 *#+
 *#+	kc.okane@gmail.com
 *#+
 *#+	This library is free software; you can redistribute it and/or
 *#+	modify it under the terms of the GNU Lesser General Public
 *#+	License as published by the Free Software Foundation; either
 *#+	version 2.1 of the License, or (at your option) any later version.
 *#+
 *#+	This library is distributed in the hope that it will be useful,
 *#+	but WITHOUT ANY WARRANTY; without even the implied warranty of
 *#+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *#+	Lesser General Public License for more details.
 *#+
 *#+   You should have received a copy of the GNU Lesser General Public
 *#+	License along with this library; if not, write to the Free Software
 *#+	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *#+
 *#+	http://www.cs.uni.edu/~okane
 *#+	http://www.omahadave.com
 *#+
 *#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 *#+
 *#+	Some of this code was originally written in Fortran
 *#+	which will explain the odd array and label usage,
 *#+	especially arrays beginning at index 1.
 *#+
 *#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 *#+
 *#+	This is the native btree global array handler from the
 *#+	Mumps Compiler.
 *#+
 *#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

#include <stdio.h>

#include <unistd.h>

#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>

#include <mumpsc/stateVector.h>
#include <mumpsc/global.h>
#include <mumpsc/defines.h>
#include <mumpsc/btree.h>
#include <mumpsc/keyfix.h>

// dbtype becomes #define NATIVE or POSTGRESDB depending on the DB in use

@dbtype@

// client becomes #define CLIENT if --with-client specified in configure

@client@

// serverbuf becomes the size of the buffer used to send msgs to/from the server

@serverbuf@

// serverdir is the location of the mumps server -> /etc/mumps by default

#ifdef CLIENT
int GBL_FLG=0;
void sigcap(int) {
      GBL_FLG=1;
      }
#endif

// main global array interface

int Mglobal (const int g, unsigned char key[], unsigned char bd[], struct MSV * svPtr) {

//	void keyfix (unsigned char *vxd, struct MSV * svPtr);
      void unpad(unsigned char *key, struct MSV *svPtr);

      void sigint(int);
      static int CloseFlg=0;

// ---------------------------------------------------------------------------------------------
// client mode code begins here
// this code is active if you compiled in client/server/mode
// ---------------------------------------------------------------------------------------------

#ifdef CLIENT
      static int f1=0;
      static int fdes=-1;
      static int rfdes=-1;
      static char netBuf0[SERVERBUF+1];
      static char netBuf1[SERVERBUF];

      if (g==CLOSE) {
            printf("\nClosing connection with server.....\n");
            if (fdes>=0) close (fdes);
            fdes=-1;
            if (rfdes>=0) close (rfdes);
            rfdes=-1;
            return 0;
            }

      signal(SIGINT,sigcap);

      if (!f1) {  // no connection?

            // begin looking for an available pipe

            f1=1;

            fdes=open("@serverdir@/""mps0",O_WRONLY );
            if (flock(fdes,LOCK_EX | LOCK_NB)==-1) {
                  close(fdes);
                  fdes=-1;
                  }
            else {
                  if (fdes != -1)
                        goto c1;
                  }

            f1++;
            fdes=open("@serverdir@/" "mps1",O_WRONLY);
            if (flock(fdes,LOCK_EX | LOCK_NB)==-1) {
                  close(fdes);
                  fdes=-1;
                  }
            else {
                  if (fdes != -1) goto c1;
                  }

            f1++;
            fdes=open("@serverdir@/" "mps2",O_WRONLY);
            if (flock(fdes,LOCK_EX | LOCK_NB)==-1) {
                  close(fdes);
                  fdes=-1;
                  }
            else {
                  if (fdes != -1) goto c1;
                  }

            f1++;
            fdes=open("@serverdir@/" "mps3",O_WRONLY);
            if (flock(fdes,LOCK_EX | LOCK_NB)==-1) {
                  close(fdes);
                  fdes=-1;
                  }
            else {
                  if (fdes != -1) goto c1;
                  }

            f1++;
            fdes=open("@serverdir@/" "mps4",O_WRONLY);
            if (flock(fdes,LOCK_EX | LOCK_NB)==-1) {
                  close(fdes);
                  fdes=-1;
                  }
            else {
                  if (fdes != -1) goto c1;
                  }

            f1++;
            fdes=open("@serverdir@/" "mps5",O_WRONLY);
            if (flock(fdes,LOCK_EX | LOCK_NB)==-1) {
                  close(fdes);
                  fdes=-1;
                  }
            else {
                  if (fdes != -1) goto c1;
                  }

            printf("No connection to host\n");
            sigint(100);

            }

c1:

      strcpy(&netBuf0[1],(char *)key);
      netBuf0[0]=g;
      write(fdes,netBuf0,SERVERBUF);

      strcpy(netBuf1,(char *)bd);
      write(fdes,netBuf1,SERVERBUF);

      if (f1==1) rfdes=open("@serverdir@/" "rmps0",O_RDONLY);
      else if (f1==2) rfdes=open("@serverdir@/" "rmps1",O_RDONLY);
      else if (f1==3) rfdes=open("@serverdir@/" "rmps2",O_RDONLY);
      else if (f1==4) rfdes=open("@serverdir@/" "rmps3",O_RDONLY);
      else if (f1==5) rfdes=open("@serverdir@/" "rmps4",O_RDONLY);
      else if (f1==6) rfdes=open("@serverdir@/" "rmps5",O_RDONLY);

      if (rfdes<0) {
            printf("Return pipe error in globalb\n");
            sigint(100);
            }

      read(rfdes,netBuf0,SERVERBUF);
      strcpy( (char *) key, &netBuf0[1]);

      read(rfdes,netBuf1,SERVERBUF);
      strcpy( (char *) bd, netBuf1);

      close(rfdes);
      rfdes=-1;

      signal(SIGINT,sigint);
      if (GBL_FLG) raise(SIGINT);
      return netBuf0[0];
#endif

// ---------------------------------------------------------------------------------------------
// native mode begins here
// ---------------------------------------------------------------------------------------------

#ifdef POSTGRESSDB
      keyfix(key);
      return btree(g,key,bd,svPtr);
#endif

      if (g==RETRIEVE) {
            int i;
            keyfix(key);
            i=btree(g,key,bd,svPtr);
            return i;
            }

      if (g==STORE) {
            int i;
            keyfix(key);
            i=btree(g,key,bd,svPtr);
            return i;
            }

      if (g==ORDERNEXT || g==ORDERPREV ||
                  g==NEXT || g==PREVIOUS) {	 /* prepare NEXT/ORDER cases */
            int b,j,gx=g;
            unsigned char hold[STR_MAX];
            j=strlen( (const char *) key);
            if (g!=ORDERNEXT && g!=ORDERPREV &&
                        key[j-1]==1 && key[j-2]=='1' &&
                        /* $next -1 case */
                        key[j-3]=='-' && key[j-4]==1) {
                  key[j-3]=2;
                  key[j-2]=1;
                  key[j-2]=0;
                  key[j-1]=0;
                  strcpy( (char *) bd,"");
                  j--;
                  }
            else if (g==NEXT || g==ORDERNEXT) {
                  key[j-1]=2;
                  key[j]=0;
                  key[j+1]=0;
                  key[j+2]=0;
                  key[j+3]=0;
                  strcpy( (char *) bd,"");
                  }
            else if (g==ORDERPREV && key[j-1]==1 && key[j-2]==1) {
                  key[j-1]='~';
                  }
            gx=g;
            if (gx==NEXT) gx=XNEXT;
            else if (gx==ORDERNEXT) gx=XNEXT;
            else if (gx==ORDERPREV) gx=PREVIOUS;
            keyfix(key);
            strcpy( (char *) hold, (const char * ) key);
            b=btree(gx,key,bd,svPtr);
            if (g==NEXT || g==ORDERNEXT || g==ORDERPREV) {
                  j=strlen( (const char *) hold)-1;
                  if (hold[j]==1) j--;
                  for (; j>0 && hold[j]!=1; j--);
                  if (strncmp(( const char  * ) hold,( const char  * ) bd,j)!=0 ||
                              hold[j]!=1 ||
                              bd[j]!=1) {
                        if (g==NEXT) strcpy( (char *) bd,"-1");
                        else strcpy( (char *) bd,"");
                        return 0;
                        }
                  //            if (j>0) strcpy( (char *) bd, (const char * ) &bd[j+1]); STRCPY
                  if (j>0) {
                        unsigned char * x=bd;
                        unsigned char * y= &bd[j+1];
                        // STRCPY
                        for (; *y != 0; x++,y++) *x = *y;
                        *x=0;
                        }
                  for (j=0; bd[j]!=1&&bd[j]!=0; j++);
                  bd[j]=0;
                  unpad(bd,svPtr);
                  if (strlen( (const char *) bd)==0) {
                        if (g==NEXT) strcpy( (char *) bd,"-1");
                        else strcpy( (char *) bd,"");
                        return 0;
                        }
                  return 1;
                  }
            }

      if (g==GKILL) {
            return btree(g,key,bd,svPtr);
            }

      if (g==XNEXT) {
            int i;
            keyfix(key);
            return btree(g,key,bd,svPtr);
            }

      if (g==CLOSE) {
            //      if (CloseFlg) return EXIT_SUCCESS;
            //      CloseFlg=1;
            btree(g,key,bd,svPtr);
            return EXIT_SUCCESS;
            }

      return 0;
      }
