/***************************************************************************
 * $Id: torkview_base.ui.h,v 1.48 2009/06/20 09:29:15 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.              *
 ***************************************************************************/

#include <tqtooltip.h>
#include <tqpopupmenu.h>
#include <tqclipboard.h>

#include <kdebug.h>
#include <tdeapplication.h>
#include <kiconloader.h>
#include <kstandarddirs.h>

#include "torkconfig.h"
#include "tork.h"
#include "crypto.h"

#ifndef EXTERNAL_GEOIP
# include "GeoIP-1.4.0/libGeoIP/GeoIP.h"
#else
# include <GeoIP.h>
#endif

bool m_LeaveStreamsUnattached;

typedef TQMap<TQString, TQListViewItem*> ResolveMap;
ResolveMap resolveMap;
typedef TQMap<TQListViewItem*, int > ResolveColMap;
ResolveColMap resolveColMap;

void torkview_base::init()
{

    serverFilter->setListView((TDEListView *)serverList);
    TQValueList<int> tmp;
    tmp << 1;
    serverFilter->setSearchColumns(tmp);

    clearButton->setIconSet(SmallIconSet("locationbar_erase"));
    connect(clearButton, TQ_SIGNAL( clicked() ),
                    serverFilter, TQ_SLOT(clear()) );

    serverList->addColumn( kapp->iconLoader()->loadIconSet("tork_torsmall", 
                           TDEIcon::Small),"", 24 );
    serverList->addColumn( "Server" );
    serverList->addColumn( "FP" );
    serverList->addColumn( "conditions" );
    serverList->addColumn( "countrycode" );
    serverList->addColumn( "ip" );

    serverList->setSelectionMode( TQListView::Extended );
    serverList->setColumnWidthMode(2, TQListView::Manual);
    serverList->hideColumn(2);
    serverList->setColumnWidthMode(3, TQListView::Manual);
    serverList->hideColumn(3);
    serverList->setColumnWidthMode(4, TQListView::Manual);
    serverList->hideColumn(4);
    serverList->setColumnWidthMode(5, TQListView::Manual);
    serverList->hideColumn(5);
    serverList->header()->setResizeEnabled(FALSE, 1);
    serverList->setResizeMode( TQListView::NoColumn );
    serverList->setHScrollBarMode(TQScrollView::AlwaysOff);

    streamList->addColumn( "ID" );
    streamList->addColumn(  tr2i18n("Source")  );
    streamList->addColumn(  tr2i18n("Host/Port")  );
    streamList->addColumn(  kapp->iconLoader()->loadIconSet("tork_torsmall", TDEIcon::Small),"", 24  );
    streamList->addColumn(  tr2i18n("Speed")  );
    streamList->addColumn(  tr2i18n("Exit")  );
    streamList->addColumn(  tr2i18n("Circuit")  );

    streamList->setSelectionMode( TQListView::Extended );
    streamList->setColumnWidthMode(0, TQListView::Manual);
    streamList->hideColumn(0);
    streamList->header()->setResizeEnabled(FALSE, 0);
    streamList->setResizeMode( TQListView::NoColumn );


    circuitList->addColumn( tr2i18n( "ID" ) );
    circuitList->addColumn( kapp->iconLoader()->loadIconSet("tork_torsmall", TDEIcon::Small),"", 24 );
    circuitList->addColumn( tr2i18n( "Path" ) );
    circuitList->setSelectionMode( TQListView::Extended );
    circuitList->setColumnWidthMode(0, TQListView::Manual);
    circuitList->hideColumn(0);
    circuitList->header()->setResizeEnabled(FALSE, 0);
    circuitList->setResizeMode( TQListView::LastColumn );


    ORList->addColumn( kapp->iconLoader()->loadIconSet("tork_torsmall", TDEIcon::Small),"", 24 );
    ORList->addColumn( tr2i18n( "Server" ) );
    ORList->setSelectionMode( TQListView::Extended );
    ORList->setColumnWidthMode(0, TQListView::Manual);
    ORList->setResizeMode( TQListView::LastColumn );

    TorTraffic->setColumnWidthMode(0, TQListView::Manual);
    TorTraffic->hideColumn(0);
    TorTraffic->header()->setResizeEnabled(FALSE, 0);
    TorTraffic->setResizeMode( TQListView::NoColumn );
    TorTraffic->setSorting ( 1, true);
    NonTorTraffic->setSorting ( 0, true);

    m_LeaveStreamsUnattached = false;

    infoList->setColumnWidthMode(1, TQListView::Manual);
    infoList->hideColumn(1);
    infoList->header()->setResizeEnabled(FALSE, 1);
    infoList->setSorting ( 0, true);

    kcfg_LogNonTorTraffic->setChecked(TorkConfig::logNonTorTraffic());
    kcfg_LogTorTraffic->setChecked(TorkConfig::logTorTraffic());
    kcfg_LogNonTorTraffic_toggled(TorkConfig::logNonTorTraffic());
    kcfg_LogTorTraffic_toggled(TorkConfig::logTorTraffic());

    NonTorTrafficMaxEntries->setValue(TorkConfig::nonTorTrafficMaxEntries());

}

