/***************************************************************************
 * $Id: newstreamosd.cpp,v 1.22 2008/08/20 16:49:22 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.              *
 ***************************************************************************/
/* 
 *
 * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org>
 *
 * This file is part of the K3b project.
 * Copyright (C) 1998-2005 Sebastian Trueg <trueg@k3b.org>
 *
 * 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.
 * See the file "COPYING" for the exact licensing terms.
 *
 * Some minor changes for TorK:
 *   Copyright (C) 2006 - 2008 Robert Hogan                                *
 *   robert@roberthogan.net                                                *
 *                                                                         *
 */
 
#include "newstreamosd.h"
#include "torkview.h"
 
#include <tqlistview.h>
#include <tqlayout.h>
#include <tqheader.h>
#include <tqpixmap.h>
#include <tqpainter.h>
#include <tqapplication.h>
#include <tqframe.h>
#include <tqtoolbutton.h>
#include <tqtooltip.h> //TQToolTip::palette()

#include <twin.h>
#include <kiconloader.h>
#include <kdebug.h>
#include <kcursor.h>
#include <tdeconfig.h>
#include <tdelocale.h>
#include <tdepopupmenu.h>
#include <tdeapplication.h>
#include <kiconloader.h>

#include <X11/Xlib.h>


StreamOSD::StreamOSD( torkView* parent, bool tortraffic, const char* name )
  : TQWidget( parent, name, WType_TopLevel | WNoAutoErase | WStyle_Customize | WX11BypassWM | WStyle_StaysOnTop ),
    m_dirty(true),
    m_dragging(false),
    m_screen(0),
    m_position(s_outerMargin, s_outerMargin),
    m_parent(parent),
    m_tortraffic(tortraffic)
{
  setFocusPolicy( NoFocus );
  setBackgroundMode( NoBackground );
  // dummy size
  resize( 250, 125 );

  // make sure we are always visible
  KWin::setOnAllDesktops( winId(), true );

  if (m_tortraffic)
    renderOSD();
  else
    renderNonTorOSD();

}


StreamOSD::~StreamOSD()
{
}




void StreamOSD::setText( const TQString& text )
{
  if( m_text != text ) {
    m_text = text;
    refresh();
  }
}


void StreamOSD::setProgress( int p )
{

  if( m_progress != p ) {
    m_progress = p;
    refresh();
  }
}


void StreamOSD::setPosition( const TQPoint& p )
{
  m_position = p;
  reposition();
}


void StreamOSD::refresh()
{
  if( isVisible() ){
    if (m_tortraffic)
      renderOSD();
    else
      renderNonTorOSD();
  }else
    m_dirty = true;
}


