/*
    knetd, KDE Network Daemon

    Copyright (c) 2005 by Engin AYDOGAN		<engin @ bzzzt.biz>

    *************************************************************************
    *                                                                       *
    * 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.                                   *
    *                                                                       *
    *************************************************************************
*/

#include "popupdispatch.h"

#include <math.h> // floor(), ceil()

#include <qwidget.h>
#include <qtimer.h>

#include <kapplication.h>
#include <dcopclient.h>
#include <kglobalsettings.h>
#include <kdebug.h>

PopupDispatch::PopupDispatch( const PopupInternal& tti, PopupDispatch* last, PopupManager* m )
 : m_popupData( tti ), m_previous( last ), m_next( 0 ), m_manager( m ), m_settled( false ), m_new( true )
{
	selfPlace();
}

void
PopupDispatch::selfPlace()
{
	QRect screen = KGlobalSettings::desktopGeometry( m_popupData.widget );
	QPoint origin; // origin of the destination -- crappy naming sorry.
	int frameHeight = m_popupData.widget->frameGeometry().height();
	int frameWidth = m_popupData.widget->frameGeometry().width();
	m_size = m_popupData.widget->frameGeometry().size();
	if( m_previous )
	{
		m_position = m_previous->m_position;

		if( m_position == Top )
		{
			origin = QPoint( screen.width() - frameWidth, m_previous->origin().y() + m_previous->size().height() );
		}
		else if( m_position == Bottom )
		{
			origin = QPoint( screen.width() - frameWidth, m_previous->origin().y() - frameHeight );
		}
		else if( m_position == Left )
		{
			origin = QPoint( m_previous->origin().x() + m_previous->size().width(), m_previous->origin().y() );
		}
		else if( m_position == Right )
		{
			origin = QPoint( m_previous->origin().x() - frameWidth, m_previous->origin().y() );
		}
		// Let the previous one know about us
		m_previous->setNext( this );
	}
	else
	{
		m_position = -1;
		int size = -1;
		// Check the taskbars orientation and position and try to make a sensible choice
		DCOPClient* cl = KApplication::dcopClient();
		QByteArray data, replyData;
		QCString replyType;

		if( cl->call( "kicker", "Panel", "panelPosition()", data, replyType, replyData ) )
		{
			QDataStream r2( replyData, IO_ReadOnly );
			r2 >> m_position;
		} else kdWarning() << k_funcinfo << "Could not receive panel position." << endl;
	
		if( cl->call( "kicker", "Panel", "panelSize()", data, replyType, replyData ) )
		{
			QDataStream r3( replyData, IO_ReadOnly );
			r3 >> size;
		} else kdWarning() << k_funcinfo << "Could not receive panel size." << endl;

		if( m_position == -1 || size == -1 )
		{
			// one or more dcop calls failed default to sane values.
			kdWarning() << k_funcinfo << "Some kicker DCOP calls failed." << endl;
			m_position = 3;
			size = 58;
		}

		if( m_position == Top )
		{
			origin = QPoint( screen.width() - frameWidth, size );
		}
		else if( m_position == Bottom )
		{
			origin = QPoint( screen.width() - frameWidth,
					screen.height() - size - frameHeight );
		}
		else if( m_position == Left )
		{
			origin = QPoint( size, screen.height() - frameHeight );
		}
		else if( m_position == Right )
		{
			origin = QPoint( screen.width() - size - frameWidth,
					screen.height() - frameHeight );
		}
	}

	// TODO setStartingPosition() with a Auto enum available
	if( m_new )
	{
		if( m_position == Top )
		{
			if( m_new ) m_popupData.widget->move( screen.width() - frameWidth, 0 - frameHeight );
		}
		else if( m_position == Bottom )
		{
			if( m_new ) m_popupData.widget->move( screen.width() - frameWidth, screen.height() );
		}
		else if( m_position == Left )
		{
			if( m_new ) m_popupData.widget->move( 0 - frameWidth, screen.height() - frameHeight );
		}
		else if( m_position == Right )
		{	
			if( m_new ) m_popupData.widget->move( screen.width(), screen.height() - frameHeight );
		}
	}
	m_new = false;

	
	m_popupData.widget->installEventFilter( this );

	connect( m_popupData.widget, SIGNAL( destroyed() ), this, SLOT( widgetDestroyed() ) );

	setOrigin( origin );
	if( m_popupData.flags & PopupManager::Animation )
	{
		m_x = m_popupData.widget->x(); // double meta data of current position
		m_y = m_popupData.widget->y(); // double meta data of current position
		m_popupData.widget->show();
		startTimer( 30 );
	}
	else
	{
		m_settled = true;
		m_popupData.widget->move( origin );
		m_popupData.widget->show();
		if( m_popupData.flags & PopupManager::AutoDelete )
		{
			QTimer::singleShot( m_popupData.timeout, this, SLOT( destroy() ) );
		}
	}
}

