/*
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 "DialogEnvironment.h"
#include "DebuggerCoreInterface.h"
#include "PluginAPI.h"
#include "SymbolManager.h"
#include "Core.h"
#include "Configuration.h"

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

//------------------------------------------------------------------------------
// Name: 
// Desc: 
//------------------------------------------------------------------------------
DialogEnvironment::DialogEnvironment(PluginAPI &api, QWidget *parent) : QDialog(parent), m_API(api) {
	ui.setupUi(this);
	
	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 DialogEnvironment::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) {
		m_API.dumpData(addr, false);
	}
}

//------------------------------------------------------------------------------
// Name: getLibcName()
// Desc: 
//------------------------------------------------------------------------------
QString DialogEnvironment::getLibcName() const {

	QString libcName;

	const QStringList libs = m_API.loadedLibraries();

	foreach(const QString &s, libs) {
		if(!libcName.isEmpty()) {
			break;
		}

		const QFileInfo fileinfo(s);

		// this tries its best to cover all possible libc library versioning possibilities
		// we need to find out if this is 100% accurate, so far seems correct based on my system

		if(fileinfo.completeBaseName().startsWith("libc-")) {
			libcName = fileinfo.completeBaseName() + "." + fileinfo.suffix();
			qDebug() << "[Environment] libc library appears to be:" << libcName;
			continue;
		}

		if(fileinfo.completeBaseName().startsWith("libc.so")) {
			libcName = fileinfo.completeBaseName() + "." + fileinfo.suffix();
			qDebug() << "[Environment] libc library appears to be:" << libcName;
			continue;
		}
	}
	
	return libcName;
}

//------------------------------------------------------------------------------
// Name: doFind()
// Desc: 
//------------------------------------------------------------------------------
void DialogEnvironment::doFind() {
	QStringList results;
	
	const int minStringLength = m_API.config().minStringLength;
	
	const QString libcName = getLibcName();
	const SymbolManager::Symbol *const s = m_API.symbolManager().findSymbol(libcName + "::__environ");
	if(s != 0) {
		edb::address_t evironment_address = s->address;
	
		qDebug() << QString("[Environment] pointer to environment array is at: %1").arg(evironment_address, EDB_MAX_HEX, 16, QChar('0'));
		m_API.debuggerCore->readBytes(evironment_address, &evironment_address, sizeof(evironment_address));
		qDebug() << QString("[Environment] environment array is at: %1").arg(evironment_address, EDB_MAX_HEX, 16, QChar('0'));

		edb::address_t address;
		m_API.debuggerCore->readBytes(evironment_address, &address, sizeof(address));
		QString temp;
		while(address != 0) {

			QString str;
			int stringLen;
			if(m_API.getASCIIStringAtAddress(address, str, minStringLength, 256, stringLen)) {
				results << QString("%1:%2").arg(address, EDB_MAX_HEX, 16, QChar('0')).arg(str);
			}

			evironment_address += sizeof(edb::address_t);
			m_API.debuggerCore->readBytes(evironment_address, &address, sizeof(address));
		}
	} else {
		qDebug("[Environment] __environ symbol not found in libc");
	}
	
	m_Model->setStringList(results);
}

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


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