/***************************************************************************
 ** $Id: torkview.h,v 1.59 2009/10/20 20:16:00 hoganrobert Exp $
 *   Copyright (C) 2006 - 2008 Robert Hogan                                *
 *   robert@roberthogan.net                                                *
 *                                                                         *
 *   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 St, Fifth Floor, Boston, MA 02110-1301, USA.              *
 ***************************************************************************/


#ifndef _TORKVIEW_H_
#define _TORKVIEW_H_

#include <qwidget.h>

#include "torkview_base.h"
#include "hitwidget.h"
#include "kwidgetlistbox.h"
#include "kerrylabel.h"
#include "dndlistview.h"

#include <qlistview.h>
#include <qdragobject.h>
#include <qiconview.h>
#include <qdatetime.h>
#include <kpassivepopup.h>
#include "newstreamosd.h"

class QPainter;
class KURL;
class QListViewItem;
class QDragEnterEvent;
class QDragDropEvent;
class KPassivePopup;
class StreamOSD;
class HitWidget;
class streamItem;

/**
 * This is the main view class for tork.  Most of the non-menu,
 * non-toolbar, and non-statusbar (e.g., non frame) GUI code should go
 * here.
 *
 * @short Main view
 * @author Robert Hogan <robert@roberthogan.net>
 * @version 0.1
 */
class torkView : public torkview_base
{
    Q_OBJECT

	enum {
		HISTORY_SIZE = 300,	// Speed history buffer size
		SPEED_BUFFER_SIZE = 10	// Speed normalization buffer size
	};

public:
	/**
	 * Default constructor
	 */
    torkView(QWidget *parent);

	/**
	 * Destructor
	 */
    virtual ~torkView();

    void hidePopup();
    bool getShowTormon() {return m_tormon;}
    void setShowTormon(bool tormon) { m_tormon = tormon;}
    void infoUpdated(const QString &type, const QString &summary,
                     const QString &data);
    QStringList subnet16List(){ return m_subnet16List; }
    QValueList<int> countryList(){ return m_countryList; }
    StreamOSD* m_osd;
    StreamOSD* m_nontorosd;
    void toggleAnonymizerTork(bool state);
    HitWidget* welcomeitem;
    HitWidget* hiddenservicesitem;
    HitWidget* mixminionitem;
    HitWidget* sshitem;
    HitWidget* kopeteitem;
    HitWidget* gaimitem;
    HitWidget* pidginitem;
    HitWidget* konversationitem;
    HitWidget* gpgitem;
    HitWidget* konqitem;
    HitWidget* telnetitem;
    HitWidget* allpurposeitem;
    HitWidget* ksircitem;
    HitWidget* operaitem;
    HitWidget* firefoxitem;
    QValueList<HitWidget*> menuItems;

    KURLLabel *configurePriv;
    KURLLabel *configurePrivText;

	//	Rx e Tx to bytes and packets
	unsigned long mBRx, mBTx, sysmBRx,sysmBTx;
	// Statistics
	unsigned long mTotalBytesRx, mTotalBytesTx;
	// Speed buffers
	double mSpeedBufferRx[SPEED_BUFFER_SIZE],
           mSpeedBufferTx[SPEED_BUFFER_SIZE];
    double sys_mSpeedBufferRx[SPEED_BUFFER_SIZE],
           sys_mSpeedBufferTx[SPEED_BUFFER_SIZE];
	// pointer to current speed buffer position
	int mSpeedBufferPtr;
    int sys_mSpeedBufferPtr;

	// History buffer TODO: Make it configurable!
	double mSpeedHistoryRx[HISTORY_SIZE];
	double mSpeedHistoryTx[HISTORY_SIZE];
	double sys_mSpeedHistoryRx[HISTORY_SIZE];
	double sys_mSpeedHistoryTx[HISTORY_SIZE];

	int mSpeedHistoryPtr;
	double mMaxSpeed;
	int mMaxSpeedAge;
	int sys_mSpeedHistoryPtr;
	double sys_mMaxSpeed;
	int sys_mMaxSpeedAge;

	const double* speedHistoryRx() const { return mSpeedHistoryRx; }
	const double* speedHistoryTx() const { return mSpeedHistoryTx; }
	int historyBufferSize() const { return HISTORY_SIZE; }
	const int* historyPointer() const { return &mSpeedHistoryPtr; }
	const double* maxSpeed() const { return &mMaxSpeed; }

