/***************************************************************************
 *   Copyright (C) 2004 by Stefano                                         *
 *   stefano@xiaprojects.com                                               *
 *                                                                         *
 *   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.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "xeplugin_animator.h"

#include "xeconfiguration.h"
#include "xgdocker.h"
#include "xgicon.h"

#include <time.h>

#include <kxdocker_setup_sources.h>

//#undef ENABLE_FINAL

XEPlugin_Animator::XEPlugin_Animator(QObject *parent, const char *name)
 : QObject(parent, name)
{
	XEObject::xPluginAdd(this);
}


XEPlugin_Animator::~XEPlugin_Animator()
{
}


#include "xeplugin_animator.moc"


/*!
    \fn XEPlugin_Animator::xSetup
 */
void XEPlugin_Animator::xSetup()
{
#ifndef ENABLE_FINAL
	qWarning("Animator::xSetup");
#endif
	XEConfiguration *Configurator=(XEConfiguration *)XEObject::xGetConfiguration();
	xGDocker=(XGDocker *)XEObject::xGetDocker();
	if(Configurator==NULL || xGDocker==NULL)
	{
#ifndef ENABLE_FINAL
	// Emits Signal of warning
	//xWarningMsg(this,"error while searching for plugin");
	qWarning("error while searching for plugin");
#endif
		return;
	}
	ActiveConfiguration=Configurator->xGetConfiguration();

	onClickAnimation="bounce";
	onRaiseAnimation="micro";
	onCloseAnimation="poof";
}


/*!
    \fn XEPlugin_Animator::xEventMouseClick(int,int,int,int)
 */
void XEPlugin_Animator::xEventMouseClick(int icon,int x,int y,int button)
{
	//if(AnimationsMutex.tryLock()==false)return;
#ifndef ENABLE_FINAL
	qWarning("Animation");
#endif
	if(icon<0||icon>=ActiveConfiguration->ObjectsIcons.count())return;
#ifndef ENABLE_FINAL
	qWarning("xeplugin_animator.cpp:67");
#endif
	
	//if(x!=xGDocker->xLastX || y!=xGDocker->xLastY )return;
	if(button!=Qt::LeftButton)return;
	
	//0.25 patch
	// this will not animate a separator
	if(ActiveConfiguration->ObjectsIcons.at(icon)->Info.className=="GSeparator")return;
	
	if(ActiveConfiguration->ObjectsIcons.at(icon)->Tasks.TaskInfo==NULL)
	{
		xAnimateBounce(this->xGDocker->getObjectIcon(icon));
	}
	else
	{
		xAnimateMicro(this->xGDocker->getObjectIcon(icon));
	}
}


/*!
    \fn XEPlugin_Animator::xStop()
 */
void XEPlugin_Animator::xStop()
{
    /// @todo implement me
}


/*!
    \fn XEPlugin_Animator::xStart()
 */