void StreamOSD::renderOSD()
{
    TQColor osdcolor = TQToolTip::palette().color(TQPalette::Active, TQColorGroup::Background);
    int large = font().pointSize();
    int small = font().pointSize() - 1;
    TQFont f( font().rawName(), small );
    setFont( f );
    setWFlags( TQt::WX11BypassWM );
    setPalette(osdcolor);
    setPaletteBackgroundColor(osdcolor);
    //setBackgroundMode( PaletteBase );
    TQGridLayout* TabPageLayout = new TQGridLayout( this, 3, 8, 11, 6, "TabPageLayout"); 
    TabPageLayout->setMargin(2);
    TQLabel* textLabel = new TQLabel( this, "textLabel2" );
    textLabel->setText(i18n("<b>Tor Traffic</b>"));
    TQFont f2( font().rawName(), large  );
    textLabel->setFont( f2 );

    TabPageLayout->addMultiCellWidget( textLabel, 0,0,0,3 );

    changeID = new TQToolButton( this,"changeid" );
    changeID->setIconSet( SmallIconSet( "tork_identity" ) );
    changeID->setUsesTextLabel(false);
    changeID->setMaximumSize(SmallIconSet( "tork_identity" ).iconSize(TQIconSet::Small));
    changeID->adjustSize();
    TabPageLayout->addWidget(changeID,0,5);
    TQToolTip::add( changeID, i18n( "Change the 'Exit' used for current traffic.") );

    
    toggleTDE = new TQToolButton( this,"konq" );
    toggleTDE->setIconSet( SmallIconSet( "tork_konqueroroff" ) );
    toggleTDE->setUsesTextLabel(false);
    toggleTDE->setMaximumSize(SmallIconSet( "tork_konqueroroff" ).iconSize(TQIconSet::Small));
    toggleTDE->adjustSize();
    TabPageLayout->addWidget(toggleTDE,0,6);
    TQToolTip::add( toggleTDE,i18n("Enable/Disable Konqueror's use of Tor"));

    TQToolButton* hideMonitor = new TQToolButton( this,"hide" );
    hideMonitor->setIconSet( SmallIconSet( "cancel" ) );
/*    hideMonitor->setTextLabel(i18n( "Hide" ));
    hideMonitor->setTextPosition(TQToolButton::Right);
    hideMonitor->setUsesTextLabel(true);*/
    hideMonitor->setUsesTextLabel(false);
    hideMonitor->setMaximumSize(SmallIconSet( "cancel" ).iconSize(TQIconSet::Small));
    hideMonitor->adjustSize();
    TabPageLayout->addWidget(hideMonitor,0,7);
    TQToolTip::add( hideMonitor,i18n("Hide this Display."));

    TQToolTip::add( this,i18n("This displays all network activity currently being handled by Tor."));

     connect( hideMonitor, TQ_SIGNAL(clicked()),
         TQ_SLOT(slotHideMonitor()) );
     connect( toggleTDE, TQ_SIGNAL(clicked()),
         TQ_SLOT(slotToggleTDE()) );
     connect( changeID, TQ_SIGNAL(clicked()),
         TQ_SLOT(slotChangeID()) );

//      connect( toggleTDE, TQ_SIGNAL(clicked()),
//          TQ_SLOT(slotToggleTDE()) );


    infoList = new TQListView( this, "infoList" );
    infoList->addColumn(  "StreamID"  );
    infoList->addColumn(  "Host"  );
    infoList->addColumn(  kapp->iconLoader()->loadIconSet("tork_torsmall", TDEIcon::Small),"", 24   );
    infoList->addColumn(  "KB/s"  );
    infoList->addColumn(  "Exit"  );
    infoList->setColumnWidthMode(0, TQListView::Manual);
    infoList->hideColumn(0);
    infoList->hideColumn(2);
    infoList->header()->setResizeEnabled(false, 0);
    infoList->setResizeMode( TQListView::NoColumn );
    infoList->setHScrollBarMode(TQScrollView::AlwaysOff);
    infoList->setVScrollBarMode(TQScrollView::AlwaysOff);
    infoList->setSelectionMode( TQListView::Single );
    TabPageLayout->addMultiCellWidget( infoList, 1,1,0,7 );
    infoList->setPaletteBackgroundColor(osdcolor);
//     infoList->header()->hide();

	m_graphOut = new StatGraph(this,1,0,"Up");
	m_graphIn = new StatGraph(this,1,0,"Down");
    m_graphOut->setReadingColor(TQt::red);
    m_graphIn->setReadingColor(TQt::green);
/*    chart = new Chart(this, m_parent->speedHistoryTx(), m_parent->speedHistoryRx(), m_parent->historyBufferSize(), m_parent->historyPointer(), m_parent->maxSpeed());
    TabPageLayout->addMultiCellWidget( chart, 2,2, 0,3 );
    chart->setMinimumHeight(10);*/
    TabPageLayout->addMultiCellWidget( m_graphOut, 2,2, 0,3 );
    TabPageLayout->addMultiCellWidget( m_graphIn, 2, 2, 4,7 );

    //infoList->adjustSize();
    //frame->update();
     connect( infoList, TQ_SIGNAL( contextMenuRequested(TQListViewItem*,const TQPoint&,int) ), this, TQ_SLOT( contextMenuRequested(TQListViewItem*,const TQPoint&,int) ) );



    TQPoint point;
    TQRect rect( point, size() );
    const uint M = fontMetrics().width( 'x' );


    const uint xround = (M * 200) / size().width();
    const uint yround = (M * 200) / size().height();


    {   /// apply the mask
        static TQBitmap mask;

        mask.resize( size() );
        mask.fill( TQt::black );

        TQPainter p( &mask );
        p.setBrush( TQt::white );
        p.drawRoundRect( rect, xround, yround );
        setMask( mask );
    }

      m_osdBuffer.resize( rect.size() );
      TQPainter p( &m_osdBuffer );
      p.fillRect( rect, backgroundColor() );
      p.setPen( backgroundColor().dark() );
      p.drawRoundRect( rect, xround, yround );
      p.end();

}