	const double* sys_speedHistoryRx()
                  const { return sys_mSpeedHistoryRx; }
	const double* sys_speedHistoryTx()
                  const { return sys_mSpeedHistoryTx; }
	int sys_historyBufferSize() const { return HISTORY_SIZE; }
	const int* sys_historyPointer()
                  const { return &sys_mSpeedHistoryPtr; }
	const double* sys_maxSpeed() const { return &sys_mMaxSpeed; }

	// calc tha max. speed stored in the history buffer
	inline void calcMaxSpeed();
	inline void sys_calcMaxSpeed();
	// calc the speed using a speed buffer
	inline double calcSpeed(const double* buffer) const;

	/// RX Speed in bytes per second
	inline double byteSpeedRx() const;
	/// TX Speed in bytes per second
	inline double byteSpeedTx() const;

	/// RX Speed in bytes per second
	inline double sys_byteSpeedRx() const;
	/// TX Speed in bytes per second
	inline double sys_byteSpeedTx() const;

	static inline QString byteFormat( double num,
                                      const char* ksufix = " KB",
                                      const char* msufix = " MB");

    void resetBWHistory();
    void updateChart();
    QStringList m_subnet16List;
    QValueList<int> m_countryList;
    void clearStreamMaps();

    QTime timeLastTorUse;
    QTime timeTorWasLastUsed(){return timeLastTorUse;};
    QString addrLastTorUse;
    QString addrTorWasLastUsed(){return addrLastTorUse;};

    void setGeoIPAvailable(bool set){geoip_db = set;};

signals:

    /**
     * Use this signal to change the content of the caption
     */
    void signalChangeCaption(const QString& text);
    void showSecurityNotice(const QString& cleanedPort);
    void showScreamingNotice(const QString& cleanedPort);
    void showMyKonqueror();
    void riskySession();
    void aboutTorify();
    void aboutTor();
    void configurePrivoxy();
    void aboutParanoidMode();
    void showMyHiddenServices();
    void startEverything();
    void stopEverything();
    void updateStats();
    void mixminionHome();
    void processWarning(const QString& , const QString& );
    void signalCheckGuards();
    void signalCheckTorNet();
    void signalCheckBWSettings();
    void updateTrayStats(const QString &,const QString &,
                         const QString &,const QString &);

public slots:
    void toggleParanoidMode(int);
    void torify(const QString &);
    void sendAnonymousEmail();
    void anonymousOpera();
    void anonymousFirefox();
    void anonymizedOpera(const QString &);
    void anonymizedFirefox(const QString &);
    void showServerBW(const QString&);
private slots:
    void switchColors();
    void settingsChanged();
    void streamStatusUpdated(const QString &, const QString &,
                             const QString &, const QString &,
                             const QString &);
    void circuitStatusUpdated(const QString &, const QString &,
                              const QString &, const QString &);
    void ORStatusUpdated(const QString &ORID, const QString &status);
    void guardStatusUpdated(const QString &ORID, const QString &status);
    void bwUpdated(const QString &in, const QString &out);
    void streamBwUpdated(const QString &stream, const QString &in,
                         const QString &out);
    QPixmap streamProgram(const QString &port);
    void activeServersUpdated(const QStringList &servers);
    void displayError(const QString &,const QString &);
    void displayServer(const QString &,const QString &);
    void serverStatusUpdated(const QString &, const QString &,
                             const QString &,const QString &);
    void privoxiedBash();
    void downloadMixminion();
    void downloadTorButton();
    void reportBW(int secs);
    void changeQuickConfigure(int no);

private:

    unsigned long readInterfaceNumValue(QString interface,
                                        const char* name);
    void setHiddenServicesText();
    QString parseStreamPort(const QString &);
    void populateMenu();

    bool geoip_db;

    KPassivePopup* m_pop;
    bool m_tormon;
    QStringList mSysDevPathList;
    bool mFirstUpdate;
    bool checkInterface();
    bool gotEth0;
    KURLLabel *paranoidmodeicon;
    KURLLabel *paranoidmodetext;
    QStringList greenonion;
    QStringList redonion;
    QStringList yellowonion;
    QStringList orangeonion;
    QStringList littleonion;
    QStringList todelete;
    QValueList<QStringList> iconList;
    QValueList<QString> torType;