void XEPlugin_Animator::xStart()
{
#ifndef ENABLE_FINAL
	qWarning("void XEPlugin_Animator::xStart() [97]");
#endif
	for(int i=0;i<ActiveConfiguration->Plugins.Plugin.count(); i++)
	{
#ifndef ENABLE_FINAL
		qWarning(ActiveConfiguration->Plugins.Plugin.at(i)->Info.Name);
#endif
		if(ActiveConfiguration->Plugins.Plugin.at(i)->Info.Name=="xAnimator")
		{
#ifndef ENABLE_FINAL
		qWarning("void XEPlugin_Animator::xStart() parsing xml configuration");
#endif
		if(ActiveConfiguration->Plugins.Plugin.at(i)->xmlConfiguration.count())
		{
#ifndef ENABLE_FINAL
			qWarning("parsing...");
			qWarning(
ActiveConfiguration->Plugins.Plugin.at(i)->xmlConfiguration.item(0).toElement().attribute("onClickAnimation")
			);
#endif
			
			onClickAnimation=
			ActiveConfiguration->Plugins.Plugin.at(i)->xmlConfiguration.item(0).toElement().attribute("onClickAnimation", "bounce");
			onRaiseAnimation=
			ActiveConfiguration->Plugins.Plugin.at(i)->xmlConfiguration.item(0).toElement().attribute("onRaiseAnimation", "micro");
			onCloseAnimation=
			ActiveConfiguration->Plugins.Plugin.at(i)->xmlConfiguration.item(0).toElement().attribute("onCloseAnimation", "poof");
		}
		else
		{
		// Ok, You don't have specified the xml configuration, we have to create it!!
			
			// Creating fake document
			QDomDocument 	doc( "KXDocker_Conf" );
			// the fake root
			QDomElement fakeRoot=doc.createElement("FakeRoot");
			// appending childs
			doc.appendChild(fakeRoot);
			// now creating the configuration
			QDomElement CreatingCfg=doc.createElement("pluginconf");
			// Ok this is a plugin Configuration
			QStringList	a;
			// Creating the Attributes via the standard plugin interface
			xGetParameterList(&a);
			for(int istoringXML=0;istoringXML<a.count();istoringXML++)
			{
				QString returnValue;
				xGetParameter(a[istoringXML],returnValue);
				CreatingCfg.setAttribute(a[istoringXML],returnValue);
			}
			// Now appending to the configuration
			fakeRoot.appendChild(CreatingCfg);
			ActiveConfiguration->Plugins.Plugin.at(i)->xmlConfiguration=fakeRoot.childNodes();//fakeRoot.elementsByTagName("pluginconf");
		
		}
		
		break;
		}
	
	}
	
	if(onClickAnimation=="bounce")
	connect(xGDocker,SIGNAL(xEventMouseClick(int,int,int,int)),
		this,SLOT(xEventMouseClick(int,int,int,int)));
	connect(xGDocker,SIGNAL(xEventReset(int,int)),
		this,SLOT(xEventReset(int,int)));
	connect(xGDocker,SIGNAL(xEventAnimateTo(int,int,int,int)),
		this,SLOT(xEventAnimateTo(int,int,int,int)));
	QObject *TaskManager=XEObject::xFindObject("xTaskManager");
	if(onCloseAnimation=="micro")
	connect(TaskManager,SIGNAL(xEventRemoveIcon(int)),this,SLOT(xEventTaskOpen(int)));
	if(onCloseAnimation=="poof")
	{
	connect(xGDocker,SIGNAL(xEventRemoveIcon(int )),
		this,SLOT(xEventRemoveIcon(int )));
	
	connect(TaskManager,SIGNAL(xEventRemoveIcon(int )),
		this,SLOT(xEventRemoveIcon(int )));
	}
	if(onRaiseAnimation=="micro")
	connect(TaskManager,SIGNAL(xEventTaskOpen(int)),this,SLOT(xEventTaskOpen(int)));
	lastIcon=NULL;
	mouse.setX(0);
	mouse.setY(0);
	mousef.setX(0);
	mousef.setY(0);
	moltiplier=0;
	lastRaise=0;
	AnimationsMutex.unlock();
	
}


/*!
    \fn XEPlugin_Animator::xAnimateBounce(XGIcon *)
 */
void XEPlugin_Animator::xAnimateBounce(XGIcon *Icon)
{

	//xGDocker->isAnimating=0;
	if(AnimationsMutex.tryLock()==false)return;
	//AnimationsMutex.lock();
	lastIcon=Icon;
	mousef.setY(Icon->xPosition.y());
	mouse.setX(xGDocker->xLastX);
	mouse.setY(xGDocker->xLastY);
	xAnimateStepBounce();


	return;
}


/*!
    \fn XEPlugin_Animator::xEventTaskOpen(int)
 */
void XEPlugin_Animator::xEventTaskOpen(int icon)
{
	//if(AnimationsMutex.tryLock()==false)return;
#ifndef ENABLE_FINAL
	char pippo[50];
	sprintf(pippo,"void XEPlugin_Animator::xEventTaskOpen(int %d)",icon);
	qWarning(pippo);
#endif
	xAnimateMicro(xGDocker->getObjectIcon(icon));
	//xGDocker->xUpdate();
	//xGDocker->update();
	//xGDocker->repaint(false);
}


/*!
    \fn XEPlugin_Animator::xEventReset()
 */
void XEPlugin_Animator::xEventReset(int x, int y)
{
	if(AnimationsMutex.tryLock()==false)return;
#ifndef ENABLE_FINAL
	qWarning("Animating reset");
#endif
	
	
	mouse.setX(x);
	mouse.setY(y);
	xGDocker->isAnimating=1;
	moltiplier=1;
	xAnimate();
}


/*!
    \fn XEPlugin_Animator::xAnimate(int)
 */
