/*
   Copyright (C) 1998,1999,2000,2001
   T. Scott Dattalo and Ralf Forsberg

This file is part of gpsim.

gpsim 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, or (at your option)
any later version.

gpsim 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 gpsim; see the file COPYING.  If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.  */

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

#include "../config.h"
#ifdef HAVE_GUI

#include <unistd.h>
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <gdk/gdkkeysyms.h>
#include <glib.h>
#include <string.h>

#include <gtkextra/gtkbordercombo.h>
#include <gtkextra/gtkcolorcombo.h>
#include <gtkextra/gtksheet.h>

#include "gui.h"
#include "gui_src.h"

#include <assert.h>
#include <map>


class StepEvent : public KeyEvent
{
public:
  void press(gpointer data)
  {
    SourceBrowser_Window *sbw = (SourceBrowser_Window *) data;
    if(sbw && sbw->pma)
	sbw->pma->step(1);
  }
  void release(gpointer data) {}
};

class StepOverEvent : public KeyEvent
{
public:
  void press(gpointer data)
  {
    SourceBrowser_Window *sbw = (SourceBrowser_Window *) data;
    if(sbw && sbw->pma)
      // Step Over Next instruction, or hll statement
      sbw->pma->step_over();
  }
  void release(gpointer data) {}
};

class RunEvent : public KeyEvent
{
public:
  void press(gpointer data)
  {
    SourceBrowser_Window *sbw = (SourceBrowser_Window *) data;
    if(sbw && sbw->pma)
      sbw->pma->run();
  }
  void release(gpointer data) {}
};

class StopEvent : public KeyEvent
{
public:
  void press(gpointer data)
  {
    SourceBrowser_Window *sbw = (SourceBrowser_Window *) data;
    if(sbw && sbw->pma)
      sbw->pma->stop();
  }
  void release(gpointer data) {}
};

class FinishEvent : public KeyEvent
{
public:
  void press(gpointer data)
  {
    SourceBrowser_Window *sbw = (SourceBrowser_Window *) data;
    if(sbw && sbw->pma)
      sbw->pma->finish();
  }
  void release(gpointer data) {}
};

static map<guint, KeyEvent *> KeyMap;


static gint
key_press(GtkWidget *widget,
	  GdkEventKey *key, 
	  gpointer data)
{
  int low_level_step=0;

  SourceBrowser_Window *sbw = (SourceBrowser_Window *) data;

  if(!sbw) return(FALSE);
  if(!sbw->gp) return(FALSE);
  if(!sbw->gp->cpu) return(FALSE);

  // fix this
  if(sbw->wt == WT_opcode_source_window)
  {
      SourceBrowserOpcode_Window *sbow = (SourceBrowserOpcode_Window*)sbw;

      if(gtk_notebook_get_current_page(GTK_NOTEBOOK(sbow->notebook)))
	  return FALSE;

      low_level_step=1;
  }
  
  KeyEvent *pKE = KeyMap[key->keyval];
  if(pKE) 
    {
      pKE->press(data);
      return TRUE;
    }

  return FALSE;
}

static int delete_event(GtkWidget *widget,
			GdkEvent  *event,
                        SourceBrowser_Window *sbw)
{
    sbw->ChangeView(VIEW_HIDE);
    return TRUE;
}


void SourceBrowser_Window::SetPC(int address)
{
  printf("%s shouldn't be called \n",__FUNCTION__);

}
void SourceBrowser_Window::UpdateLine(int address)
{
  printf("%s shouldn't be called \n",__FUNCTION__);

}
void SourceBrowser_Window::Update(void)
{
  if(!gp || !gp->cpu)
    return;
  if (gp->cpu->simulation_mode == eSM_RUNNING ||
    gp->cpu->simulation_mode == eSM_SINGLE_STEPPING)
    return;

  SetPC(gp->cpu->pma->get_PC());
}


