/*
Copyright (C) 2006 Evan Teran
                   eteran@alum.rit.edu

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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#ifndef DEBUGGERMAIN_20060508_H_
#define DEBUGGERMAIN_20060508_H_

#include "ui_debuggermain.h"
#include "MemoryRegions.h"
#include "types.h"
#include "DebugEventHandlerInterface.h"

class QPoint;
class QToolButton;
class ByteStreamRegion;
class DebugEventServer;
class DebuggerPluginInterface;

#include <QVector>
#include <QString>

class DebuggerMain : public QMainWindow, public DebugEventHandlerInterface {
	Q_OBJECT
	
public:
	DebuggerMain(QWidget *parent = 0);
	virtual ~DebuggerMain();

protected:	
	virtual void closeEvent(QCloseEvent *event);
	virtual void showEvent(QShowEvent *event);
	
public:
	void finishPluginSetup(QVector<DebuggerPluginInterface *> &plugins);
	
public slots:
	// the autoconnected slots
	void on_action_Attach_triggered();
	void on_action_Run_triggered();
	void on_action_Step_Into_triggered();
	void on_action_Step_Over_triggered();
	void on_action_Memory_Regions_triggered();
	void on_action_Pause_triggered();
	void on_action_Restart_triggered();
	void on_action_Detach_triggered();
	void on_action_Kill_triggered();
	void on_actionRun_Until_Return_triggered();
	void on_action_Open_triggered();
	void on_action_Configure_Debugger_triggered();
	void on_cpuView_customContextMenuRequested(const QPoint &);	
	void on_stackView_customContextMenuRequested(const QPoint &);
	void on_actionAbout_QT_triggered();
	void on_action_About_triggered();
	void on_registerList_itemDoubleClicked(QTreeWidgetItem *);
	void on_actionApplication_Arguments_triggered();
	void on_cpuView_breakPointToggled(BaseTypes::address_t);
	void on_action_Run_Pass_Signal_To_Application_triggered();
	void on_action_Step_Into_Pass_Signal_To_Application_triggered();
	void on_action_Step_Over_Pass_Signal_To_Application_triggered();
	void on_registerList_customContextMenuRequested(const QPoint &);
	void on_actionApplication_Working_Directory_triggered();
	
	// the manually connected slots
	void mnuCPUJumpToAddress();
	void mnuCPUJumpToEIP();
	void mnuFollowInDump();
	void mnuStackFollowInDump();
	void debugEventHandler(DebugEvent event);
	void dumpContextMenu(const QPoint &pos);
	void mnuGotoAddress();
	void createNewDataTab();
	void removeDataTab();
	void followInDump()			{ followRegisterInDump(false); }
	void followInDumpNewTab()	{ followRegisterInDump(true); }
	void followInStack();
	void modifyBytesDump();
	void dumpDataToFile();
	void modifyBytesStack();
	void pushDWORD();
	void popDWORD();
	
	void openRecentMenuItem();
	void clearRecentMenu();
	void doOpenFile(const QString &s);


public:
	void doAttach(BaseTypes::pid_t pid);
		
public:
	virtual void handleEvent(DebugEvent event);
	
private:
	enum GUI_STATE {
		PAUSED,
		RUNNING,
		TERMINATED
	};

public:
	struct DataViewInfo {
	
		DataViewInfo() : stream(0), view(0) {
		}
	
	private:
		DataViewInfo(const DataViewInfo &rhs);
		DataViewInfo &operator=(const DataViewInfo &rhs);
		
	public:
		MemoryRegions::Region	region;
		ByteStreamRegion		*stream;
		QHexView				*view;
		
		void update();
	};
	
	void updateData(DataViewInfo *v);
	void clearData(DataViewInfo *v);

private:	
	void followRegisterInDump(bool tabbed);
	void doResume(bool passExceptionToApp);
	void updateMenuState(GUI_STATE guiState);
	void updateGUI();
	void updateDisassembly(BaseTypes::address_t address, const MemoryRegions::Region &r);
	void updateInstructionInfo(BaseTypes::address_t address);
	void handleEventSignaled();
	void handleEventStopped();
	void handleEventExited();
	void setInitialDebuggerState();
	void setupTabButtons();
	void cleanupDebugger();
	void cleanupEventThread();
	void setInitialBreakpoint(const QString &s);
	void doFollowInDump(QHexView *hv);
	BaseTypes::reg_t *valueFromName(const QString &s, unsigned int mode);
	QString findFunctionSymbol(BaseTypes::address_t address, const QString &defaultValue);
	void doDetachFromProcess(bool kill);
	void doUpdateRegister(QTreeWidgetItem *item, const QString &name, BaseTypes::reg_t value);
	
	void updateRegisterView(const QString &defaultRegionName);
	void updateStackView();
	void updateCPUView(MemoryRegions::Region &region);
	void updateDataViews();
	void updateRecentFileList();
	void loadRecentFileList();
	void saveRecentFileList();
	
	void loadWindowState();
	void saveWindowState();

private:
	static BaseTypes::address_t getELFEntryPoint(const QString &s);
	
private:
	QToolButton					*m_AddTab;
	QToolButton					*m_DelTab;
	DebugEventServer 			*m_DebugEventServer;
	QString						m_Arguments;
	QString						m_WorkingDirectory;
	State						m_CurrentState;
	bool						m_UpdateGUI;
	BaseTypes::address_t		m_ReenableBreakPointAddress;
	DebugEvent					m_LastEvent;
	bool						m_StepWasRun;
	GUI_STATE					m_GUIState;
	QString						m_LastOpenDirectory;
	QVector<QString>			m_RecentFileList;
	QVector<QTreeWidgetItem *>	m_RegisterViewItems;
	
private:
	static const int			MaxRecentFiles = 4;

public:
	QVector<DataViewInfo *>	m_DataRegions;
	DataViewInfo			m_StackViewInfo;

public:
	Ui::DebuggerMain ui;
};

#endif