void XEPlugin_Animator::xAnimate()
{
	timespec req,   rem;
	req.tv_nsec=ActiveConfiguration->Engine.SleepAnimations;
	if(xGDocker->getRaised()&&xGDocker->xLastX==mouse.x()&&xGDocker->xLastY==mouse.y())
	{
		mouse.setY(mouse.y()-moltiplier);
		moltiplier++;
		//QMouseEvent e(QEvent::MouseMove,mouse,0,0);
		//xGDocker->mouseMoveEventSW(&e);
		xGDocker->mouseMoveEventSW(mouse.x(),mouse.y());
		xGDocker->xUpdate();
		//nanosleep(&req,&rem);
		//QTimer::singleShot(0,this,SLOT(xAnimate()));
		xGDocker->repaint(false);
		xAnimate();
	}
	else
	{
		xGDocker->isAnimating=0;
		
		AnimationsMutex.unlock();
	}
}


/*!
    \fn XEPlugin_Animator::xEventAnimateTo(int,int,int,int)
 */
void XEPlugin_Animator::xEventAnimateTo(int x,int y,int fx,int fy)
{
	//if(AnimationsMutex.tryLock()==false)return;
#ifndef ENABLE_FINAL
	qWarning("undoreset start");
#endif
	mouse.setX(x);
	mouse.setY(y);
	mousef.setX(fx);
	mousef.setY(fy);
	xGDocker->isAnimating=1;
	moltiplier=1;

	xAnimateTo();
}


/*!
    \fn XEPlugin_Animator::xAnimateTo()
 */
void XEPlugin_Animator::xAnimateTo()
{
	timespec req,   rem;
	req.tv_nsec=ActiveConfiguration->Engine.SleepAnimations;
	//qWarning("undoreset polling");
	if(
	xGDocker->xLastX<mousef.x()+20&&xGDocker->xLastX>mousef.x()-20 &&
	xGDocker->xLastY<mousef.y()+20&&xGDocker->xLastY>mousef.y()-20)
	{
		if(mousef.y()<=mouse.y())
		{
			mousef.setY(mousef.y()+moltiplier);
			moltiplier++;
			//QMouseEvent e(QEvent::MouseMove,mousef,0,0);
			//xGDocker->mouseMoveEventSW(&e);
			//mouseMoveEventSW(int x,int y,int force,Qt::ButtonState button)
			xGDocker->mouseMoveEventSW(mousef.x(),mousef.y());
			xGDocker->xUpdate();
			xGDocker->repaint(false);
			//nanosleep(&req,&rem);
			
			QTimer::singleShot(
			ActiveConfiguration->Engine.SleepAnimations/10
				,this,SLOT(xAnimateTo()));
				
			//xAnimateTo();
		}
	}
	else
	{
		xGDocker->isAnimating=0;
		AnimationsMutex.unlock();

	}
}


/*!
    \fn XEPlugin_Animator::xAnimateBounce(XGIcon *Icon)
 */
void XEPlugin_Animator::xAnimateMicro(XGIcon *Icon)
{
	if(AnimationsMutex.tryLock()==false)return;
	//AnimationsMutex.lock();
#ifndef ENABLE_FINAL
	qWarning("Animate::Micro");
#endif
	if(Icon==NULL)return;
#ifndef ENABLE_FINAL
	qWarning("Animate::Micro 311");
#endif
	//xGDocker->isAnimating=0;
	lastIcon=Icon;
	mousef.setY(Icon->xPosition.y());
	mousef.setX(Icon->xPosition.x());
	mouse.setX(xGDocker->xLastX);
	mouse.setY(xGDocker->xLastY);
	moltiplier=Icon->xZoom;
	lastRaise=xGDocker->getRaised();
#ifndef ENABLE_FINAL
	qWarning("Animate::Micro 319");
#endif
	xAnimateStepMicro();
#ifndef ENABLE_FINAL
	qWarning("Animate::Micro 321");
#endif
	
	return;
}


/*!
    \fn XEPlugin_Animator::xEventRemoveIcon(int)
 */