    QStringList guard;
    QStringList redguard;
    QStringList detachedguard;
    QStringList littleguard;
    QValueList<QStringList> guardIconList;
    QValueList<QStringList> circuitIconList;

    typedef QMap<QString, QString> stringmap;
    stringmap entryGuards;
    stringmap streamPurpose;
    stringmap portStream;

    typedef QMap<QString, streamItem*> streamlist;
    streamlist streams;
    typedef QMap<QString, QListViewItem*> osdstreamlist;
    osdstreamlist osdstreams;
    osdstreamlist logstreams;
    osdstreamlist torservers;
    osdstreamlist circuitExits;
    typedef QMap<QString, QPixmap> stringToPixmap;
    stringToPixmap streamStatusIcon;
    stringToPixmap cachedStreamIcon;

    typedef QMap<QString, int> streamBw;
    streamBw streamBwIn;
    streamBw streamBwOut;


    QLabel *welcomeheaderLabel;

    unsigned int torbtx;
    unsigned int torbrx;
    unsigned int progDisplayCounter;
};

void torkView::calcMaxSpeed() {
	double max = 0.0;
	int ptr = mSpeedHistoryPtr;
	for (int i = 0; i < HISTORY_SIZE; ++i) {
		if (mSpeedHistoryRx[i] > max) {
			max = mSpeedHistoryRx[i];
			ptr = i;
		}
		if (mSpeedHistoryTx[i] > max) {
			max = mSpeedHistoryTx[i];
			ptr = i;
		}
	}
	mMaxSpeed = max;
	mMaxSpeedAge = (mSpeedHistoryPtr > ptr) ? (mSpeedHistoryPtr - ptr)
                   : (mSpeedHistoryPtr + HISTORY_SIZE - ptr);
}


void torkView::sys_calcMaxSpeed() {
	double max = 0.0;
	int ptr = sys_mSpeedHistoryPtr;
	for (int i = 0; i < HISTORY_SIZE; ++i) {
		if (sys_mSpeedHistoryRx[i] > max) {
			max = sys_mSpeedHistoryRx[i];
			ptr = i;
		}
		if (sys_mSpeedHistoryTx[i] > max) {
			max = sys_mSpeedHistoryTx[i];
			ptr = i;
		}
	}
	sys_mMaxSpeed = max;
	sys_mMaxSpeedAge = (sys_mSpeedHistoryPtr > ptr) ?
                          (sys_mSpeedHistoryPtr - ptr) :
                          (sys_mSpeedHistoryPtr + HISTORY_SIZE - ptr);
}


double torkView::calcSpeed(const double* buffer) const {
	double total = 0.0;
	for (int i = 0; i < SPEED_BUFFER_SIZE; ++i)
		total += buffer[i];
	return total/SPEED_BUFFER_SIZE;
}

double torkView::byteSpeedRx() const {
	return mSpeedHistoryRx[mSpeedHistoryPtr];
}

double torkView::byteSpeedTx() const {
	return mSpeedHistoryTx[mSpeedHistoryPtr];
}

double torkView::sys_byteSpeedRx() const {
	return sys_mSpeedHistoryRx[sys_mSpeedHistoryPtr];
}

double torkView::sys_byteSpeedTx() const {
	return sys_mSpeedHistoryTx[sys_mSpeedHistoryPtr];
}

QString torkView::byteFormat( double num, const char* ksufix,
                              const char* msufix ) {
	const double ONE_KB = 1024.0;
	const double ONE_MB = ONE_KB*ONE_KB;
	if ( num >= ONE_MB ) 	// MB
		return QString::number( num/(ONE_MB), 'f', 1 ) + msufix;
	else	// Kb
		return QString::number( num/ONE_KB, 'f', 1 ) + ksufix;
}

class streamItem : public QObject, public QListViewItem
{
Q_OBJECT

public:
    streamItem( DndListView *parent, const QString &id,
                const QString &program, const QString &target,
                const QString &status, const QString &bw,
                const QString &exit, const QString &circuit );
    streamItem();

	enum {
		HISTORY_SIZE = 300,	// Speed history buffer size
		SPEED_BUFFER_SIZE = 10	// Speed normalization buffer size
	};

	//	Rx e Tx to bytes and packets
	unsigned long mBRx, mBTx;
	// Statistics
	unsigned long mTotalBytesRx, mTotalBytesTx;
	// Speed buffers
	double mSpeedBufferRx[SPEED_BUFFER_SIZE], mSpeedBufferTx[SPEED_BUFFER_SIZE];
	// pointer to current speed buffer position
	int mSpeedBufferPtr;