void StreamOSD::renderNonTorOSD()
{
    TQColor osdcolor = TQt::green;
    int large = font().pointSize();
    int small = font().pointSize() - 1;
    TQFont f( font().rawName(), small );
    setFont( f );
    setWFlags( TQt::WX11BypassWM );
    setPalette(osdcolor);
    setPaletteBackgroundColor(osdcolor);
    //setBackgroundMode( PaletteBase );
    TQGridLayout* TabPageLayout = new TQGridLayout( this, 3, 8, 11, 6, "TabPageLayout"); 
    TabPageLayout->setMargin(2);
    TQLabel* textLabel = new TQLabel( this, "textLabel2" );
    textLabel->setText(i18n("<b>Tor Traffic</b>"));
    TQFont f2( font().rawName(), large  );
    textLabel->setFont( f2 );

    TabPageLayout->addMultiCellWidget( textLabel, 0,0,0,3 );

    TQToolButton* hideMonitor = new TQToolButton( this,"hide" );
    hideMonitor->setIconSet( SmallIconSet( "cancel" ) );
    hideMonitor->setUsesTextLabel(false);
    hideMonitor->setMaximumSize(SmallIconSet( "cancel" ).iconSize(TQIconSet::Small));
    hideMonitor->adjustSize();
    TabPageLayout->addWidget(hideMonitor,0,7);
    TQToolTip::add( hideMonitor,i18n("Hide this Display."));

    TQToolTip::add( this,i18n("This displays all your system's network activity."));

     connect( hideMonitor, TQ_SIGNAL(clicked()),
         TQ_SLOT(slotHideMonitor()) );


    infoList = new TQListView( this, "infoList" );
    infoList->addColumn(  "Program"  );
    infoList->addColumn(  "Host"  );
    infoList->addColumn(  "KB/s"  );
    infoList->setColumnWidthMode(0, TQListView::Manual);
    infoList->header()->setResizeEnabled(false, 0);
    infoList->setResizeMode( TQListView::NoColumn );
    infoList->setHScrollBarMode(TQScrollView::AlwaysOff);
    infoList->setVScrollBarMode(TQScrollView::AlwaysOff);
    infoList->setSelectionMode( TQListView::Single );
    TabPageLayout->addMultiCellWidget( infoList, 1,1,0,7 );
    infoList->setPaletteBackgroundColor(osdcolor);

	m_graphOut = new StatGraph(this,1,0,"Up");
	m_graphIn = new StatGraph(this,1,0,"Down");
    m_graphOut->setReadingColor(TQt::red);
    m_graphIn->setReadingColor(TQt::green);
    TabPageLayout->addMultiCellWidget( m_graphOut, 2,2, 0,3 );
    TabPageLayout->addMultiCellWidget( m_graphIn, 2, 2, 4,7 );

    TQPoint point;
    TQRect rect( point, size() );
    const uint M = fontMetrics().width( 'x' );


    const uint xround = (M * 200) / size().width();
    const uint yround = (M * 200) / size().height();


    {   /// apply the mask
        static TQBitmap mask;

        mask.resize( size() );
        mask.fill( TQt::black );

        TQPainter p( &mask );
        p.setBrush( TQt::white );
        p.drawRoundRect( rect, xround, yround );
        setMask( mask );
    }

      m_osdBuffer.resize( rect.size() );
      TQPainter p( &m_osdBuffer );
      p.fillRect( rect, backgroundColor() );
      p.setPen( backgroundColor().dark() );
      p.drawRoundRect( rect, xround, yround );
      p.end();

}


void StreamOSD::setScreen( int screen )
{
  const int n = TQApplication::desktop()->numScreens();
  m_screen = (screen >= n) ? n-1 : screen;
  reposition();
}


