/*
 *
 * Copyright (C) 2002 George Staikos <staikos@kde.org>
 * Copyright (C) 2002 Richard Moore <rich@kde.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */


#include <qlayout.h>
#include <qvbox.h>
#include <qcolor.h>
#include <qrect.h>
#include <qpoint.h>

#include <kcmenumngr.h>
#include <kdebug.h>
#include <kwin.h>

#include "qtvision.h"
#include "viewmanager.h"

#include "qtvisionwidget.h"
#include "qtvisionwidget.moc"

QtVisionWidgetFrame::QtVisionWidgetFrame( QtVisionWidget *parent, const char *name )
    : QVBox( parent, name )
{
    this->parent = parent;
}

QtVisionWidgetFrame::~QtVisionWidgetFrame()
{
}

void QtVisionWidgetFrame::closeEvent( QCloseEvent *ev )
{
    ev->ignore();
    emit parent->frameCloseEvent();
}

void QtVisionWidgetFrame::moveEvent( QMoveEvent *ev )
{
    if (parent->mode == QtVisionWidget::ViewTopLevel && !parent->reparenting) {
	parent->driver()->config()->topLevelPos = ev->pos();
	kdDebug() << "moveEvent " << ev->pos().x() << "," << ev->pos().y() << endl;
    }
}

void QtVisionWidgetFrame::resizeEvent( QResizeEvent *ev )
{
    if (parent->mode == QtVisionWidget::ViewTopLevel) {
	parent->driver()->config()->topLevelSize = ev->size();
	kdDebug() << "resizing " << ev->size().width() << "," << ev->size().height() << endl;
    }
}

QtVisionWidget::QtVisionWidget( QWidget *parent, const char *name, int wflags )
    : QHBox( parent, name ? name : "qtvision_widget", wflags ? wflags : WStyle_Customize | WStyle_Tool ),
      DCOPObject( "QtVisionViewIface" ),
      qtv(0), frame(0), screen(0), mode( ViewNormal ), floating(false), reparenting(false)
{
    setPaletteBackgroundColor( QColor( 0, 0, 0 ) );
    setDriver( new QtVision( this ) );
}

QtVisionWidget::QtVisionWidget( QtVision *qtv, QWidget *parent, const char *name, int wflags )
    : QHBox( parent, name ? name : "qtvision_widget", wflags ? wflags : WStyle_Customize | WStyle_Tool ),
      DCOPObject( "QtVisionViewIface" ),
      qtv(0), frame(0), screen(0), mode(ViewNormal), floating(false), reparenting(false)
{
    setPaletteBackgroundColor( QColor( 0, 0, 0 ) );
    setDriver( qtv );
}

QtVisionWidget::~QtVisionWidget()
{
}

DCOPRef QtVisionWidget::driverIface() const
{
    return DCOPRef( qtv );
}

void QtVisionWidget::setDriver( QtVision *drv )
{
    if ( qtv && (qtv->parent() == this) ) {
	delete qtv;
	screen = 0;
    }

    qtv = drv;
    if ( !qtv )
	return;

    frame = new QtVisionWidgetFrame( this );
    frame->setPaletteBackgroundColor( QColor( 0, 0, 0 ) );

    connect( drv, SIGNAL( channelChanged(const QString &) ),
	     frame, SLOT( setCaption(const QString & ) ) );

    screen = qtv->createScreen( frame );
    connect( screen, SIGNAL( doubleClicked() ), this, SLOT( nextViewMode() ) );

    connect( drv->views(), SIGNAL( stayOnTopChanged(bool) ),
	    SLOT( stayOnTopCfgChanged(bool) ) );
}

void QtVisionWidget::addContextMenu( QPopupMenu *pop )
{
    if ( !pop )
	return;
    if ( !screen )
	return;

    KContextMenuManager::insert( screen, pop );
}

void QtVisionWidget::resetViewMode()
{
    setViewMode( ViewNormal );
}

void QtVisionWidget::nextViewMode()
{
    kdDebug() << "QtVisionWidget::nextViewMode() Current is " << viewMode() << endl;

    // Note: We don't want to switch to the ViewNone mode
    int m = viewMode();
    if ( ++m > ViewMaxIterable )
	m = ViewNormal;
    setViewMode( m );
}

void QtVisionWidget::toggleFullScreen()
{
    if ( isShowFullScreen() ) {
	setViewMode( (oldMode <= ViewMaxIterable) ? oldMode : ViewNormal );
    }
    else {
	oldMode = viewMode();
	setShowFullScreen( true );
    }
}

void QtVisionWidget::setViewMode( int mode )
{
    switch( mode ) {
	case ViewNone:
	    kdDebug() << "QtVisionWidget::setViewMode(): Setting ViewNone" << endl;
	    setShowNone( true );
	    break;
	case ViewNormal:
	    kdDebug() << "QtVisionWidget::setViewMode(): Setting ViewNormal" << endl;
	    setShowNormal( true );
	    break;
	case ViewTopLevel:
	    kdDebug() << "QtVisionWidget::setViewMode(): Setting ViewTopLevel" << endl;
	    setShowTopLevel( true );
	    break;
	case ViewFullScreen:
	    kdDebug() << "QtVisionWidget::setViewMode(): Setting ViewFullScreen" << endl;
	    setShowFullScreen( true );
	    break;
	case ViewVideoDesktop:
	    kdDebug() << "QtVisionWidget::setViewMode(): Setting ViewVideoDesktop" << endl;
	    setShowVideoDesktop( true );
	    break;
	default:
	    kdDebug() << "QtVisionWidget::setViewMode(): Unknown mode " << mode
		      << ", defaulting to ViewNormal" << endl;
	    setShowNormal( true );
	    break;
    }
}