void XEPlugin_Animator::xEventRemoveIcon(int icon)
{
	if(AnimationsMutex.tryLock()==false)return;
	timespec req,   rem;
	req.tv_nsec=ActiveConfiguration->Engine.SleepAnimations*1000*1000;
	req.tv_sec=0;
	// poof animation
#ifndef ENABLE_FINAL
	qWarning("Poof Animations");
#endif
	XGIcon *Icon=xGDocker->getObjectIcon(icon);
	int lastx=Icon->xPosition.x();
	int lasty=Icon->xPosition.y();
	int lastz=Icon->xZoom;
	QImage Poof=Icon->Poof;
	if(Poof.isNull())
	{
		Poof=ActiveConfiguration->Theme.Poof;
	}
#ifndef ENABLE_FINAL
#else
	char pippo[50];
	sprintf(pippo,"Poof: %d %d %d",
		lastz,
		Poof.width(),
		Poof.height());
#endif
	Poof=Poof.smoothScale(lastz,lastz,QImage::ScaleMax);
#ifndef ENABLE_FINAL
#else
	qWarning(pippo);
	sprintf(pippo,"Poof Size: %d %d",
		lastz,
		Poof.width(),
		Poof.height());
	// now paint this
	qWarning(pippo);
#endif
	QImage RenderBuffer,Rendered;
	RenderBuffer.create(lastz,lastz,32);
	RenderBuffer.setAlphaBuffer(false);
	RenderBuffer.fill(0);
	RenderBuffer.setAlphaBuffer(true);
	for(int i=0;i*lastz<Poof.height();i=i+1)
	{
		Rendered.reset();
		Rendered=RenderBuffer.copy();
		bitBlt(&Rendered,0,0,&Poof,0,i*lastz,lastz,lastz);
		Icon->xImgShowed=Rendered;
		//xGDocker->xDockerRedraw(lastIcon);
		xGDocker->xDockerRedraw(Icon);
		//xGDocker->xUpdate();
		//xGDocker->repaint(false);
		//req*10);
		usleep(ActiveConfiguration->Engine.SleepAnimations*100);
		//nanosleep(&req,&rem);
		qWarning("Poof Animations !!!");
#ifndef ENABLE_FINAL
		qWarning("Poof Animations !!!");
#endif

	}
#ifndef ENABLE_FINAL
	qWarning("Poof End");
#endif
	//Icon->xSetUpdate=1;
	Icon->xZoom=0;
	Icon->xSetZoom(lastz);
	AnimationsMutex.unlock();
	
}


/*!
    \fn XEPlugin_Animator::xAnimateStepBounce()
 */
void XEPlugin_Animator::xAnimateStepBounce()
{
	//qWarning("Animate::Bounce Step!");
	if(lastIcon==NULL)return;
	
	double radr=6.28/360;
	static double radians=0;
	int lasty=mousef.y();

	
	if(radians<=6.28
	&&
	xGDocker->xLastX==mouse.x()
	&&
	!xGDocker->isAnimating
//	&&
//	xGDocker->getRaised()
	&&
	xGDocker->xLastY==mouse.y())
	{
		
		radians=radians+radr*8;
		lastIcon->xPosition.setY(
		int(
		lasty-sin(radians)*15*sin(radians)
		)
		);
		//xGDocker->xUpdate();
		// new engine 20040611
		// let's redraw only 1 icon :)
		xGDocker->xDockerRedraw(lastIcon);
		//xGDocker->repaint(false);
		QTimer::singleShot(
			ActiveConfiguration->Engine.SleepAnimations/10
				,this,SLOT(xAnimateStepBounce()));
	}
	else
	{
		radians=0;
#ifndef ENABLE_FINAL
		qWarning("Interrotta animazione! 2");
#endif
#ifdef ENABLE_SPECIALENGINE2
#else
		if(xGDocker->isAnimating)// ||!xGDocker->getRaised())
#endif
		{
#ifndef ENABLE_FINAL
			qWarning("Interrotta animazione! 1");
#endif
			AnimationsMutex.unlock();
			return;
		}
		lastIcon->xPosition.setY(lasty);
		//xGDocker->isAnimating=0;
		//xGDocker->xUpdate();
#ifdef ENABLE_SPECIALENGINE2
		// isAnimating is useful but on sp2 the  are not right than we ask to redraw all :(
		qWarning("sp2 enabled");
		xGDocker->mouseMoveEventSW(xGDocker->xLastX,xGDocker->xLastY,1);
#else
		xGDocker->xDockerRedraw(lastIcon);
#endif
		//xGDocker->repaint(false);
		AnimationsMutex.unlock();
		
	}
	
}


/*!
    \fn XEPlugin_Animator::xAnimateStepMicro()
 */
