/*
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 QDISASSEMBLYVIEW_20061101_H_
#define QDISASSEMBLYVIEW_20061101_H_

#include <QAbstractScrollArea>
#include <QSet>
#include <QPixmap>

#include "MemoryRegions.h"
#include "Configuration.h"
#include "Instruction.h"
#include "Types.h"

class QDisassemblyView : public QAbstractScrollArea {
	Q_OBJECT
		
public:
	QDisassemblyView(QWidget *parent = 0);
	
protected:
	virtual void paintEvent(QPaintEvent *event);
	virtual void mouseDoubleClickEvent(QMouseEvent *event);
	virtual void mousePressEvent(QMouseEvent *event);
	virtual void mouseMoveEvent(QMouseEvent *event);
	virtual void mouseReleaseEvent(QMouseEvent *event);
	virtual bool event(QEvent *event);

public:
	bool addressShown(edb::address_t address) const;
	edb::address_t addressFromPoint(const QPoint &pos) const;
	edb::address_t selectedAddress() const;
	int selectedSize() const;

public slots:
	void setFont(const QFont &f);
	void resizeEvent(QResizeEvent *event);
	void scrollTo(edb::address_t address);
	void setAddressOffset(edb::address_t address);
	void setRegion(const MemoryRegions::Region &r);
	void setCurrentAddress(edb::address_t address);
	void clear();
	void repaint();
	
signals:
	void breakPointToggled(edb::address_t address);

private:
	static int InstructionSize(quint8 *buffer, std::size_t size);

private:
	int getInstructionSize(edb::address_t address, bool &ok) const;
	int getInstructionSize(edb::address_t address, bool &ok, quint8 *buf, int &size) const;
	void updateScrollbars();
	void updateSelectedAddress(QMouseEvent *event);
	int line1() const;
	int line2() const;
	
	int autoLine1() const;
	
	int addressLen() const;
	QString formatAddress(edb::address_t address) const;
	QString formatInstruction(const Instruction &insn, const quint8 *buf, std::size_t size, bool upper) const;
	QString formatInstructionBytes(const quint8 *buf, int size, int maxStringPix) const;
	edb::address_t addressFromCoord(int x, int y) const;
	
private:
	edb::address_t			m_AddressOffset;
	edb::address_t	 		m_CurrentAddress;
	int						m_FontWidth;	// width of a character in this font
	int						m_FontHeight;	// height of a character in this font
	QPixmap					m_Breakpoint;
	QPixmap					m_CurrentAddressIcon;
	bool					m_ShowAddressSeparator;
	MemoryRegions::Region	m_Region;
	char					m_AddressFormatString[32];
	QFontMetrics			m_FontMetrics;
	edb::address_t			m_SelectedInstructionAddress;
	int						m_SelectedInstructionSize;
	QSet<edb::address_t>	m_ShowAddresses;
	bool					m_MovingLine1;
	bool					m_MovingLine2;
	int						m_Line1;
	int						m_Line2;
};

#endif
