/*****
* runhistory.in
*
* Runtime functions for history operations.
*
*****/

pair     => primPair()
picture* => primPicture()
stringarray* => stringArray()


#include "array.h"
#include "mathop.h"
#include "builtin.h"

#if defined(_WIN32)
#include <io.h>
#define isatty _isatty
#else
#include <unistd.h>
#endif

using namespace camp;
using namespace settings;
using namespace vm;
using namespace run;

typedef array stringarray;
using types::stringArray;

namespace camp {
bool allowRender=false;
}

#if defined(HAVE_LIBREADLINE) && defined(HAVE_LIBCURSES)
#include <readline/readline.h>
#include <readline/history.h>

struct historyState {
 bool store;
 HISTORY_STATE state;
};

typedef mem::map<const string, historyState> historyMap_t;
historyMap_t historyMap;
static HISTORY_STATE history_save;

// Store a deep copy of the current readline history in dest.
void store_history(HISTORY_STATE *dest)
{
 HISTORY_STATE *src=history_get_history_state();
 if(src) {
   *dest=*src;
   for(Int i=0; i < src->length; ++i)
     dest->entries[i]=src->entries[i];
   free(src);
 }
}

stringarray* get_history(Int n)
{
 int N=intcast(n);
 if(N <= 0) N=history_length;
 else N=Min(N,history_length);
 array *a=new array((size_t) N);
 int offset=history_length-N+1;
 for(int i=0; i < N; ++i) {
   HIST_ENTRY *last=history_get(offset+i);
   string s=last ? last->line : "";
   (*a)[i]=s;
 }
 return a;
}

string historyfilename(const string &name)
{
 return historyname+"_"+name;
}

#endif

namespace run {

extern string emptystring;

#if defined(HAVE_LIBREADLINE) && defined(HAVE_LIBCURSES)

#endif

void cleanup()
{
#if defined(HAVE_LIBREADLINE) && defined(HAVE_LIBCURSES)
 store_history(&history_save);
 int nlines=intcast(getSetting<Int>("historylines"));
 for(historyMap_t::iterator h=historyMap.begin(); h != historyMap.end();
     ++h) {
   history_set_history_state(&h->second.state);
   if(h->second.store) {
     stifle_history(nlines);
     write_history(historyfilename(h->first).c_str());
     unstifle_history();
   }
 }
 history_set_history_state(&history_save);
#endif
#ifdef HAVE_LIBGSL
 trans::GSLrngFree();
#endif
}
}

// Autogenerated routines:


// Return the last n lines of the history named name.
stringarray* history(string name, Int n=1)
{
#if defined(HAVE_LIBREADLINE) && defined(HAVE_LIBCURSES)
 bool newhistory=historyMap.find(name) == historyMap.end();

 string filename;

 if(newhistory) {
   filename=historyfilename(name);
   std::ifstream exists(filename.c_str());
   if(!exists) return new array(0);
 }

 store_history(&history_save);
 HISTORY_STATE& history=historyMap[name].state;
 history_set_history_state(&history);

 if(newhistory)
   read_history(filename.c_str());

 array *a=get_history(n);

 store_history(&history);
 history_set_history_state(&history_save);

 return a;
#else
 unused(&n);
 return new array(0);
#endif
}

// Return the last n lines of the interactive history.
stringarray* history(Int n=0)
{
#if defined(HAVE_LIBREADLINE) && defined(HAVE_LIBCURSES)
 return get_history(n);
#else
 unused(&n);
 return new array(0);
#endif
}

// Prompt for a string using prompt, the GNU readline library, and a
// local history named name.
string readline(string prompt=emptystring, string name=emptystring,
               bool tabcompletion=false)
{
 bool stdinIsTty=isatty(STDIN_FILENO);
 bool hasInpipe=getSetting<Int>("inpipe") >= 0;
 if(!(stdinIsTty || hasInpipe))
 {
   return emptystring;
 }
#if defined(HAVE_LIBREADLINE) && defined(HAVE_LIBCURSES)
 interact::init_readline(tabcompletion);

 store_history(&history_save);
 bool newhistory=historyMap.find(name) == historyMap.end();
 historyState& h=historyMap[name];
 HISTORY_STATE& history=h.state;
 history_set_history_state(&history);

 if(newhistory)
   read_history(historyfilename(name).c_str());

 static char *line=NULL;
 /* Return the memory to the free pool
    if the buffer has already been allocated. */
 if(line) {
   free(line);
   line=NULL;
 }

 /* Get a line from the user. */
 bool allowRenderSave=allowRender;
 allowRender=false;
 line=readline(prompt.c_str());
 allowRender=allowRenderSave;

 if(!line) cout << endl;

 history_set_history_state(&history_save);

 return line ? string(line) : emptystring;
#else
 cout << prompt;
 string s;
 getline(cin,s);
 unused(&tabcompletion); // Avoid unused variable warning message.
 return s;
#endif
}

// Save a string in a local history named name.
// If store=true, store the local history in the file historyfilename(name).
void saveline(string name, string value, bool store=true)
{
#if defined(HAVE_LIBREADLINE) && defined(HAVE_LIBCURSES)
 store_history(&history_save);
 bool newhistory=historyMap.find(name) == historyMap.end();
 historyState& h=historyMap[name];
 h.store=store;
 HISTORY_STATE& history=h.state;
 history_set_history_state(&history);

 if(newhistory)
   read_history(historyfilename(name).c_str());

 if(value != "") {
   add_history(value.c_str());
   if(store) {
     std::ofstream hout(historyfilename(name).c_str(),std::ios::app);
     hout << value << endl;
   }
 }

 store_history(&history);
 history_set_history_state(&history_save);
#else
 unused(&store);
#endif
}