/**********************************************************************
 *
 * historydb.cpp -- 
 * Copyright (C) 1999  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 "historydb.h"
#include "fileutil.h"
#include "cgiutils.h"
#include "recptproto.h"
#include "recptprototools.h"
#include "dbclass.h"

#if defined(USE_GDBM)
#include "gdbmclass.h"
#define DBCLASS gdbmclass
//#define DBFNAME "history.gdb"

#elif defined(USE_JDBM)
#include "jdbmnaiveclass.h"
#define DBCLASS jdbmnaiveclass
//#define DBFNAME "history.jdb"

#elif defined(USE_SQLITE)
#include "sqlitedbclass.h"
#define DBCLASS sqlitedbclass
//#define DBFNAME "history.litedb"

#elif defined(USE_MSSQL)
#include "mssqldbclass.h"
#define DBCLASS mssqldbclass
//#define DBFNAME "history.msdb"

#else
#error "Unable to compile Greenstone. Need at least one database backend enabled."
#endif


#define MAX_RECORDS 20
#define HIST_SEP ';'


dbclass* get_history_db_ptr (const text_t& gsdlhome)
{
  // Create a dbclass of the correct type
  dbclass *historydb = NULL;

  historydb = new DBCLASS(gsdlhome);

  return historydb;
}


// returns true on success (in which case historyinfo will contain
// the information for this history)
bool get_history_info (const text_t &userid, text_tarray &historyinfo, 
		       const text_t &gsdlhome, ostream &logout) {

  bool result = false;

  // Create a dbclass of the correct type
  dbclass *historydb = get_history_db_ptr(gsdlhome);
  if (historydb == NULL) return false;
  text_t historyfile = filename_cat(gsdlhome, "etc", "history") + historydb->getfileextension();
  
  // open the history database  
  if (historydb->opendatabase(historyfile, DB_READER, 1000, true)) {
    // get history list
    text_t historyresult;
    
    historydb->getkeydata(userid, historyresult);
    
    if (historyresult != "") { //  there are entries, process them
      
      splitchar(historyresult.begin(), historyresult.end(), '\n', historyinfo);
      result = true;
    }
    historydb->closedatabase();
    
  } else {
    outconvertclass text_t2ascii;
    logout << text_t2ascii << "couldn't open history database " << historyfile << "\n";
  }

  delete historydb;
  return result;
}


// returns true on success
// changed to only save 20 records per user, numbers not included
// only save if there are already entries there, or if display=true
bool set_history_info (const text_t &userid, const text_t &history, const text_t &gsdlhome, bool display) {

  bool result = false;

  // Create a dbclass of the correct type
  dbclass *historydb = get_history_db_ptr(gsdlhome);
  if (historydb == NULL) return false;
  text_t historyfile = filename_cat(gsdlhome, "etc", "history") + historydb->getfileextension();
  
  text_t oldhistoryresult;
  text_t newhistoryresult;
  int numentries=0;

  // open the history database  
  if (!historydb->opendatabase(historyfile, DB_READER, 1000, true)) {
    // not created yet
    oldhistoryresult="";
    if (!display) return true; // dont need to save
  }
  else {

    // get history list
   if (! historydb->getkeydata(userid, oldhistoryresult)) {
     oldhistoryresult="";
     if (!display) return true; // dont need to save
   }
   historydb->closedatabase();
  }

  text_tarray entries;
  
  if (oldhistoryresult!="") {
    splitchar(oldhistoryresult.begin(), oldhistoryresult.end(), '\n', entries);
    numentries = entries.size();
    if (numentries >= MAX_RECORDS) numentries = MAX_RECORDS-1;
  }
  
  // open for writing
  if (!historydb->opendatabase(historyfile, DB_WRITER_CREATE, 1000, true)) return false;
  
  // add on new linethe new record to the front of the list, then add the
  // appropriate entries from the old stuff 
  newhistoryresult += history;
  newhistoryresult += "\n";
  for (int i=0; i<numentries;++i) {
    newhistoryresult +=  entries[i]+"\n";
  }
  
  if (historydb->setkeydata(userid, newhistoryresult)) 
    result=true; 
  
  historydb->closedatabase();
  delete historydb;
  return result;
}

// deletes all a users history
bool delete_all_history_info (const text_t &userid, const text_t &gsdlhome) {

  // Create a dbclass of the correct type
  dbclass *historydb = get_history_db_ptr(gsdlhome);
  if (historydb == NULL) return false;
  text_t historyfile = filename_cat(gsdlhome, "etc", "history") + historydb->getfileextension();
  
  // open the history database  
  if (!historydb->opendatabase(historyfile, DB_WRITER, 1000, true)) return false;

  historydb->deletekey(userid);
  historydb->closedatabase();
  delete historydb;
  return true;
  
}

// retrieves the value of one of the arguments
void parse_saved_args(text_t &args, text_t key, text_t &value)
{
  text_t::iterator here = args.begin();
  text_t::iterator end = args.end();
  text_t::iterator it;
  while (here != end) {
    if(*here==key[0]) {
      it=findchar(here, end, '=');
      if (it==end) {
	value=""; return;
      }
      text_t entry = substr(here, it);
      if (entry==key) {
	here=it+1;
      	it=findchar(here, end, HIST_SEP);
	value = substr(here, it);
	return;
      }
    }
    ++here;
  }// while
}

// retrieves the value of all of the arguments
void parse_saved_args(text_t &args, infodbclass &info)
{
  text_t::iterator here = args.begin();
  text_t::iterator end = args.end();
  text_t::iterator it;
  text_tarray values;

  splitchar(here, end, HIST_SEP, values);
  
  text_tarray::iterator start = values.begin();
  text_tarray::iterator stop = values.end();

  text_t key;
  text_t value;
  while(start!=stop) {

    here=(*start).begin();
    end=(*start).end();
    it=findchar(here, end, '=');
    if (it!=end) {
      key = substr(here, it);
      value = substr(it+1, end);
      
      info[key]=value;
    }
    ++start;
  }
}


void split_saved_query(text_t &query, text_t &numdocs, text_t &cgiargs)
{
  text_t::iterator begin = query.begin();
  text_t::iterator end = query.end();
  
  while (*begin >='0'&& *begin <='9') { // get the digits for numdocs
    numdocs.push_back(*begin);
    ++begin;
  }          
                 
  if (*begin == '+') {  // get the + if there
    numdocs.push_back(*begin);
    ++begin;
  }
  if (*begin == ':') { // have the old format - previous bit was record number
    numdocs.clear();
    ++begin;

    while(*begin >='0' && *begin <='9') { // get the digits
      numdocs.push_back(*begin);
      ++begin;
    }
    if (*begin == '+') { // get the + if there
      numdocs.push_back(*begin);
      ++begin;
    }
  }
  cgiargs += (substr(begin, end));  // put rest of query into cgiargs

}

void format_user_info (text_t &historyargs, text_t &userinfo,  
		       cgiargsclass &args,
		       recptprotolistclass *protos, ostream &logout) 
{
  text_tset metadata;
  userinfo.clear();

  infodbclass argsinfo;
  parse_saved_args(historyargs, argsinfo);
  text_t collect = argsinfo["c"];
  if (collect=="") {
    userinfo="";
    return;
  }
 
  if (collect != args["c"]) {
    userinfo += collect+", ";
  }
  
  if (argsinfo["h"] != args["h"]) {
  
    recptproto *collectproto = protos->getrecptproto(collect,logout);
    if (collectproto == NULL) {
      userinfo="";
      return;
    }
    metadata.insert(argsinfo["h"]);
    FilterResponse_t response;
    
    get_info("collection", collect, args["l"], metadata, false, collectproto, response, logout);
    text_t index = response.docInfo[0].metadata[argsinfo["h"]].values[0];
    if (!index.empty()) {
      userinfo += index+", ";
    }
  }

  if (argsinfo["b"] != args["b"] || argsinfo["t"] != args["t"]) {
    if (argsinfo["b"]=="0") { // simple mode
      if (argsinfo["t"]=="0") {
	userinfo += " _texthallwords_, ";
      }
      else if (argsinfo["t"]=="1"){
	userinfo += " _texthsomewords_, ";
      }
      
    } 
    else if (argsinfo["b"] == "1") { // advanced mode
      if (argsinfo["t"]=="0") {
	userinfo += " _texthboolean_, ";
      }
      else if (argsinfo["t"]=="1") {
	userinfo += " _texthranked_, ";
      }
    }
  }
  
  if (argsinfo["k"] != "" && argsinfo["k"] != args["k"]) {
    text_t options;
    // the text translations are the wrong way round
    if (argsinfo["k"]=="1") {
      userinfo += " _texthcaseoff_, ";
    }
    else if (argsinfo["k"]=="0") {
      userinfo += " _texthcaseon_, ";
    }
  }

  if (argsinfo["s"] != "" && argsinfo["s"] != args["s"]) {
    if (argsinfo["s"]=="0") {
      userinfo += " _texthstemoff_, ";
    }
    else if (argsinfo["s"]=="1") {
      userinfo += " _texthstemon_, ";
    }
  }

}