void XEPlugin_Animator::xAnimateStepMicro()
{
	
	
#ifndef ENABLE_FINAL
	qWarning("Animate::Bounce Step!");
 #endif
	if(lastIcon==NULL)return;
	
	static int i=0;
	int lasty=mousef.y();
	int lastx=mousef.x();
	int lastZoom=moltiplier;
	
	
	if(i<16 && (lastZoom-i*2)>3
	&&
	lastIcon->xZoom==(lastZoom-i*2)
	&&
	!xGDocker->isAnimating
	&&
	xGDocker->getRaised()==lastRaise
	&&
	xGDocker->xLastX==mouse.x()
	&&
	xGDocker->xLastY==mouse.y())
	{
#ifndef ENABLE_FINAL
		qWarning("Animate::Bounce Step! 487");
#endif		
		i=i+2;
		
		lastIcon->xPosition.setY(lasty+i);
		lastIcon->xPosition.setX(lastx+i);
		lastIcon->xSetZoom(lastZoom-i*2);
		//xGDocker->xUpdate();
		xGDocker->xDockerRedraw(lastIcon);
		//xGDocker->repaint(false);
#ifndef ENABLE_FINAL
		qWarning("Animate::Bounce Step! 496");
#endif
		QTimer::singleShot(
			ActiveConfiguration->Engine.SleepAnimations/10
				,this,SLOT(xAnimateStepMicro()));
	}
	else
	{
	
		i=0;
		if(xGDocker->getRaised()!=lastRaise 
			||xGDocker->isAnimating
			||
			xGDocker->xLastX!=mouse.x()
			||
			xGDocker->xLastY!=mouse.y()
			//||lastIcon->xZoom!=(lastZoom-i*2)
			)
		{
			AnimationsMutex.unlock();
			return;
		}
	
#ifndef ENABLE_FINAL
		qWarning("Animate::Bounce Step! 503");
#endif
		//xGDocker->isAnimating=0;
		lastIcon->xPosition.setY(lasty);
		lastIcon->xPosition.setX(lastx);
		lastIcon->xSetZoom(lastZoom);
		//xGDocker->xUpdate();
		xGDocker->xDockerRedraw(lastIcon);
		//xGDocker->repaint(false);
		AnimationsMutex.unlock();
//		xGDocker->mouseMoveSoftware(xGDocker->xLastX,xGDocker->xLastY);
		//xGDocker->repaint(false);
		
	}
	
#ifndef ENABLE_FINAL
	qWarning("Animate::Bounce Step! 514");
#endif	
	
}


/*!
    \fn XEPlugin_Animator::xGetParameter(const QString, QString&)
 */
void XEPlugin_Animator::xGetParameter(const QString sName, QString& sValue)
{
	if(sName=="onCloseAnimation")
	{
		sValue=(onCloseAnimation);
	}
	if(sName=="onRaiseAnimation")
	{
		sValue=(onRaiseAnimation);
	}
	if(sName=="onClickAnimation")
	{
		sValue=(onClickAnimation);
	}
}


/*!
    \fn XEPlugin_Animator::xGetParameterList(QStringList *)
 */
void XEPlugin_Animator::xGetParameterList(QStringList *a)
{
	a->append("onClickAnimation");
	a->append("onRaiseAnimation");
	a->append("onCloseAnimation");
}


/*!
    \fn XEPlugin_Animator::xSetupParameter(const QString, const QString)
 */
void XEPlugin_Animator::xSetupParameter(const QString sName,const QString sValue)
{
	if(sName=="onCloseAnimation")
	{
		onCloseAnimation=sValue;
	}
	if(sName=="onRaiseAnimation")
	{
		onRaiseAnimation=sValue;
	}
	if(sName=="onClickAnimation")
	{
		onClickAnimation=sValue;
	}
	
	for(int i=0;i<ActiveConfiguration->Plugins.Plugin.count(); i++)
	{
		if(ActiveConfiguration->Plugins.Plugin.at(i)->Info.Name=="xAnimator")
		{
		// update xml configuration
		ActiveConfiguration->Plugins.Plugin.at(i)->xmlConfiguration.item(0).toElement().setAttribute
		("onClickAnimation",onClickAnimation);
		ActiveConfiguration->Plugins.Plugin.at(i)->xmlConfiguration.item(0).toElement().setAttribute
		("onRaiseAnimation",onRaiseAnimation);
		ActiveConfiguration->Plugins.Plugin.at(i)->xmlConfiguration.item(0).toElement().setAttribute
		("onCloseAnimation",onCloseAnimation);
		}
	}
	
}
