// Copyright (c) 1997 by Jim Lynch.
// Copyright (c) 2010-2012 by Philipp Schafft.
// This software comes with NO WARRANTY WHATSOEVER.
//
// This program is free software; you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation; version 2 dated June, 1991, or, at your
//    option, any LATER version.
//
//    This program 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 General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this software; see the file COPYING.  If not, write to
//    the Free Software Foundation, 51 Franklin Street, Fifth Floor,
//    Boston, MA 02110-1301, USA.

#include "gdbm-stuff.h"
#include "main.h"

#include <iostream>
#include <sstream>
#include <errno.h>
#include <grp.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <malloc.h>

long lastKeyAssigned;

long CStringToLong(const char *string)
{
  istrstream in(string);
  long result;

  in >> result;

  return result;
}

char *LongToNewCString(long theLong)
{
  ostrstream out;

  out << theLong;

  return MakeCStringCopy(out);
}

char *MakeCStringCopy(const string &orig)
{
  char *tmp = new char[orig.size() + 1];

  if(tmp)
  {
    strcpy(tmp, orig.c_str());
  }

  return tmp;
}

char *MakeCStringCopy(const char *orig)
{
  char *tmp = new char[strlen(orig) + 1];

  if(tmp)
  {
    strcpy(tmp, orig);
  }

  return tmp;
}

// this copies the current contents of an ostrstream to a C string
// whose bytes are allocated w/ new. (so free them w/ delete[])

char *MakeCStringCopy(ostrstream &orig)
{
  int stringSize = orig.pcount();
  char *tmp = new char[stringSize + 1];

  if(tmp)
  {
    memcpy(tmp, orig.str(), stringSize);
    tmp[stringSize] = '\0';

    orig.freeze(0);
  }

  return tmp;
}

GDBMFile OpenFile(const char * dbfile)
{
  GDBMFile result;
  struct stat dummy;
  
  if(stat(dbfile, &dummy) == -1) // stat failed?
    {
      if(errno == ENOENT) // file not found?
	{
	  // create the file here, fully; ready for animals.
	  
	  mode_t saveMode = umask(0);
	  
	  result = gdbm_open
                      (
		        dbfile,
			0 /* use file system blk size */,
			GDBM_WRCREAT,
			0660,
			0 /* use default fatal_func */
		      );
	  
	  umask(saveMode);
	  
	  if(! result) // can't create?
	    {
	      // either or both of gdbm_errno and errno may be set now.
	      // Deal with it...
	      
	      cout << progName << ": OpenFile: file " << dbfile
		   << ": errno=" << errno;
	      cout << "; gdbm_errno=" << gdbm_errno << endl;
	      
	      exit(-1);
	    }
	  else
	    {
	      // new gdbm file. Add initial infrastructure.
	      
	      datum key;
	      datum lastAddedKey;
	      
	      key.dptr = "last";
	      key.dsize = 5;
	      
	      lastAddedKey.dptr = "0";
	      lastAddedKey.dsize = 2;
	      
	      gdbm_store(result, key, lastAddedKey, GDBM_INSERT);
	    }
	} // endif(errno == ENOENT)
      else
	{
	}
    }
  else
    {
      int chmod_res;
      
      result = gdbm_open
	            (
	              dbfile,
		      0 /* use system blk size */,
		      GDBM_WRITER,
		      0660,
		      0 /* use default fatal_func */
		    );
      
      if(! result) // can't open existing db file?
	{
	  // either or both of gdbm_errno and errno may be set now.
	  // Deal with it...
	  
	  cout << progName << ": OpenFile: file " << dbfile << ": errno=" << errno;
	  cout << "; gdbm_errno=" << gdbm_errno << endl;
	  
	  exit(-1);
	}
      else
	{
	  // file is open for update; get "last" into lastKeyAssigned
	  
	  datum key;
	  datum value;
	  
	  key.dptr = "last";
	  key.dsize = 5;
	  
	  value = gdbm_fetch(result, key);
	  
	  if(! value.dptr) // should not be null; if it is, "last" is missing
	    {
	      cout << "'last' key value missing: database seems corrupt"<< endl;
	      
	      gdbm_close(result);
	      exit(-1);
	    }
	  
	  istrstream *theLastStream = new istrstream(value.dptr);
	  
	  (*theLastStream) >> lastKeyAssigned;
	  
	  free(value.dptr);
	  
	  delete theLastStream;
	}
    }
  
  return result;
}

void CloseFile(GDBMFile handle)
{
  gdbm_close(handle);
}

void SetLast(GDBMFile handle, const string &newKey)
{
  datum content;
  datum key = 
  {
    "last",
    5
  };
  
  content.dptr = MakeCStringCopy(newKey);
    
  content.dsize = strlen(content.dptr) + 1;
  
  gdbm_store(handle, key, content, GDBM_REPLACE);
  
  delete[] content.dptr;
}

string GetLast(GDBMFile handle)
{
  string result;
  datum content;
  datum key = 
  {
    "last",
    5
  };
  
  content = gdbm_fetch(handle, key);
  // amarin 748 0276
  if(content.dptr)
  {
    result = MakeCStringCopy(content.dptr);
    free(content.dptr);
  }
  
  return result;
}

int IsAnimal(GDBMFile handle, const string &theKey)
{
  int result = 0;
  datum key;
  datum content;
  
  key.dptr = MakeCStringCopy(theKey);
  key.dsize = strlen(key.dptr) + 1;
  
  content = gdbm_fetch(handle, key);
  
  delete[] key.dptr;
  
  if(content.dptr)
    {
      if(*content.dptr == 'a')
	result = 1;
      
      free(content.dptr);
    }
  
  return result;
}