void torkview_base::stopDisplayingBubble(TQListViewItem*,const TQPoint&,int)
{
    TorkConfig::setDisplayBubble(false);
}

void torkview_base::streamList_contextMenuRequested( TQListViewItem *, const TQPoint &point, int )
{

    TQPopupMenu *menu = new TQPopupMenu( streamList );

    menu->clear();

    if (streamList->childCount() > 0)
        menu->insertItem( "Close Connection", this,TQ_SLOT(slotCloseStream()) );
    if (!m_LeaveStreamsUnattached)
        menu->insertItem( "Let Me Drag Connections To Circuits Myself", this,TQ_SLOT(slotAttachStreams()) );
    else
        menu->insertItem( "Attach Connections To Circuits Automatically", this,TQ_SLOT(slotAttachStreams()) );

    menu->popup( point );

}


void torkview_base::slotAttachStreams( )
{

    m_LeaveStreamsUnattached = !m_LeaveStreamsUnattached;
    emit attachStreams(m_LeaveStreamsUnattached);
}
void torkview_base::slotCloseStream( )
{
    kdDebug() << "deleting entry" << endl;

    TQListViewItemIterator it(streamList, TQListViewItemIterator::Selected);
    while ( it.current() ) {
        if (streamList->isSelected( it.current()))
            emit closeStream(it.current()->text(0));
        ++it;
    }


}

void torkview_base::circuitList_contextMenuRequested( TQListViewItem *, const TQPoint &point, int )
{

    if (circuitList->childCount() == 0)
        return;

    TQPopupMenu *menu = new TQPopupMenu( circuitList );

    menu->clear();
    menu->insertItem( "Close Circuit", this,TQ_SLOT(slotCloseCircuit()) );
    menu->popup( point );

}


void torkview_base::slotCloseCircuit( )
{
    kdDebug() << "deleting entry" << endl;

    TQListViewItemIterator it(circuitList, TQListViewItemIterator::Selected);
    while ( it.current() ) {
        if (circuitList->isSelected( it.current()))
            emit closeCircuit(it.current()->text(0));
        ++it;
    }


}

void torkview_base::serverList_contextMenuRequested( TQListViewItem *, const TQPoint &point, int )
{

    if (serverList->childCount() == 0)
        return;

    TQPopupMenu *menu = new TQPopupMenu( serverList );
    TQPopupMenu *m_ThisSession =  new TDEPopupMenu( this );
    TQPopupMenu *m_ThisPerm =  new TDEPopupMenu( this );

    menu->clear();
    menu->insertItem( i18n("For This Session Only"), m_ThisSession );
    menu->insertItem( i18n("From Now On"), m_ThisPerm );
    menu->insertItem( "Add to My Family", this, TQ_SLOT(slotAddToFamily()) );

    m_ThisSession->insertItem( i18n("Always Use Server As An Exit"), this,
         TQ_SLOT(slotAddSessionStrictExitNodes()) );
    m_ThisSession->insertItem( i18n("Try To Use Server As an Exit"), this, TQ_SLOT(slotAddSessionExitNodes()) );
    m_ThisSession->insertItem( i18n("Never Use Server At All"), this, TQ_SLOT(slotAddSessionExcludeNodes()) );
    m_ThisSession->insertItem( i18n("Never Use Country At All"), this, TQ_SLOT(slotAddSessionExcludeCountry()) );

    m_ThisPerm->insertItem( i18n("Always Use Server As An Exit"), this, TQ_SLOT(slotAddPermStrictExitNodes()) );
    m_ThisPerm->insertItem( i18n("Try To Use Server As an Exit"), this, TQ_SLOT(slotAddPermExitNodes()) );
    m_ThisPerm->insertItem( i18n("Never Use Server At All"), this,  TQ_SLOT(slotAddPermExcludeNodes()) );
    m_ThisPerm->insertItem( i18n("Never Use Country At All"), this,  TQ_SLOT(slotAddPermExcludeCountry()) );

    menu->insertSeparator();
    menu->insertItem( "Reset Session Settings", this, TQ_SLOT(slotClearNodes()) );
    menu->popup( point );

}

