/* Copyright (C) 1996,1997 Robert H”hne, see COPYING.RH for details */
/* This file is part of RHIDE. */
#define Uses_TEventQueue
#define Uses_TProject
#define Uses_TProgram
#define Uses_TDeskTop
#define Uses_TIDEEditWindow
#define Uses_TIDEFileEditor
#define Uses_editCommands
#define Uses_TOptions
#define Uses_TDirList
#define Uses_TParamList
#define Uses_TScreen
#define Uses_TFileViewer
#define Uses_TWindow
#define Uses_MsgBox
#define Uses_TListBox
#define Uses_TFileDialog
#define Uses_TFileInputLine
#define Uses_ideFunctions
#define Uses_ideCommands
#include <libide.h>

#define Uses_TSCollection
#define Uses_BigMessageBox
#define Uses_tvutilFunctions
#include <libtvuti.h>

#define Uses_IDEConst
#include <rhide.h>
#include <rhidehis.h>

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

TCEditor *current_editor;
uint32 CPULine;

#ifdef INTERNAL_DEBUGGER
#define Uses_tvgdbFunctions
#include <librhgdb.h>

#define Uses_TWatchListBox
#include <libtvgdb.h>

static void UserScreen()
{
  TProgram::application->suspend();
}

static void DebuggerScreen()
{
  TProgram::application->resume();
  Repaint();
}

static void select_source_line(char *fname,int line)
{
  char *full_name = NULL;
  TCEditWindow *ew = NULL;
  // remove at first the last CPU line
  if (current_editor)
  {
    CPULine = (uint32)-1;
    current_editor->update(ufView);
  }
  if (!fname) return;
  ew = is_on_desktop(fname,False);
  if (!ew && FindFile(fname,full_name) == False)
  {
    ushort result;
    char *bname;
    BaseName(fname,bname);
    messageBox(mfError | mfOKButton,_("Could not find the source "
                                      "file %s."),bname);
    string_free(full_name);
    TFileDialog *dialog;
    InitHistoryID(RHIDE_History_source_file);
    dialog = new TFileDialog(bname,_("Open a file"),
                      _("~N~ame"),fdOpenButton,RHIDE_History_source_file);
    result = TProgram::deskTop->execView(dialog);
    string_free(bname);
    if (result != cmCancel)
    {
      full_name = (char *)malloc(PATH_MAX);
      dialog->getData(full_name);
      FExpand(full_name);
      char *dir,*name,*ext;
      split_fname(full_name,dir,name,ext);
      string_free(name);
      string_free(ext);
      if (*dir) dir[strlen(dir)-1] = 0;
      if (messageBox(mfConfirmation | mfYesNoCancel,
                     _("Add '%s' to the search path for source files"),
                     dir) == cmYes)
      {
        Options.SrcDirs->insert(strdup(dir));
      }
      string_free(dir);
    }
    else
    {
      current_editor = NULL;
      return;
    }
  }
  if (!ew) ew = OpenEditor(full_name,True);
  ew->select();
  string_free(full_name);
  current_editor = ew->editor;
  CPULine = line-1;
  current_editor->lock();
  current_editor->MoveCursorTo(0,CPULine);
  current_editor->trackCursor(False);
  /* If the line is at the first or last screen line, try to
     center it */
  current_editor->update(ufView);
  current_editor->unlock();
  if (current_editor->cursor.y == 0 ||
      current_editor->cursor.y == current_editor->size.y-1)
  {
    current_editor->trackCursor(True);
    current_editor->update(ufView);
  }
}

const char *WhereIsCursor(int &line,int &column,char *&bname,TCEditWindow *&ew)
{
  const char *file;
  ew = (TCEditWindow *)TProgram::deskTop->current;
  if (!ew) return NULL;
  TEvent event;
  event.what = evBroadcast;
  event.message.command = cmEditorAnswer;
  ew->handleEvent(event);
  if (event.what != evNothing) return NULL;
  file = ew->getTitle(100);
  BaseName(file,bname);
  line = ew->editor->curPos.y+1;
  column = ew->editor->curPos.x+1;
  return file;
}

void GOTO(int _switch_to_user)
{
  int line,column;
  const char *file;
  char *bname;
  TCEditWindow *ew;
  file = WhereIsCursor(line,column,bname,ew);
  if (!file) return;
  switch_to_user = _switch_to_user;
  GoToLine(bname,line);
//  ew->select();
}  
    
void RESET()
{
  ResetDebugger();
  if (project_directory) chdir(project_directory);
  Repaint();
}

int DEBUGGER_STARTED()
{
  return debugger_started;
}

void TRACE(int _switch_to_user)
{
  switch_to_user = _switch_to_user;
  Trace();
}

void STEP(int _switch_to_user)
{
  switch_to_user = _switch_to_user;
  Step();
}

