/*
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 "DialogStrings.h"
#include "DebuggerCoreInterface.h"
#include "Debugger.h"
#include "MemoryRegions.h"

#include <QHeaderView>
#include <QMessageBox>
#include <QVector>

#define MIN_STRING_LEN 4

//------------------------------------------------------------------------------
// Name: 
// Desc: 
//------------------------------------------------------------------------------
DialogStrings::DialogStrings(QWidget *parent) : QDialog(parent) {
	ui.setupUi(this);
	ui.tableWidget->verticalHeader()->hide();
	ui.tableWidget->horizontalHeader()->setStretchLastSection(true);
}

//------------------------------------------------------------------------------
// Name: on_listWidget_itemDoubleClicked(QListWidgetItem *item)
// Desc: follows the found item in the data view
//------------------------------------------------------------------------------
void DialogStrings::on_listWidget_itemDoubleClicked(QListWidgetItem *item) {
	bool ok;
	const QString s = item->text();
	// TODO: remove hard coded 8
	const BaseTypes::address_t addr = s.left(8).toUInt(&ok, 16);
	if(ok) {
		Debugger::dumpData(addr);
	}
}


//------------------------------------------------------------------------------
// Name: 
// Desc: 
//------------------------------------------------------------------------------
void DialogStrings::showEvent(QShowEvent *) {
	if(Debugger::memoryRegions != 0) {
		Debugger::memoryRegions->sync();
		QVector<MemoryRegions::Region> r = Debugger::memoryRegions->regions();

		ui.tableWidget->setSortingEnabled(false);
		ui.tableWidget->setRowCount(0);
		for(QVector<MemoryRegions::Region>::const_iterator i = r.begin(); i != r.end(); ++i) {
			int row = ui.tableWidget->rowCount();
			ui.tableWidget->insertRow(row);
			ui.tableWidget->setItem(row, 0, new QTableWidgetItem(QString().sprintf("%08x", i->start)));
			ui.tableWidget->setItem(row, 1, new QTableWidgetItem(QString().sprintf("%08x", i->end)));
			ui.tableWidget->setItem(row, 2, new QTableWidgetItem(QString().sprintf("%c%c%c", i->readable() ? 'r' : '-', i->writeable() ? 'w' : '-', i->executable() ? 'x' : '-' )));
			ui.tableWidget->setItem(row, 3, new QTableWidgetItem(i->name));
		}
		ui.tableWidget->setSortingEnabled(true);
	} else {
		ui.tableWidget->setRowCount(0);
	}
	ui.progressBar->setValue(0);
	ui.listWidget->clear();
}

//------------------------------------------------------------------------------
// Name: 
// Desc: 
//------------------------------------------------------------------------------
void DialogStrings::on_btnFind_clicked() {

	QList<QTableWidgetItem *> sel = ui.tableWidget->selectedItems();

	unsigned int column_index			= 0;
	BaseTypes::address_t start_address	= 0;
	BaseTypes::address_t end_address	= 0;
	
	QString str;
	ui.listWidget->clear();

	if(sel.size() == 0) {
		QMessageBox::information(this, "No Region Selected", "You must select a region which is to be scanned for strings.");
	}


	foreach(QTableWidgetItem *selected_item, sel) {

		ui.progressBar->setValue(0);
		
		switch(column_index) {
		case 0:
			// start address
			start_address	= selected_item->text().toUInt(0, 16);
			break;
		case 1:
			// end address
			end_address		= selected_item->text().toUInt(0, 16);
			break;
		case 2:
			do {
				const BaseTypes::address_t orig_start = start_address;
				BaseTypes::address_t last_start = start_address;

				// do the search for this region!
				while(start_address < end_address) {

					char ch;
					Debugger::debuggerBase->readBytes(start_address, &ch, 1);

					if(std::isprint(ch) || std::isspace(ch)) {
						str += ch;
					} else {
						// we just ended a potential string, was it long enough?
						if(str.length() >= MIN_STRING_LEN) {
							ui.listWidget->addItem(QString().sprintf("%08x: %s", last_start + 1, qPrintable(str)));
						}

						// reset the string tracking
						last_start = start_address;
						str = "";
					}

					const BaseTypes::address_t howManyDone	= start_address - orig_start;
					const BaseTypes::address_t howMany		= end_address - orig_start;
					const int percent = static_cast<int>(static_cast<double>(howManyDone) / static_cast<double>(howMany) * 100);			

					ui.progressBar->setValue(percent);
					++start_address;
				}

				if(str.length() >= MIN_STRING_LEN) {
					ui.listWidget->addItem(QString().sprintf("%08x: %s", last_start + 1, qPrintable(str)));
				}
			} while(0);
			break;
		case 3:
			break;
		}

		column_index = (column_index + 1) % ui.tableWidget->columnCount();
	}
}