void torkview_base::slotClearNodes( )
{
    emit clearNodes();
}

void torkview_base::slotAddToFamily( )
{
    TQStringList currentList;
    currentList = TorkConfig::myFamily();

    TQListViewItemIterator it(serverList, TQListViewItemIterator::Selected | TQListViewItemIterator::Visible);
    while ( it.current() ) {
            if (!TorkConfig::myFamily().contains(TQString("%1-%2-%3")
                .arg((*it)->text(4)).arg((*it)->text(2)).arg((*it)->text(1)))){
                    TQStringList existingServers = TorkConfig::myFamily();
                    existingServers.append(TQString("%1-%2-%3")
                        .arg((*it)->text(4)).arg((*it)->text(2)).arg((*it)->text(1)));
                    TorkConfig::setMyFamily(existingServers);
            }
        ++it;
    }
    TorkConfig::writeConfig();
}

void torkview_base::slotAddPermExcludeCountry( )
{
    TQStringList selectedCountries = selectByCountry();

    TQStringList newCountries = TorkConfig::excludeCountries();
    for ( TQStringList::Iterator it = selectedCountries.begin(); it != selectedCountries.end(); ++it )
	{
        if ((!TorkConfig::excludeCountries().contains(*it)) &&
           (!newCountries.contains(*it)))
            newCountries.append(*it);
    }
    TorkConfig::setExcludeCountries(newCountries);

    addExcludeNodes(true,TorkConfig::excludeCountries());
}

void torkview_base::slotAddPermExcludeNodes( )
{
    addExcludeNodes(true, TQStringList());
}

TQStringList torkview_base::selectByCountry( )
{

    TQStringList selectCountries;

    TQListViewItemIterator it(serverList, TQListViewItemIterator::Selected | TQListViewItemIterator::Visible);
    while ( it.current() ) {
        TQString cc = (*it)->text(4);
        selectCountries.append(cc);
        ++it;
    }
    return selectCountries;
}

void torkview_base::slotAddSessionExcludeCountry( )
{

    addExcludeNodes(false, selectByCountry());
}

void torkview_base::slotAddSessionExcludeNodes( )
{
    addExcludeNodes(false, TQStringList());
}

void torkview_base::slotAddPermExitNodes( )
{
    addExitNodes(true, false);
}

void torkview_base::slotAddPermStrictExitNodes( )
{
    addExitNodes(true, true);
}

void torkview_base::slotAddSessionExitNodes( )
{
    addExitNodes(false, false);
}

void torkview_base::slotAddSessionStrictExitNodes( )
{
    addExitNodes(false, true);
}

void torkview_base::slotAddPermEntryNodes( )
{
    addEntryNodes(true);
}

void torkview_base::slotAddSessionEntryNodes( )
{
    addEntryNodes(false);
}