void QtVisionWidget::setShowNone( bool enable )
{
    kdDebug() << "QtVisionWidget::setShowNone(): " << enable << endl;
    if ( !enable )
	return;
    if ( !screen )
	return;
    if ( isShowNone() )
	return;
    if ( isShowVideoDesktop() )
	qtv->setVideoDesktop(false);

    setFloating( false );

    mode = ViewNone;
    emit showNone( true );
    emit viewModeChanged( mode );
}

void QtVisionWidget::setShowNormal( bool enable )
{
    kdDebug() << "QtVisionWidget::setShowNormal(): " << enable << endl;
    if ( !enable )
	return;
    if ( !screen )
	return;
    if ( isShowNormal() )
	return;
    if ( isShowVideoDesktop() )
	qtv->setVideoDesktop(false);

    setFloating( false );

    mode = ViewNormal;
    emit showNormal( true );
    emit viewModeChanged( mode );
}

void QtVisionWidget::setShowTopLevel( bool enable )
{
    kdDebug() << "QtVisionWidget::setShowTopLevel(): " << enable << endl;
    if ( !enable )
	return;
    if ( !screen )
	return;
    if ( isShowTopLevel() )
	return;
    if ( isShowVideoDesktop() )
	qtv->setVideoDesktop(false);

    setFloating( true );

    mode = ViewTopLevel;
    emit showTopLevel(true);
    emit viewModeChanged( mode );
}

void QtVisionWidget::setShowFullScreen( bool enable )
{
    kdDebug() << "QtVisionWidget::setShowFullScreen(): " << enable << endl;
    if ( !enable )
	return;
     if ( !screen )
	 return;
     if ( isShowFullScreen() )
	 return;
     if ( isShowVideoDesktop() )
	 qtv->setVideoDesktop(false);

     setFloating( true );

     mode = ViewFullScreen;
     frame->showFullScreen();

     emit showFullScreen( true );
     emit viewModeChanged( mode );
 }

 void QtVisionWidget::setShowVideoDesktop( bool enable )
 {
     kdDebug() << "QtVisionWidget::setShowVideoDesktop(): " << enable << endl;
     if ( !enable )
	return;
    if ( !screen )
	return;    
    if ( isShowVideoDesktop() )
	return;

    setFloating( false );
    qtv->setVideoDesktop( true );
    kdDebug() << "starting video desktop" << endl;

    mode = ViewVideoDesktop;
    emit showVideoDesktop(true);
    emit viewModeChanged( mode );
}

void QtVisionWidget::setFloating( bool enable )
{
    kdDebug() << "QtVisionWidget::setFloating() " << enable << endl;
    if ( isShowFullScreen() ) {
	frame->showNormal();
    }

    bool hasChange = floating != enable;
    if ( hasChange && enable ) {
	driver()->config()->topLevelPos = mapToGlobal(pos());
    }

    // we detach the screen even if already floating, because
    // otherwise window border and stay on top settings are not
    // correctly restored
    floating = enable;
    if ( enable )
	detachScreen();
    else
	attachScreen();

    if (hasChange)
	emit floatingChanged( floating );

    kdDebug() << "QtVisionWidget::setFloating() " << enable << " done" << endl;
}

void QtVisionWidget::detachScreen()
{
    kdDebug() << "QtVisionWidget::detachScreen" << endl;

    // Save icons
    QWidget *win = topLevelWidget();
    QPixmap miniIcon = KWin::icon( win->winId(), 16, 16, true );
    QPixmap icon = KWin::icon( win->winId(), 34, 34, false );
    if ( icon.isNull() )
	icon = KWin::icon( win->winId(), 32, 32, true );
    if ( icon.isNull() ) {
	const QPixmap *px = win->icon();
	if ( px )
	    icon = *px;
	else
	    icon.resize( 0, 0 );
    }
    
    // Reparent
    WFlags options = WStyle_Customize | WStyle_Tool;
    if ( driver()->config()->stayOnTop )
	options |= WStyle_StaysOnTop;

    frame->resize(driver()->config()->topLevelSize);
    reparenting = true;
    frame->reparent( 0, options, driver()->config()->topLevelPos, true );
    reparenting = false;

    // Set icons for top level
    frame->setIcon( icon );
    KWin::setIcons( frame->winId(), icon, miniIcon );

}

void QtVisionWidget::attachScreen()
{
    kdDebug() << "QtVisionWidget::attachScreen" << endl;
    frame->reparent( this, WStyle_Customize | WStyle_Tool, QPoint(0,0), true );
    updateGeometry();
}

void QtVisionWidget::stayOnTopCfgChanged(bool enable)
{
    if (enable) {
	KWin::setState(winId(), NET::StaysOnTop);
	KWin::setState(frame->winId(), NET::StaysOnTop);
    } else {
	KWin::clearState(winId(), NET::StaysOnTop);
	KWin::clearState(frame->winId(), NET::StaysOnTop);
    }
}

void QtVisionWidget::bringToFront()
{
    if (floating) {
	frame->setActiveWindow();
	frame->raise();
    }
}
