#ifndef _KVI_IRCVIEW_H_
#define _KVI_IRCVIEW_H_
//=========================================================================================================
//
//   File : kvi_ircview.h
//   Creation date : Fri Mar 19 1999 05:39:01 by Szymon Stefanek
//
//   This file is part of the KVirc irc client distribution
//   Copyright (C) 1999-2000 Szymon Stefanek (stefanek@tin.it)
//
//   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 opinion) 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. ,59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
//=========================================================================================================

#define UNICODE_IRCVIEW
#define QSTRING_IRCVIEW

#include "kvi_settings.h"
#include "kvi_string.h"

#include <qwidget.h>
#include <qpixmap.h>
#include <qcolor.h>
#include <qscrollbar.h>
#include <qfile.h>
#include "kvi_list.h"
#include <qframe.h>
#include <qlabel.h>
#include <qtoolbutton.h>
#include <qlineedit.h>
#include <qcheckbox.h>
#include <qlistview.h>

#include "kvi_wstring.h"

#include <qfontmetrics.h>

//=========================================================================================================
// Tip label widget
//=========================================================================================================

class KviConsole;

#ifdef _KVI_IRCVIEW_CPP_
	
	class KviIrcViewTipWidget : public QLabel
	{
		friend class KviIrcView;
	    Q_OBJECT
	protected:
		KviIrcViewTipWidget();
		~KviIrcViewTipWidget();
		void abort();
		void popup(const QPoint &pnt);
		virtual void timerEvent(QTimerEvent *e);
		virtual void mousePressEvent(QMouseEvent *e);
		virtual void enterEvent(QEvent *e);
		int m_iHideTimer;
	};

#endif

//=========================================================================================================
// Item for the filter list view
//=========================================================================================================

class KviIrcView;
class KviIrcViewToolWidget;

class KviIrcMessageCheckListItem : public QCheckListItem
{
public:
	KviIrcMessageCheckListItem(QListView * par,KviIrcViewToolWidget * w,int id);
	~KviIrcMessageCheckListItem();
private:
	int m_iId;
	KviIrcViewToolWidget * m_pToolWidget;
public:
	void setToolWidget(KviIrcViewToolWidget * w){ m_pToolWidget = w; };
	virtual void stateChange(bool bOn);
};

//=========================================================================================================
// Search tools widget
//=========================================================================================================

class KviIrcViewToolWidget : public QFrame
{
	friend class KviIrcView;
	Q_OBJECT
protected:
	KviIrcViewToolWidget(KviIrcView * par);
	~KviIrcViewToolWidget();
protected:
	KviIrcView * m_pIrcView;
	QLineEdit  * m_pStringToFind;
	QPoint       m_pressPoint;

	QCheckBox  * m_pCaseSensitive;
	QCheckBox  * m_pRegExp;
	QCheckBox  * m_pExtendedRegExp;

	QLabel     * m_pFindResult;

	QListView  * m_pFilterView;

	KviIrcMessageCheckListItem ** m_pFilterItems;

public:
	void setFindResult(const char * text);
	inline bool messageEnabled(int msg_type){ return m_pFilterItems[msg_type]->isOn(); }
	void forceRepaint();
protected slots:
	void findPrev();
	void findNext();
	void filterEnableAll();
	void filterEnableNone();
	void filterSave();
	void filterLoad();
protected:
	virtual void mouseMoveEvent(QMouseEvent *);
	virtual void mousePressEvent(QMouseEvent *);
};

//=========================================================================================================
// Internal data structures
//=========================================================================================================
//
//#define KVI_IRCVIEW_MAX_TEXT_BLOCKS 64
//it is really enough...16 * 64 = 1 KB (maximum) for each text line
//

// Force this structure to be packed...
#ifdef COMPILE_ON_WINDOWS
	#pragma pack(push,old_packing,1)
	#define _KVI_PACKED
#else //!COMPILE_ON_WIDNOWS
	#define _KVI_PACKED __attribute__((__packed__))
#endif //!COMPILE_ON_WINDOWS
typedef struct _KviIrcViewTextAttributeTag
{
	int            block_idx;                      //index in the data_ptr of the beginning of the block
	int            block_len;                      //length in chars of the block (excluding the terminator)
	unsigned char  attribute;          //attribute type
	union {
		unsigned short icon_id;        //KVI_TEXT_ICON attribute id
		struct {
			unsigned char  back;       //optional background color for KVI_TEXT_COLOR attribute
			unsigned char  fore;       //optional foreground color for KVI_TEXT_COLOR attribute (used also for KVI_TEXT_ESCAPE!!!)
		} _KVI_PACKED colors;
	} _KVI_PACKED attr_data;
#ifdef UNICODE_IRCVIEW
	kvi_wchar_t   *escape_cmd;
#else
	char          *escape_cmd;         //KVI_TEXT_ESCAPE attribute command buffer and KVI_TEXT_ICON icon name (non zeroed for other attributes!!!)
#endif
} _KVI_PACKED KviIrcViewTextAttribute;