void torkview_base::addExcludeNodes(bool perm, TQStringList ccs )
{

    TQStringList currentList;
    currentList = TorkConfig::currentExcludeNodes();
    TQStringList permList;
    permList = TorkConfig::excludeNodes();
    TQListViewItemIterator::IteratorFlag filter;

    if (ccs.isEmpty())
        filter = TQListViewItemIterator::IteratorFlag(TQListViewItemIterator::Selected | TQListViewItemIterator::Visible);
    else
        filter = TQListViewItemIterator::IteratorFlag();

    TQListViewItemIterator it(serverList, filter);

    while ( it.current() ) {
        if (!ccs.isEmpty()){
            if (!ccs.contains((*it)->text(4))){
                ++it;
                continue;
            }
        }

        TQString node = "$"+getFPFromFPDigest((*it)->text(2));
        currentList.append(node);
        if (perm){
            permList.append(node);
            if (!TorkConfig::excludeServersHistory().contains(TQString("%1-%2-%3")
                .arg((*it)->text(4)).arg((*it)->text(2)).arg((*it)->text(1)))){
                TQStringList existingServers = TorkConfig::excludeServersHistory();
                existingServers.append(TQString("%1-%2-%3")
                    .arg((*it)->text(4)).arg((*it)->text(2)).arg((*it)->text(1)));
                TorkConfig::setExcludeServersHistory(existingServers);
            }

        }
        //kdDebug() << getFPFromFPDigest((*it)->text(2)) << endl;
        ++it;
    }
    TorkConfig::setCurrentExcludeNodes(currentList);
    TorkConfig::setExcludeNodes(permList);

    TQListView* tmp = dynamic_cast<TQListView*>(circuitList);
    emit closeAllCircuits(tmp);
    emit updateExcludeNodes();

    emit copyOldConfig();

}

void torkview_base::addEntryNodes( bool perm )
{

    TQStringList currentList;
    currentList = TorkConfig::currentEntryNodes();
    TQStringList permList;
    permList = TorkConfig::entryNodes();

    TQListViewItemIterator it(serverList, TQListViewItemIterator::Selected | TQListViewItemIterator::Visible);
    while ( it.current() ) {
        TQString node = "$"+getFPFromFPDigest((*it)->text(2));
        currentList.append(node);
        if (perm)
            permList.append(node);
        //kdDebug() << getFPFromFPDigest((*it)->text(2)) << endl;
        ++it;
    }
    TorkConfig::setCurrentEntryNodes(currentList);
    TorkConfig::setEntryNodes(permList);
    emit copyOldConfig();
    TQListView* tmp = dynamic_cast<TQListView*>(circuitList);
    emit closeAllCircuits(tmp);
    emit updateEntryNodes();

}

void torkview_base::addExitNodes(bool perm , bool strict)
{

    TQStringList currentList;
    currentList = TorkConfig::currentExitNodes();
    TQStringList permList;
    permList = TorkConfig::exitNodes();

    TQListViewItemIterator it(serverList, TQListViewItemIterator::Selected | TQListViewItemIterator::Visible);
    while ( it.current() ) {
        TQString node = "$"+getFPFromFPDigest((*it)->text(2));
        currentList.append(node);
        if (perm){
            permList.append(node);
            if (!TorkConfig::includeServersHistory().contains(TQString("%1-%2-%3")
                .arg((*it)->text(4)).arg((*it)->text(2)).arg((*it)->text(1)))){
                TQStringList existingServers = TorkConfig::includeServersHistory();
                existingServers.append(TQString("%1-%2-%3")
                    .arg((*it)->text(4)).arg((*it)->text(2)).arg((*it)->text(1)));
                TorkConfig::setIncludeServersHistory(existingServers);
            }

        }
        //kdDebug() << getFPFromFPDigest((*it)->text(2)) << endl;
        ++it;
    }
    TorkConfig::setCurrentExitNodes(currentList);
    TorkConfig::setExitNodes(permList);
    if (perm)
      TorkConfig::setStrictExitNodes(strict);

    TQListView* tmp = dynamic_cast<TQListView*>(circuitList);
    emit closeAllCircuits(tmp);

    emit updateExitNodes();
    emit updateStrictExitNodes(strict);
    emit copyOldConfig();

}
void torkview_base::clearInfo_clicked()
{
    infoList->clear();
}


void torkview_base::clearTorTraffic_clicked()
{
    TorTraffic->clear();
}


void torkview_base::clearNonTorTraffic_clicked()
{

    NonTorTraffic->clear();

}

void torkview_base::NonTorTrafficMaxEntries_valueChanged( int newval)
{
    TorkConfig::setNonTorTrafficMaxEntries(newval);
    TorkConfig::writeConfig();
}


void torkview_base::useNewIdentity_clicked( int, int )
{

    emit newIdentity();
}


void torkview_base::useKonqWithTor_clicked( int, int )
{

    emit konqWithTor();
}


