/*
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 "DialogASCIIString.h"
#include "DebuggerCoreInterface.h"
#include "MemoryRegions.h"
#include "PluginAPI.h"
#include "ByteShiftArray.h"
#include "Util.h"
#include "State.h"
#include "Core.h"

#include <QVector>
#include <cstring>
#include <boost/smart_ptr.hpp>

//------------------------------------------------------------------------------
// Name: DialogASCIIString(PluginAPI &api, QWidget *parent)
// Desc: constructor
//------------------------------------------------------------------------------
DialogASCIIString::DialogASCIIString(PluginAPI &api, QWidget *parent) : QDialog(parent), m_API(api) {
	ui.setupUi(this);
	ui.progressBar->setValue(0);
	ui.listWidget->clear();
}

//------------------------------------------------------------------------------
// Name: doFind()
// Desc: 
//------------------------------------------------------------------------------
void DialogASCIIString::doFind() {

	const QByteArray b = ui.txtASCII->text().toAscii();
	ui.listWidget->clear();

	const int sz = b.size();
	if(sz != 0) {
	
		m_API.memoryRegions().sync();

		MemRegion region;
		edb::address_t stack_ptr = m_API.currentState().stackPointer();
		
		if(m_API.memoryRegions().findRegion(stack_ptr, region)) {
			std::size_t count = (region.end - stack_ptr) / sizeof(edb::address_t);

			boost::scoped_array<quint8> chars(new quint8[sz]);

			int i = 0;
			while(stack_ptr < region.end) {
				// get the value from the stack
				edb::address_t value;
				if(m_API.debuggerCore->readBytes(stack_ptr, &value, sizeof(edb::address_t))) {
					if(m_API.debuggerCore->readBytes(value, &chars[0], sz)) {
						if(std::memcmp(&chars[0], b.constData(), sz) == 0) {
							ui.listWidget->addItem(QString("%1").arg(stack_ptr, EDB_MAX_HEX, 16, QChar('0')));
						}
					}	
				}
				ui.progressBar->setValue(CalculatePercentage(i++, count));
				stack_ptr += sizeof(edb::address_t);
			}
		}
	}
}

//------------------------------------------------------------------------------
// Name: on_btnFind_clicked()
// Desc: find button event handler
//------------------------------------------------------------------------------
void DialogASCIIString::on_btnFind_clicked() {

	ui.btnFind->setEnabled(false);
	ui.progressBar->setValue(0);
	doFind();
	ui.progressBar->setValue(100);
	ui.btnFind->setEnabled(true);
}

//------------------------------------------------------------------------------
// Name: on_listWidget_itemDoubleClicked(QListWidgetItem *item)
// Desc: follows the found item in the data view
//------------------------------------------------------------------------------
void DialogASCIIString::on_listWidget_itemDoubleClicked(QListWidgetItem *item) {
	bool ok;
	const edb::address_t addr = edb::core::stringToAddress(item->text(), ok);
	if(ok) {
		m_API.dumpStack(addr, true);
	}
}
