/*
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.
*/

#include "DialogSymbolViewer.h"
#include "DebuggerCoreInterface.h"
#include "PluginAPI.h"
#include "SymbolManager.h"
#include "Configuration.h"
#include "Util.h"
#include "Core.h"

#include <QStringListModel>
#include <QSortFilterProxyModel>
#include <QHeaderView>
#include <QFileInfo>
#include <QMenu>

#include <boost/smart_ptr.hpp>

//------------------------------------------------------------------------------
// Name: DialogSymbolViewer((PluginAPI &api, QWidget *parent)
// Desc: 
//------------------------------------------------------------------------------
DialogSymbolViewer::DialogSymbolViewer(PluginAPI &api, QWidget *parent) : QDialog(parent), m_API(api) {
	ui.setupUi(this);
	
	ui.listView->setContextMenuPolicy(Qt::CustomContextMenu);
	
	m_Model = new QStringListModel(this);
	m_FilterModel = new QSortFilterProxyModel(this);
	
	m_FilterModel->setFilterKeyColumn(0);
	m_FilterModel->setSourceModel(m_Model);
	ui.listView->setModel(m_FilterModel);
	
	connect(ui.txtSearch, SIGNAL(textChanged(const QString &)), m_FilterModel, SLOT(setFilterFixedString(const QString &)));
}

//------------------------------------------------------------------------------
// Name: on_listView_doubleClicked(const QModelIndex &index) 
// Desc: follows the found item in the data view
//------------------------------------------------------------------------------
void DialogSymbolViewer::on_listView_doubleClicked(const QModelIndex &index) {

	bool ok;
	const QString s = index.data().toString();
	const edb::address_t addr = edb::core::stringToAddress(s, ok);

	if(ok) {
	
		const SymbolManager::Symbol *const sym = m_API.symbolManager().findSymbol(addr);
		
		if(sym != 0 && sym->isCode()) {
			m_API.jumpToAddress(addr);
		} else {
			m_API.dumpData(addr, false);
		}
	}
}

//------------------------------------------------------------------------------
// Name: on_listView_customContextMenuRequested(const QPoint &pos)
// Desc: 
//------------------------------------------------------------------------------
void DialogSymbolViewer::on_listView_customContextMenuRequested(const QPoint &pos) {
	
	QModelIndex index = ui.listView->indexAt(pos);
	if(index.isValid()) {
	
		bool ok;
		const QString s = index.data().toString();
		const edb::address_t addr = edb::core::stringToAddress(s, ok);
	
		boost::scoped_ptr<QMenu> menu(new QMenu(this));
		QAction *const action1 = menu->addAction(tr("&Follow In Disassembly"), this, SLOT(mnuFollowInCPU()));
		QAction *const action2 = menu->addAction(tr("&Follow In Dump"), this, SLOT(mnuFollowInDump()));
		QAction *const action3 = menu->addAction(tr("&Follow In Dump (New Tab)"), this, SLOT(mnuFollowInDumpNewTab()));
		QAction *const action4 = menu->addAction(tr("&Follow In Stack"), this, SLOT(mnuFollowInStack()));
		
		action1->setData(addr);
		action2->setData(addr);
		action3->setData(addr);
		action4->setData(addr);
		
		menu->exec(ui.listView->mapToGlobal(pos));
	}
}

//------------------------------------------------------------------------------
// Name: 
// Desc: 
//------------------------------------------------------------------------------
void DialogSymbolViewer::mnuFollowInDump() {
	QAction *const action = qobject_cast<QAction *>(sender());
	if(action != 0) {
		const edb::address_t address = action->data().toULongLong();
		m_API.dumpData(address, false);
	}
}

//------------------------------------------------------------------------------
// Name: 
// Desc: 
//------------------------------------------------------------------------------
void DialogSymbolViewer::mnuFollowInDumpNewTab() {
	QAction *const action = qobject_cast<QAction *>(sender());
	if(action != 0) {
		const edb::address_t address = action->data().toULongLong();
		m_API.dumpData(address, true);
	}
}

//------------------------------------------------------------------------------
// Name: 
// Desc: 
//------------------------------------------------------------------------------
void DialogSymbolViewer::mnuFollowInStack() {
	QAction *const action = qobject_cast<QAction *>(sender());
	if(action != 0) {
		const edb::address_t address = action->data().toULongLong();
		m_API.dumpStack(address, false);
	}
}

//------------------------------------------------------------------------------
// Name: 
// Desc: 
//------------------------------------------------------------------------------
void DialogSymbolViewer::mnuFollowInCPU() {
	QAction *const action = qobject_cast<QAction *>(sender());
	if(action != 0) {
		const edb::address_t address = action->data().toULongLong();
		m_API.jumpToAddress(address);
	}
}

//------------------------------------------------------------------------------
// Name: doFind()
// Desc: 
//------------------------------------------------------------------------------
void DialogSymbolViewer::doFind() {
	QStringList results;
	QString temp;
	
	QList<SymbolManager::Symbol> symbols = m_API.symbolManager().symbols();
	foreach(const SymbolManager::Symbol &sym, symbols) {
		results << QString("%1: %2").arg(sym.address, EDB_MAX_HEX, 16, QChar('0')).arg(sym.name);
	}
	
	m_Model->setStringList(results);
}

//------------------------------------------------------------------------------
// Name: on_btnRefresh_clicked()
// Desc: 
//------------------------------------------------------------------------------
void DialogSymbolViewer::on_btnRefresh_clicked() {
	ui.btnRefresh->setEnabled(false);
	doFind();
	ui.btnRefresh->setEnabled(true);
}


//------------------------------------------------------------------------------
// Name: showEvent(QShowEvent *)
// Desc: 
//------------------------------------------------------------------------------
void DialogSymbolViewer::showEvent(QShowEvent *) {
	on_btnRefresh_clicked();
}