void CONTINUE()
{
  switch_to_user = 1;
  Continue();
}

static unsigned long last_modified = 0;

static int DoMake()
{
  if (debugger_started)
  {
    if (!hasmodified && already_maked)
    {
      last_modified = 0;
      return 1;
    }
    if (already_maked && hasmodified)
    {
      ushort retval;
      if (last_modified == hasmodified) return 1;
      retval = messageBox(_("Source has been modified. Rebuild it?"),
                     mfWarning|mfYesButton|mfNoButton);
      if (retval == cmNo)
      {
        last_modified = hasmodified;
        return 1;
      }
      else if (retval == cmCancel)
      {
        return 0;
      }
    }
  }
  last_modified = 0;
  ShowMessages(NULL,True);
  return (Make(False) == False) ? 0 : 1;
}

static char *GetProgName()
{
  return (char *)FName(Project.dest_name);
}

static char **GetSourceDirectories(int *count)
{
  *count = 0;
  return NULL;
}

static char **args = NULL; 

static char **GetProgramArguments(int *count)
{
  int i;
  *count = Options.ProgArgs->getCount();
  if (*count == 0) return NULL;
  args = (char **)realloc(args,*count * sizeof(char *));
  for (i=0;i<*count;i++)
  {
    args[i] = (char *)Options.ProgArgs->at(i);
  }
  return args;
}

static void UPDATE_WATCH()
{
  if (watchwindow) watches->update();
  UpdateCallStackWindow();
}

int dual_display_supported();

static void StartSession()
{
  if (!dual_display && UseDualDisplay && dual_display_supported())
  {
    TMouse::suspend();
    TScreen::suspend();
    dual_display = 1;
    TScreen::resume();
    TMouse::resume();
    TProgram::application->setScreenMode(Project.screen_mode);
  }
  if (ShowStdout) cpp_outname = open_stdout();
  if (ShowStderr) cpp_errname = open_stderr();
  if (watchwindow) watchwindow->select();
}

void CheckStderr();
void CheckStdout();

static void EndSession(int exit_code)
{
  if (dual_display && UseDualDisplay)
  {
    TMouse::suspend();
    TScreen::suspend();
    dual_display = 0;
    TScreen::resume();
    TMouse::resume();
    TProgram::application->setScreenMode(Project.screen_mode);
    Repaint();
  }

  if (ShowStdout)
  {
    close_stdout();
  }
  if (ShowStderr)
  {
    close_stderr();
  }
  messageBox(mfInformation|mfOKButton,
    _("Program exit code: %d (0x%04x)"),exit_code,exit_code);

  if (ShowUserAfterExit)
  {
    TEvent event;
    event.what = evCommand;
    event.message.command = cmUserScreen;
    TProgram::application->handleEvent(event);
  }

  if (ShowStdout)
  {
    CheckStdout();
  }
  if (ShowStderr)
  {
    CheckStderr();
  }
}

static void BreakSession()
{
  if (dual_display && UseDualDisplay)
  {
    TMouse::suspend();
    TScreen::suspend();
    dual_display = 0;
    TScreen::resume();
    TMouse::resume();
    TProgram::application->setScreenMode(Project.screen_mode);
    Repaint();
  }
  if (ShowStdout)
  {
    close_stdout();
    CheckStdout();
  }
  if (ShowStderr)
  {
    close_stderr();
    CheckStderr();
  }
}

static char *GetMainFunction()
{
  return Project.main_function;
}

void InitDebuggerInterface()
{
  _select_source_line = select_source_line;
  _UserWarning = UserWarning;
  _DebuggerScreen = DebuggerScreen;
  _UserScreen = UserScreen;
  _GetProgramArguments = GetProgramArguments;
  _GetSourceDirectories = GetSourceDirectories;
  _GetProgName = GetProgName;
  _DoMake = DoMake;
  _InitGDBOutWin = InitGDBOutWin;
  _UpdateGDBOutWin = UpdateGDBOutWin;
  _StartSession = StartSession;
  _EndSession = EndSession;
  _BreakSession = BreakSession;
  _GetMainFunction = GetMainFunction;
  post_command_hook = UPDATE_WATCH;
}

void ToggleBreak()
{
  const char *fname;
  char *bname;
  int break_number,line,column;
  TCEditWindow *ew;
  if ((fname = WhereIsCursor(line,column,bname,ew)) == NULL) return;
  break_number = IsBreakPointLine(bname,line);
  if (break_number >= 0)
    RemoveBreakPoint(break_number);
  else
    AddBreakPointLine(bname,line);
  Repaint();
}  

#else
void GOTO(int) {}
void STEP(int) {}
void TRACE(int) {}
void RESET()
{
  if (project_directory) chdir(project_directory);
}
void CONTINUE() {}
int DEBUGGER_STARTED() { return 0; }
#endif
