/*
 *  gnureadline.cc
 *
 *  This file is part of NEST.
 *
 *  Copyright (C) 2004 The NEST Initiative
 *
 *  NEST 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.
 *
 *  NEST 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 NEST.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include "gnureadline.h"
#include <cstdio>
#include "stringdatum.h"
#include <algorithm>

#ifdef HAVE_READLINE

extern "C" char* readline(const char *);
extern "C" void  add_history(const char *);
extern "C" int   read_history(const char *);
extern "C" int   write_history(const char *);
extern "C" void  using_history();
extern "C" void  clear_history();

/*BeginDocumentation
Name: GNUreadline - Read and edit a line from standard input
Synopsis: (prompt) GNUreadline -> (string) true
                               -> false
Description: GNUreadline offers an interface to the GNU readline library.
It offers - line editing
          - history browsing
          - filename completion (with TAB)
Remarks: If GNUreadline is executed with a number, the Interpreter is exited
(in contrast to readline).
SeeAlso: readline, GNUaddhistory
*/
void GNUReadline::GNUReadlineFunction::execute(SLIInterpreter *i) const
{
  //call: promptstring GNUreadline -> string true
  //                                         false

  assert(i->OStack.load()>0);
  i->EStack.pop();

  StringDatum *sd = dynamic_cast<StringDatum *>(i->OStack.top().datum());
  assert(sd != NULL);
  char *line_read = readline(sd->c_str());
  if(line_read == NULL)
  {
    // We have received EOF (Ctrl-D), so we quit.
    std::cout << std::endl; 
    Token t("quit");
    i->OStack.top().swap(t);
    i->OStack.push(i->baselookup(i->true_name));
  }
  else
  {
    StringDatum *sr = new StringDatum(line_read);  
    std::free(line_read);
    if(sr->empty())
    {
      i->OStack.pop();
      i->OStack.push(i->baselookup(i->false_name));
    }
    else
    {
      Token t(sr);
      i->OStack.top().swap(t);
      i->OStack.push(i->baselookup(i->true_name));
    }
  }
}

/*BeginDocumentation
Name: GNUaddhistory - Add a string to the readline-history
Synopsis: (string) GRNUaddhistory -> -
Description: Adds a string to the readline history. 
SeeAlso: GNUreadline
*/
void GNUReadline::GNUAddhistoryFunction::execute(SLIInterpreter *i) const
{
  //call: string GNUaddhistory

  assert(i->OStack.load()>0);
  i->EStack.pop();
  StringDatum *sd = dynamic_cast<StringDatum *>(i->OStack.top().datum());
  assert(sd != NULL);
  add_history(sd->c_str());
  char *home = std::getenv("HOME");
  std::string hist_file = std::string(home) + std::string("/.nest_history");
  
  // We write the history after _each_ command. This comes in handy if you
  // experience a crash during a long interactive session.
  write_history(hist_file.c_str());
  i->OStack.pop();
}


GNUReadline::~GNUReadline()
{
  clear_history();
}

void GNUReadline::init(SLIInterpreter *i)
{
  i->createcommand("GNUreadline", &gnureadlinefunction);
  i->createcommand("GNUaddhistory",&gnuaddhistoryfunction);
  using_history();
  char *home = std::getenv("HOME");
  std::string hist_file = std::string(home) + std::string("/.nest_history");
  read_history(hist_file.c_str());
}

#endif //HAVE_READLINE