void
PopupDispatch::setOrigin( const QPoint& p )
{
	m_dst = p;
}

QPoint
PopupDispatch::origin() const
{
	return m_dst;
}

void
PopupDispatch::updateChain()
{
	selfPlace();
	if( m_next ) m_next->updateChain();
}

void
PopupDispatch::setPrev( PopupDispatch* dp )
{
	m_previous = dp;
	updateChain();
}

void
PopupDispatch::setNext( PopupDispatch* dp )
{
	m_next = dp;
}

void
PopupDispatch::timerEvent( QTimerEvent* )
{
	//! TODO: Also make this configurable
	//if( m_previous && !m_previous->settled() ) return;
	double constant = 0.1; //! TODO: make this configurable

	double dx = ( m_dst.x() - m_x ) * constant;
	double dy = ( m_dst.y() - m_y ) * constant;
	m_x += dx;
	m_y += dy;
	int new_x, new_y;
	if( dx < 0 ) // heading to left
		new_x = static_cast<int>(floor(m_x));
	else
		new_x = static_cast<int>(ceil(m_x));

	if( dy < 0 ) // heading to up
		new_y = static_cast<int>(floor(m_y));
	else
		new_y = static_cast<int>(ceil(m_y));

	m_popupData.widget->move( new_x, new_y );
	if( !(m_dst.y() - new_y )  && !( m_dst.x() - new_x ) )
	{
		m_settled = true;
		killTimers();
		if( m_popupData.flags & PopupManager::AutoDelete )
		{
			QTimer::singleShot( m_popupData.timeout, this, SLOT( destroy() ) );
		}
	}
}

PopupDispatch::~PopupDispatch()
{

	if( m_next )
	{
		m_next->setPrev( m_previous );
	}
	else
	{
		m_manager->setLast( m_previous );
	}

	if( m_previous ) m_previous->setNext( m_next );

	if( m_popupData.widget )
	{
		m_popupData.widget->disconnect( this );
		m_popupData.widget->close();
// 		delete m_tti.w;
	}
}

void
PopupDispatch::destroy()
{
	delete this;
}

QSize
PopupDispatch::size() const
{
	return m_size;
}

bool
PopupDispatch::eventFilter( QObject* o, QEvent* e )
{
	if( o == m_popupData.widget && e->type() == QEvent::Resize )
	{
		m_size = static_cast<QWidget*>(o)->frameGeometry().size();
	}
	else if( o == m_popupData.widget && e->type() == QEvent::MouseButtonRelease )
	{
		if( m_popupData.flags & PopupManager::DieOnClick )
		{
			delete this;
		}
	}
	return false;
}

void
PopupDispatch::widgetDestroyed()
{
	m_popupData.widget = 0;
	delete this;
}

bool
PopupDispatch::settled() const
{
	return m_settled;
}

#include "popupdispatch.moc"