	// History buffer TODO: Make it configurable!
	double mSpeedHistoryRx[HISTORY_SIZE];
	double mSpeedHistoryTx[HISTORY_SIZE];

	int mSpeedHistoryPtr;
	double mMaxSpeed;
	int mMaxSpeedAge;

	const double* speedHistoryRx() const { return mSpeedHistoryRx; }
	const double* speedHistoryTx() const { return mSpeedHistoryTx; }
	int historyBufferSize() const { return HISTORY_SIZE; }
	const int* historyPointer() const { return &mSpeedHistoryPtr; }
	const double* maxSpeed() const { return &mMaxSpeed; }

	// calc tha max. speed stored in the history buffer
	inline void calcMaxSpeed();

	// calc the speed using a speed buffer
	inline double calcSpeed(const double* buffer) const;

	/// RX Speed in bytes per second
	inline double byteSpeedRx() const;
	/// TX Speed in bytes per second
	inline double byteSpeedTx() const;

    inline void calcBWRate(int torbrx, int torbtx, int secs);

private:


    bool dragging;

};




void streamItem::calcBWRate(int torbrx, int torbtx, int secs) {

    //Calculate Stream Tx/Rx
    unsigned int btx = (torbtx - mBTx);
    unsigned int brx = (torbrx - mBRx);
    mBRx = torbrx;
    mBTx = torbtx;

    if (++mSpeedBufferPtr >= SPEED_BUFFER_SIZE)
        mSpeedBufferPtr = 0;

    mSpeedBufferTx[mSpeedBufferPtr] = ((btx )*(1000.0f/(secs * 1000)));
    mSpeedBufferRx[mSpeedBufferPtr] = ((brx )*(1000.0f/(secs * 1000)));


    if (++mSpeedHistoryPtr >= HISTORY_SIZE)
        mSpeedHistoryPtr = 0;
    mSpeedHistoryRx[mSpeedHistoryPtr] = calcSpeed(mSpeedBufferRx);
    mSpeedHistoryTx[mSpeedHistoryPtr] = calcSpeed(mSpeedBufferTx);

    mMaxSpeedAge--;

    if (mSpeedHistoryTx[mSpeedHistoryPtr] > mMaxSpeed) {
        mMaxSpeed = mSpeedHistoryTx[mSpeedHistoryPtr];
        mMaxSpeedAge = HISTORY_SIZE;
    }
    if (mSpeedHistoryRx[mSpeedHistoryPtr] > mMaxSpeed)  {
        mMaxSpeed = mSpeedHistoryRx[mSpeedHistoryPtr];
        mMaxSpeedAge = HISTORY_SIZE;
    }
    if (mMaxSpeedAge < 1)
        calcMaxSpeed();

}

void streamItem::calcMaxSpeed() {
	double max = 0.0;
	int ptr = mSpeedHistoryPtr;
	for (int i = 0; i < HISTORY_SIZE; ++i) {
		if (mSpeedHistoryRx[i] > max) {
			max = mSpeedHistoryRx[i];
			ptr = i;
		}
		if (mSpeedHistoryTx[i] > max) {
			max = mSpeedHistoryTx[i];
			ptr = i;
		}
	}
	mMaxSpeed = max;
	mMaxSpeedAge = (mSpeedHistoryPtr > ptr) ? (mSpeedHistoryPtr - ptr)
                    : (mSpeedHistoryPtr + HISTORY_SIZE - ptr);
}



double streamItem::calcSpeed(const double* buffer) const {
	double total = 0.0;
	for (int i = 0; i < SPEED_BUFFER_SIZE; ++i)
		total += buffer[i];
	return total/SPEED_BUFFER_SIZE;
}

double streamItem::byteSpeedRx() const {
	return mSpeedHistoryRx[mSpeedHistoryPtr];
}

double streamItem::byteSpeedTx() const {
	return mSpeedHistoryTx[mSpeedHistoryPtr];
}


class circuitItem : public QObject, public QListViewItem
{
Q_OBJECT

public:
    circuitItem( DndListView *parent, const QString &id,
                 const QString &status, const QString &server );

//     bool acceptDrop( const QMimeSource *mime ) const;
//     void dropped ( QDropEvent * e );
//     void dragEntered( );


};



#endif // _TORKVIEW_H_
