// BotInterp.C  -*- C++ -*-
// Copyright (c) 1998 Etienne BERNARD
// Copyright (C) 2002 Clinton Ebadi

// 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "Utils.H"
#include "Bot.H"
#include "BotInterp.H"

#ifdef USESCRIPTS

#include <libguile.h>
extern "C"
{
#include <libguile/regex-posix.h>
  //  SCM scm_regexp_p(SCM);
}

BotInterp::BotInterp(Bot *b, String fn)
  : bot(b), counter(0)
{
  logPort = scm_open_file(Utils::string2SCM(fn),
                          Utils::string2SCM("a"));
  scm_gc_protect_object(logPort);
}

void
BotInterp::Execute(String command)
{
  Interp::Execute(bot, command);
}

void
BotInterp::LoadScript(String filename)
{
  Interp::LoadScript(bot, filename);
}

void
BotInterp::ScriptLog(SCM throw_args)
{
  scm_display_error_message(SCM_CADR (throw_args),
                            SCM_CADDR (throw_args),
                            logPort);
  scm_flush(logPort);
}

bool
BotInterp::AddHook(int hooktype, SCM regex, SCM function) {
  if (scm_string_p(regex) == SCM_BOOL_F)
    return false;
  String rx = Utils::scm2String(regex).toUpper();
  SCM r = scm_make_regexp(regex,
                          scm_listify (gh_lookup("regexp/icase"),
                                  SCM_UNDEFINED));
  scm_gc_protect_object(r);
  scm_gc_protect_object(function);
  // First, we check if an hook doesn't exist yet
  std::list<Hook *>::iterator it = hooksMap[hooktype].begin();
  std::list<Hook *>::iterator it2 = hooksMap[hooktype].end();
  for ( ; it != it2; ++it)
    // It exists, we replace it.
    if ((*it)->regex_str == rx) {
      scm_gc_unprotect_object((*it)->function);
      (*it)->function = function;
      return true;
    }
  // It does not exist, we create it
  hooksMap[hooktype].push_back (new Hook(hooktype, rx, r, function));
  return true;
}

bool
BotInterp::RunHooks(int hooktype, String match, SCM args)
{
  SCM result;
  std::list<Hook *>::iterator it  = hooksMap[hooktype].begin();
  std::list<Hook *>::iterator it2 = hooksMap[hooktype].end();
  struct wrapper_data wd;
  wd.args = args;
  for ( ; it != it2; ++it) {
    wd.func = (*it)->function;
    if (scm_regexp_exec((*it)->regex, Utils::string2SCM(match),
                        SCM_UNDEFINED, SCM_UNDEFINED) != SCM_BOOL_F) {
      result = gh_catch(SCM_BOOL_T, 
			(scm_t_catch_body) scm_apply_wrapper,
			(void *)&wd, 
			(scm_t_catch_handler) Interp::ErrorHandler, 0);
      // TODO: add tf like hooks system...
      //      break;
      //if (result != SCM_BOOL_T) break;
    }
  }
  return true;
}

SCM
BotInterp::AddTimer(int delay, SCM function)
{
  int when = time(NULL) + delay;
  int c = ++counter;
  scm_gc_protect_object(function);
  Timer *t = new Timer(c, when, function);
  timersList.push_back(t);
  return scm_long2num (c);
}

bool
BotInterp::DelTimer(SCM timer)
{
  int count = scm_num2long(timer, SCM_ARG1, "BotInterp::DelTimer");
  std::list<Timer *>::iterator it = timersList.begin();
  std::list<Timer *>::iterator it2 = timersList.end();

  for ( ; it != it2; ++it) {
    if ((*it)->count == count) {
      scm_gc_unprotect_object((*it)->function);
      delete (*it);
      timersList.erase(it);
      return true;
    }
  }
  return false;
}

bool
BotInterp::RunTimers(int now)
{
  std::list<Timer *>::iterator it = timersList.begin();
  std::list<Timer *>::iterator it2 = timersList.end();
  std::list<Timer *>::iterator it3;
  Timer *t;
  struct wrapper_data wd;
  wd.args = scm_listify (SCM_UNDEFINED);

  while (it != it2) {
    if ((*it)->when <= now) {
      wd.func = (*it)->function;
      gh_catch(SCM_BOOL_T, (scm_t_catch_body) scm_apply_wrapper,
               (void *)&wd, (scm_t_catch_handler) Interp::ErrorHandler, 0);
      scm_gc_unprotect_object(wd.func);
      it3 = it;
      ++it3;
      delete (*it);
      timersList.erase(it);
      it = it3;
    } else {
      ++it;
    }
  }
  return true;
}

#endif


syntax highlighted by Code2HTML, v. 0.9.1