/**********************************************************************
 *
 * jdbmnaiveclass.cpp -- 
 * Copyright (C) 1999-2010  The New Zealand Digital Library Project
 *
 * A component of the Greenstone digital library software
 * from the New Zealand Digital Library Project at the
 * University of Waikato, New Zealand.
 *
 * 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; either version 2 of the License, 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 program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *********************************************************************/

#include "jdbmnaiveclass.h"
#include "gsdltools.h"
#include "gsdlunicode.h"
#include "fileutil.h"
#include "stdlib.h"
#include <cstring>

#ifdef __WIN32__
//windows functions
#define popen _popen
#define pclose _pclose
#endif

jdbmnaiveclass::jdbmnaiveclass(const text_t& gsdlhome)
  : dbclass(gsdlhome)
{
  gsdlhome_ = gsdlhome;

  text_t jdbm_jar = filename_cat(gsdlhome_,"lib","java","jdbm.jar");

  text_t jdbm_wrapper_jar = filename_cat(gsdlhome_,"bin","java","JDBMWrapper.jar");

  classpath_ = pathname_cat(jdbm_wrapper_jar,jdbm_jar);
  classpath_cstr_ = to_utf8(classpath_).getcstr();
}

jdbmnaiveclass::~jdbmnaiveclass()
{
  delete [] classpath_cstr_;
}


// returns true if opened
bool jdbmnaiveclass::opendatabase (const text_t &filename, int mode, int num_retrys, 
#ifdef __WIN32__
			      bool need_filelock
#else
                              bool
#endif
			      )
{
  if (openfile_ == filename) {
    return true;
  }

  if (logout == NULL) {
    logout = &cerr;
  }

  // Map the DB mode value into equivalent JDBM 'must_exist' value
  bool must_exist = true; // default

  if (mode == DB_WRITER_CREATE) {
    must_exist = false;
  }

  if (must_exist) {    
    // test that jdbm file exists

    if (!file_exists(filename)) {
      outconvertclass text_t2ascii;
      (*logout) << text_t2ascii 
		<< "Error: JDBM filename " << filename << "does not exist\n";
      return false;   
    }
  }    

  openfile_ = filename;

  // In naive implementation, no connection to database to open, so
  // nothing else to do at this stage
  
  return true;
}


void jdbmnaiveclass::closedatabase ()
{
  // nothing to do in naive implementation
}

// returns file extension string
text_t jdbmnaiveclass::getfileextension ()
{
  return ".jdb";
}


void jdbmnaiveclass::deletekey (const text_t &key)
{
  if (openfile_.empty()) return;

  if (logout == NULL) {
    logout = &cerr;
  }

  // get a utf-8 encoded c string of the unicode key
  char* key_cstr = (to_utf8(key)).getcstr();
  if (key_cstr == NULL) {
    (*logout) << "jdbmnaiveclass: out of memory" << endl;
    return;
  }

  
  // delete the key<
  char* openfile_cstr = (to_utf8(openfile_)).getcstr();

  char cmd[512];
  sprintf(cmd,"java -cp \"%s\" JdbDel \"%s\" %s",classpath_cstr_,
	  openfile_cstr,key_cstr);

  delete [] openfile_cstr;

  //int status = system(cmd); // avoid flashing windows
  int status = gsdl_system(cmd, true, *logout); // true for synchronous call: wait for process to end
  if (status != 0 ) {
    (*logout) << "jdbmnaiveclass: failed to run cmd: " << cmd << endl;
  }

  // free up the key memory
  delete [] key_cstr;
}



// returns true on success
bool jdbmnaiveclass::getkeydata (const text_t& key, text_t &data)
{
  if (openfile_.empty()) return false;
  
  if (logout == NULL) {
    logout = &cerr;
  }

  // get a utf-8 encoded c string of the unicode key
  char* key_cstr = (to_utf8(key)).getcstr();
  if (key_cstr == NULL) {
    (*logout) << "jdbmnaiveclass: out of memory" << endl;

    return false;
  }
  
  // fetch the result
  char* openfile_cstr = (to_utf8(openfile_)).getcstr();

  char cmd[512];
  sprintf(cmd,"java -cp \"%s\" JdbGet \"%s\" %s",classpath_cstr_,
	  openfile_cstr,key_cstr);

  delete [] openfile_cstr;

  FILE* PIN = popen(cmd,"r");

  if (PIN == NULL) {
    (*logout) << "jdbmnaiveclass: failed to run cmd: " << cmd << endl;
  }
  else {
    while (!feof(PIN)) {
      char buf[256];
      fgets(buf,256,PIN);

      /* 
       * debuging code

      cerr << "****## buf = " << buf << endl;

      cerr << "****## buf: ";

      int blen = strlen(buf);
      for (int i=0; i< blen; i++) {
	cerr << "(" << buf[i] << "," << (int)buf[i] << ") ";
      }

      cerr << endl;
      */ // *****


      data.append(buf);
    }

  }

  delete [] key_cstr;
  
  // cerr << "**** data before to_unicode = " << data << endl;

  data = to_uni(data);  // convert to unicode

  pclose(PIN);

  return true;
}


// returns array of keys
text_tarray jdbmnaiveclass::getkeys ()
{
  text_tarray keys;

  if (openfile_.empty()) return keys;

  if (logout == NULL) {
    logout = &cerr;
  }

  char* openfile_cstr = (to_utf8(openfile_)).getcstr();

  char cmd[512];
  sprintf(cmd,"java -cp \"%s\" JdbKeys \"%s\"",classpath_cstr_,
	  openfile_cstr);

  delete [] openfile_cstr;

  FILE* PIN = popen(cmd,"r");

  if (PIN == NULL) {
    (*logout) << "jdbmnaiveclass: failed to run cmd: " << cmd << endl;
  }
  else {
    text_t key = "";

    while (!feof(PIN)) {

      char buf[256];
      fgets(buf,256,PIN);
      key.append(buf);

      keys.push_back(key);
      
    }
  }

  pclose(PIN);

  return keys;
}


// returns true on success
bool jdbmnaiveclass::setkeydata (const text_t &key, const text_t &data)
{
  if (openfile_.empty()) return false;
  
  if (logout == NULL) {
    logout = &cerr;
  }

  // get a utf-8 encoded c string of the unicode key
  char* key_cstr = (to_utf8(key)).getcstr();

  if (key_cstr == NULL) {
    (*logout) << "jdbmnaiveclass: out of memory" << endl;

    return false;
  }

  char* data_cstr = (to_utf8(data)).getcstr();
  if (data_cstr == NULL) {
    (*logout) << "jdbmnaiveclass: out of memory" << endl;

    delete [] key_cstr;
    return false;
  }
  int data_len = strlen(data_cstr);

  char* openfile_cstr = (to_utf8(openfile_)).getcstr();

  char cmd[512];
  sprintf(cmd,"java -cp \"%s\" JdbSet \"%s\" %s %s",
	  classpath_cstr_,openfile_cstr,key_cstr,data_cstr);

  delete [] openfile_cstr;

  //int status = system(cmd); // causes flashing DOS prompt windows
  // https://stackoverflow.com/questions/1597289/hide-console-in-c-system-function-win
  int status = gsdl_system(cmd, true, *logout); // passing false makes it a synchronous call
  if (status != 0) {
    (*logout) << "jdbmnaiveclass: failed to run cmd:" 
	      << cmd << endl;
  }

  delete [] key_cstr;
  delete [] data_cstr;

  return (status == 0);
}