void SourceBrowser_Window::Create(void)
{
  last_simulation_mode = eSM_INITIAL;

  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);

  gtk_window_set_default_size(GTK_WINDOW(window), width,height);
  gtk_widget_set_uposition(GTK_WIDGET(window),x,y);
  gtk_window_set_wmclass(GTK_WINDOW(window),name(),"Gpsim");

  gtk_signal_connect (GTK_OBJECT (window), "delete_event",
		      GTK_SIGNAL_FUNC(delete_event),
		      (gpointer) this);

  // FIXME - populate the KeyMap map with source browser functions. This should
  // FIXME   probably go into some kind of configuration file.

  KeyMap['s'] = new StepEvent();
  KeyMap['S'] = KeyMap['s'];
  KeyMap[GDK_F7] = KeyMap['s'];

  KeyMap['o'] = new StepOverEvent();
  KeyMap['O'] = KeyMap['o'];
  KeyMap['n'] = KeyMap['o'];
  KeyMap[GDK_F8] = KeyMap['o'];

  KeyMap['r'] = new RunEvent();
  KeyMap['R'] = KeyMap['r'];
  KeyMap[GDK_F9] = KeyMap['r'];

  KeyMap[GDK_Escape] = new StopEvent();

  KeyMap['f'] = new FinishEvent();
  KeyMap['F'] = KeyMap['f'];

  /* Add a signal handler for key press events. This will capture
   * key commands for single stepping, running, etc.
   */
  gtk_signal_connect(GTK_OBJECT(window),"key_press_event",
		     (GtkSignalFunc) key_press,
		     (gpointer) this);


  
  gtk_container_set_border_width (GTK_CONTAINER (window), 0);

  vbox = gtk_vbox_new (FALSE, 0);
  gtk_widget_show(vbox);
  gtk_container_add (GTK_CONTAINER (window), vbox);

}

void SourceBrowser_Window::SetTitle() {
  char buffer[256];

  if (gp->cpu == NULL || pma == NULL) {
      return;
  }
    
  if (last_simulation_mode != eSM_INITIAL &&
    ((last_simulation_mode == eSM_RUNNING &&
    gp->cpu->simulation_mode == eSM_RUNNING) ||
    (last_simulation_mode != eSM_RUNNING &&
    gp->cpu->simulation_mode != eSM_RUNNING)) &&
    sLastPmaName == pma->name()) {
      return;
  }
  last_simulation_mode = gp->cpu->simulation_mode;
  char * sStatus;
  if (gp->cpu->simulation_mode == eSM_RUNNING)
    sStatus = "Run";
  else // if (gp->cpu->simulation_mode == eSM_STOPPED)
    sStatus = "Stopped";
  sprintf(buffer,"Source Browser: [%s] %s", sStatus, pma != NULL ?
    pma->name().c_str() : "" );
  sLastPmaName = pma->name();
  gtk_window_set_title (GTK_WINDOW (window), buffer);
}

void SourceBrowser_Window::NewProcessor(GUI_Processor *gp)
{
  printf("%s shouldn't be called \n",__FUNCTION__);
}
void SourceBrowser_Window::SelectAddress(int address)
{
  printf("%s shouldn't be called \n",__FUNCTION__);
}
void SourceBrowser_Window::SelectAddress(Value *addrSym)
{

  if(typeid(*addrSym) == typeid(line_number_symbol) ||
     typeid(*addrSym) == typeid(address_symbol)) {

    int i;
    addrSym->get(i);
    SelectAddress(i);
  }
       
}


gint gui_object_configure_event(GtkWidget *widget, GdkEventConfigure *e, GUI_Object *go)
{
//    struct gui_config_winattr winattr;

    if(widget->window==0)
	return 0;
    
    gdk_window_get_root_origin(widget->window,&go->x,&go->y);
    gdk_window_get_size(widget->window,&go->width,&go->height);
    
    go->set_config();
    
    return 0; // what should be returned?, FIXME
}

#endif // HAVE_GUI


syntax highlighted by Code2HTML, v. 0.9.1