typedef struct _KviIrcViewTextBlockTag
{
	int                      block_start;
	int                      block_len;            //length if the block in characters
	int                      block_width;          //width of the block in pixels
	KviIrcViewTextAttribute *attr_ptr;             //pointer to attributes or 0 for word wraps
} _KVI_PACKED KviIrcViewTextBlock;

typedef struct _KviIrcViewTextLine
{
	unsigned int             index;                //index of the text line (needed for find and splitting)

	QString                  data_str;

	int                      msg_type;

	int                      attr_len;             //number of allocated attr structures
	KviIrcViewTextAttribute *attr_ptr;             //pointer to the allocated structures
	// Precalculated text blocks
	int                      line_wraps;
	int                      max_line_width;       //width that the blocks were calculated for
	int                      num_text_blocks;      //number of allocated text blocks
	KviIrcViewTextBlock     *text_blocks_ptr;      //pointer to the allocated text blocks

	struct _KviIrcViewTextLine      *prev_line;
	struct _KviIrcViewTextLine      *next_line;
} _KVI_PACKED KviIrcViewTextLine;

#ifdef COMPILE_ON_WINDOWS
	#pragma pack(pop,old_packing)
#else //!COMPILE_ON_WINDOWS
	#undef _KVI_PACKED
#endif //!COMPILE_ON_WINDOWS

typedef struct _KviIrcViewTextBlockSelectionInfoTag
{
	int selection_type;
	int part_1_length;
	int part_1_width;
	int part_2_length;
	int part_2_width;
	int part_3_length;
	int part_3_width;
} KviIrcViewTextBlockSelectionInfo;



//=========================================================================================================
// Screen layout
//=========================================================================================================

//FIRST LINE (prev_line = 0) <---m_pFirstLine
//LINE
//--------------------SCREEN--
//LINE
//LINE
//LINE
//LINE <-------------------------m_pCurLine
//--------------------SCREEN--
//LAST LINE (next_line = 0) <----m_pLastLine

//=========================================================================================================
// The monster
//=========================================================================================================

class KviWindow;
class KviFrame;

class KVIRC_API KviIrcView : public QWidget
{
	friend class KviIrcViewToolWidget;
	Q_OBJECT
	Q_PROPERTY(int TransparencyCapable READ dummyRead)
public:
	KviIrcView(QWidget *parent,KviFrame *pFrm,KviWindow *pWnd);
	~KviIrcView();
public:
	int dummyRead() const { return 0; };
private:
	KviIrcViewTextLine        * m_pFirstLine;
	KviIrcViewTextLine        * m_pCurLine;    // Bottom line in the view
	KviIrcViewTextLine        * m_pLastLine;
	KviIrcViewTextLine        * m_pCursorLine;

	// Highliting of links
	KviIrcViewTextBlock       * m_pLastLinkUnderMouse;
	int                         m_iLastLinkRectTop;
	int                         m_iLastLinkRectHeight;

	int                         m_iNumLines;
	int                         m_iMaxLines;

	unsigned int                m_uNextLineIndex;

	QPixmap                   * m_pPrivateBackgroundPixmap;
	QScrollBar                * m_pScrollBar;
	QToolButton               * m_pToolWidgetButton;

	KviIrcViewToolWidget      * m_pToolWidget;

	int                         m_iLastScrollBarValue;

	// Font related stuff (needs precalculation!)
	int                         m_iFontLineSpacing;
	int                         m_iFontLineWidth;
	int                         m_iFontDescent;
	int                         m_iFontCharacterWidth[256];    //1024 bytes fixed

	int                         m_iWrapMargin;
	int                         m_iMinimumPaintWidth;
	int                         m_iRelativePixmapY;
	int                         m_iIconWidth;
	int                         m_iIconSideSpacing;

	QPoint                      m_mousePressPos;
	QPoint                      m_mouseCurrentPos;

	// Selection
	int                         m_iSelectionBegin;
	int                         m_iSelectionTop;
	int                         m_iSelectionEnd;
	int                         m_iSelectionBottom;
	int                         m_iSelectionLeft;
	int                         m_iSelectionRight;

	bool                        m_bMouseIsDown;