void torkview_base::viewNetworkList_clicked( int, int )
{

    emit networkList();
}


void torkview_base::viewHiddenServices_clicked( int, int )
{

    emit hiddenServices();
}


void torkview_base::kcfg_LogNonTorTraffic_toggled( bool state)
{
    TorkConfig::setLogNonTorTraffic(state);
    NonTorTraffic->setEnabled(state);
    emit toggleNonTorTraffic( state );
}


void torkview_base::kcfg_LogTorTraffic_toggled( bool state)
{
    TorkConfig::setLogTorTraffic(state);
/*    TorkConfig::writeConfig();*/
    TorTraffic->setEnabled(state);
    emit toggleTorTraffic( state );
}


void torkview_base::ShowHostNames_toggled( bool safe)
{
  emit safeLogging(!safe);
}

void torkview_base::copyLogLines()
{
  TQClipboard *cb = TQApplication::clipboard();
  TQString logLines;

  TQListViewItemIterator it(infoList, TQListViewItemIterator::Selected | TQListViewItemIterator::Visible);
  while ( it.current() ) {
    // Copy text into the clipboard
    logLines.append((*it)->text(0));
    logLines.append("\t");
    logLines.append((*it)->text(2));
    logLines.append("\t");
    logLines.append((*it)->text(3));
    logLines.append("\n");

     ++it;
  }

  cb->setText( logLines, TQClipboard::Clipboard );

}

void torkview_base::selectAllLogLines()
{
  TQListViewItemIterator it(infoList);
  while ( it.current() ) {
     (*it)->setSelected(true);
     ++it;
  }
  infoList->repaint();
}

void torkview_base::infoList_contextMenuRequested( TQListViewItem *, const TQPoint &point, int )
{
    TQPopupMenu *menu = new TQPopupMenu( infoList );

    menu->clear();
    menu->insertItem( SmallIconSet("copy"), "Copy", this, TQ_SLOT(copyLogLines()) );
    menu->insertSeparator();
    menu->insertItem( "Select All", this, TQ_SLOT(selectAllLogLines()) );
    menu->popup( point );

}


void torkview_base::TorTraffic_contextMenuRequested( TQListViewItem *, const TQPoint &point, int )
{

    TQPopupMenu *menu = new TQPopupMenu( TorTraffic );

    menu->clear();
    menu->insertItem( SmallIconSet("help"), "Resolve Hostname/Address", this, TQ_SLOT(queryHostName()) );
    menu->popup( point );

}

void torkview_base::queryHostName()
{
    TQRegExp rx("[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}");
    TQRegExp rx2("[^:]+");

    TQListView *tmpList;
    TQString addressToResolve;
    TQString addressToMatch;

    if (TorTraffic->hasFocus()) {
      tmpList = TorTraffic;
    }else{
      tmpList = NonTorTraffic;
    }

    int col = (tmpList == TorTraffic) ? 2 : 1;
    rx.search(tmpList->selectedItem()->text(col));
    TQString tmp = rx.cap(0);
    rx2.search(tmpList->selectedItem()->text(col));
    TQString tmp2 = rx2.cap(0);

    if (!tmp.isEmpty()){
        addressToMatch = TQString("REVERSE[%1]").arg(tmp);
        addressToResolve = tmp;
    }else{
        addressToResolve = tmp2;
        addressToMatch = tmp2;
    }

    resolveMap[addressToMatch] = tmpList->selectedItem();
    resolveColMap[tmpList->selectedItem()] = col;

    emit resolveAddress(addressToResolve);
}

void torkview_base::resolvedAddress(const TQString &info)
{
    TQString type = info.section(" ",0,0);
    TQString address = info.section(" ",1,1);

    if (resolveMap[type]){
        int column = resolveColMap[resolveMap[type]];
        resolveMap[type]->setText(column,address);
        resolveMap.erase(type);
        resolveColMap.erase(resolveMap[type]);
    }
}

void torkview_base::NonTorTraffic_contextMenuRequested( TQListViewItem *, const TQPoint &point, int )
{
    TQPopupMenu *menu = new TQPopupMenu( NonTorTraffic );

    menu->clear();
    menu->insertItem( SmallIconSet("help"), "Resolve Hostname/Address", this, TQ_SLOT(queryHostName()) );
    menu->popup( point );

}