void StreamOSD::reposition( TQSize newSize )
{
  if( !newSize.isValid() )
    newSize = size();

  TQPoint newPos = m_position;
  const TQRect& screen = TQApplication::desktop()->screenGeometry( m_screen );

  // now to properly resize if put into one of the corners we interpret the position
  // depending on the quadrant
  int midH = screen.width()/2;
  int midV = screen.height()/2;
  if( newPos.x() > midH )
    newPos.rx() -= newSize.width();
  if( newPos.y() > midV )
    newPos.ry() -= newSize.height();

  newPos = fixupPosition( newPos );
 
  // correct for screen position
  newPos += screen.topLeft();
  
  // ensure we are painted before we move
  if( isVisible() )
    paintEvent( 0 );

  // fancy X11 move+resize, reduces visual artifacts
  XMoveResizeWindow( x11Display(), winId(), newPos.x(), newPos.y(), newSize.width(), newSize.height() );
}


void StreamOSD::paintEvent( TQPaintEvent* )
{

    bitBlt( this, 0, 0, &m_osdBuffer );
}


void StreamOSD::mousePressEvent( TQMouseEvent* e )
{
  m_dragOffset = e->pos();

  if( e->button() == LeftButton && !m_dragging ) {
    grabMouse( KCursor::sizeAllCursor() );
    m_dragging = true;
  }
/*  else if( e->button() == RightButton ) {
    TDEPopupMenu m;
    if( m.insertItem( i18n("Hide OSD") ) == m.exec( e->pos() ) )
      hide();
  }*/
}


void StreamOSD::mouseReleaseEvent( TQMouseEvent* )
{
  if( m_dragging ) {
    m_dragging = false;
    releaseMouse();
  }
}


void StreamOSD::mouseMoveEvent( TQMouseEvent* e )
{
  if( m_dragging && this == mouseGrabber() ) {

    // check if the osd has been dragged out of the current screen
    int currentScreen = TQApplication::desktop()->screenNumber( e->globalPos() );
    if( currentScreen != -1 )
      m_screen = currentScreen;

    const TQRect& screen = TQApplication::desktop()->screenGeometry( m_screen );
    
    // make sure the position is valid
    m_position = fixupPosition( e->globalPos() - m_dragOffset - screen.topLeft() );

    // move us to the new position
    move( m_position );

    // fix the position
    int midH = screen.width()/2;
    int midV = screen.height()/2;
    if( m_position.x() + width() > midH )
      m_position.rx() += width();
    if( m_position.y() + height() > midV )
      m_position.ry() += height();
  }
}


TQPoint StreamOSD::fixupPosition( const TQPoint& pp )
{
  TQPoint p(pp);
  const TQRect& screen = TQApplication::desktop()->screenGeometry( m_screen );
  int maxY = screen.height() - height() - s_outerMargin;
  int maxX = screen.width() - width() - s_outerMargin;

  if( p.y() < s_outerMargin )
    p.ry() = s_outerMargin;
  else if( p.y() > maxY )
    p.ry() = maxY;

  if( p.x() < s_outerMargin )
    p.rx() = s_outerMargin;
  else if( p.x() > maxX )
    p.rx() = screen.width() - s_outerMargin - width();

  p += screen.topLeft();

  return p;
}


void StreamOSD::readSettings( TDEConfigBase* c )
{
  TQString oldGroup = c->group();
  if (m_tortraffic)
    c->setGroup( "TorKOSD Position" );
  else
    c->setGroup( "NonTorOSD Position" );

  setPosition( c->readPointEntry( "Position", 0 ) );
  setScreen( c->readNumEntry( "Screen", 0 ) );
    
  c->setGroup( oldGroup );
}


void StreamOSD::saveSettings( TDEConfigBase* c )
{
  TQString oldGroup = c->group();
  if (m_tortraffic)
    c->setGroup( "TorKOSD Position" );
  else
    c->setGroup( "NonTorOSD Position" );

  c->writeEntry( "Position", m_position );
  c->writeEntry( "Screen", m_screen );

  c->setGroup( oldGroup );
}

void StreamOSD::slotHideMonitor( )
{
    emit requestHideMonitor();
}

void StreamOSD::slotChangeID( )
{
    emit requestChangeID();
}

void StreamOSD::slotToggleTDE( )
{
    emit requestToggleTDE();
}

void StreamOSD::contextMenuRequested( TQListViewItem *, const TQPoint &point, int )
{

    TQPopupMenu *menu = new TQPopupMenu( infoList );

    menu->clear();
    menu->insertItem( "Close Stream", this,TQ_SLOT(slotCloseStream()) );
    menu->popup( point );

}


void StreamOSD::slotCloseStream( )
{

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


}

#include "newstreamosd.moc"