	bool                        m_bSkipScrollBarRepaint;
	bool                        m_bShowImages; // <-- this should be prolly killed too ? (only global)
//    bool                        m_bDrawEmoticons;
	int                         m_iSelectTimer;
	int                         m_iTipTimer;
	bool                        m_bTimestamp;
	KviWStr                     m_szLastSelection;
	KviWStr                     m_szLastSelectionLine;
	KviWindow                 * m_pKviWindow;
	KviIrcViewTextBlockSelectionInfo m_TextBlockSelectionInfo;
	QFile                     * m_pLogFile;
	KviFrame                  * m_pFrm;
	bool                        m_bAcceptDrops;
	int                         m_iUnprocessedPaintEventRequests;
	bool                        m_bPostedPaintEventPending;
	KviPtrList<KviIrcViewTextLine> * m_pMessagesStoppedWhileSelecting;
	KviIrcView                * m_pMasterView;
	QFontMetrics                m_fm;


public:
	void applyOptions();
	void enableDnd(bool bEnable);
	void appendText(int msg_type,const char *data_ptr,bool bRepaint=true);
	void appendText(int msg_type,const kvi_wchar_t *data_ptr,bool bRepaint=true);

	void removeHeadLine(bool bRepaint=false);
	void emptyBuffer(bool bRepaint=true);
	void getTextBuffer(KviStr &buffer);
	void setMaxBufferSize(int maxBufSize,bool bRepaint=true);
	int  maxBufferSize(){ return m_iMaxLines; }; //Never used ?
	void setShowImages(bool bShow,bool bRepaint=true);
	void setTimestamp(bool bTimestamp);
	bool timestamp(){ return m_bTimestamp; }; //Never used ?
	bool imagesVisible(){ return m_bShowImages; }; //Never used ?
	bool saveBuffer(const char *filename);
	void findNext(const char * text,bool bCaseS = false,bool bRegExp = false,bool bExtended = false);
	void findPrev(const char * text,bool bCaseS = false,bool bRegExp = false,bool bExtended = false);
	KviWindow * parentKviWindow(){ return m_pKviWindow; };
	KviConsole * console();
	// A null pixmap passed here unsets the private backgrdound.
	void setPrivateBackgroundPixmap(const QPixmap &pixmap,bool bRepaint=true);
	bool hasPrivateBackgroundPixmap(){ return (m_pPrivateBackgroundPixmap != 0); };

	//==============================================================================================
	// Logging
	// Stops previous logging session too...
	bool startLogging(const char *filename,bool bPrependCurBuffer = false);
	void stopLogging();
	bool isLogging(){ return (m_pLogFile != 0); };
	void getLogFileName(KviStr &buffer);
	void add2Log(const char *buffer,int buf_len=-1);
	void flushLog();

	//==============================================================================================
	// Channel view splitting
	void setMasterView(KviIrcView * v);
	void splitMessagesTo(KviIrcView * v);
	void joinMessagesFrom(KviIrcView * v);

	void prevLine();
	void nextLine();
	void nextPage();
	void prevPage();
	virtual QSize sizeHint() const;
	const QString & lastLineOfText();
public slots:
	void toggleTimestamp();
	void toggleImages();
	void clearBuffer();
	void toggleToolWidget();
    void inputWidgetKeyPressed();
signals:
	void rightClicked();
	void dndEntered();
	void fileDropped(const char *);
private:
	void setCursorLine(KviIrcViewTextLine * l);
	KviIrcViewTextLine * getVisibleLineAt(int xPos,int yPos);
	void getLinkEscapeCommand(KviStr &buffer,const char * escape_cmd,const char * escape_label,int label_len);
	void resizeMemBuffer();
	void appendLine(KviIrcViewTextLine *ptr,bool bRepaint);
	void postUpdateEvent();
	void fastScroll(int lines = 1);
	const kvi_wchar_t * getTextLine(int msg_type,const kvi_wchar_t * data_ptr,KviIrcViewTextLine *line_ptr);
	void calculateLineWraps(KviIrcViewTextLine *ptr,int maxWidth);
	void recalcFontVariables(const QFont &font);
	bool checkSelectionBlock(KviIrcViewTextLine * line,int left,int bottom,int bufIndex);
	void calculateSelectionBounds();
	KviIrcViewTextBlock * getLinkUnderMouse(int xPos,int yPos,int *rectTop = 0,int *rectHeight = 0,KviWStr * linkCmd = 0,KviWStr * linkText = 0);
	void abortTip();
	void doLinkToolTip(KviStr &linkCmd,KviStr &linkText);
protected:
	virtual void paintEvent(QPaintEvent *);
	virtual void resizeEvent(QResizeEvent *);
	virtual void mousePressEvent(QMouseEvent *e);
	virtual void mouseReleaseEvent(QMouseEvent *);
	virtual void mouseDoubleClickEvent(QMouseEvent *e);
	virtual void mouseMoveEvent(QMouseEvent *e);
	virtual void timerEvent(QTimerEvent *e);
	virtual void dragEnterEvent(QDragEnterEvent *e);
	virtual void dropEvent(QDropEvent *e);
	virtual bool event(QEvent *e);
	virtual void wheelEvent(QWheelEvent *e);
protected slots:
	virtual void scrollBarPositionChanged(int newValue);
	void masterDead();
};

#endif //_KVI_IRCVIEW_H_
