/*************************************************************************\
*   Copyright (C) 2009 by Ulf Kreissig                                    *
*   udev@gmx.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 Street, Fifth Floor, Boston, MA 02110-1301 USA            *
\*************************************************************************/

#ifndef YET_ANOTHER_WEATHER_PLASMOID_H
#define YET_ANOTHER_WEATHER_PLASMOID_H

//--- LOCAL CLASSES ---
#include "statemachine.h"
#include "pageanimator.h"
#include "weatherservice.h"
#include "yawpday.h"
#include "configdialog/yawpconfig.h"
#include "panellayout.h"

//--- QT4 CLASSES ---
#include <QBasicTimer>
#include <QGraphicsSceneMouseEvent>
#include <QSvgRenderer>
#include <QTimerEvent>
#include <QTimeLine>

//--- KDE4 CLASSES ---
#include <Plasma/Applet>
#include <Plasma/Svg>
#include <Plasma/Weather/WeatherUtils>


class QActionGroup;
class QFont;
class QPainter;
class QRect;
class QTimer;

class KActionMenu;


class YaWP : public Plasma::Applet
{
	Q_OBJECT

	/*   we use the AnimationType as Index in m_vAnimationData,
	 *   since we need space for 5 days SlidingDayNames got index 6
	 *   we will waste one bit, but we need NoAnimation as well.
	 */
	enum AnimationType { NoAnimation=0,
	                     SlidingDayNames,
	                     PageChange,
	                     DetailsChange,
		                 IconAnimation,
	                   };
//	enum PageType { PreviewPage=0, DetailsPage=1, SatelitePage=2 };

public:
	YaWP( QObject * parent, const QVariantList & args );
	virtual ~YaWP();

	void constraintsEvent( Plasma::Constraints constraints );

	QList<QAction *> contextualActions() { return m_actions; }

	/**
	 * This method is called once the applet is loaded and added to a Corona.
	 * If the applet requires a QGraphicsScene or has an particularly intensive
	 * set of initialization routines to go through, consider implementing it
	 * in this method instead of the constructor.
	 *
	 * Note: paintInterface may get called before init() depending on initialization
	 * order. Painting is managed by the canvas (QGraphisScene), and may schedule a
	 * paint event prior to init() being called.
	 **/
    virtual void init();

	// The paintInterface procedure paints the applet to screen
	void paintInterface( QPainter * painter,
	                     const QStyleOptionGraphicsItem * option,
	                     const QRect & contentsRect );

	/**
	 * Reimplement this method so provide a configuration interface,
	 * parented to the supplied widget. Ownership of the widgets is passed
	 * to the parent widget.
	 *
	 * @param parent the dialog which is the parent of the configuration
	 *               widgets
	 */
	virtual void createConfigurationInterface( KConfigDialog * parent );

public slots:
	virtual void setBusy( bool );

protected:
	virtual void mousePressEvent( QGraphicsSceneMouseEvent * event );
	virtual void timerEvent ( QTimerEvent * event );

private slots:
	void about() const;
	
	void slotConfigurationRequired();

	void slotCityUpdate( WeatherServiceModel::ServiceUpdate updateType );
	void changeCity(QAction * action);

	void animationTimeout(int frame);
	void animationFinished();
	void configAccepted();	//--- Called when applet configuration values has changed. ---

	void setDefaultFontColors();


private:
	void loadConfig();
	void loadCustomTheme();
	void setButtonNames();
	void saveConfig();

	void initPageChange( const int iType, const int iNewValue, const bool bForward );
	void initDetailsChange( const Yawp::PageType newPage, const int iNewValue );
	void createAnimationPage( const int iPage, const int iType, const QRectF & pageRect );
	void initWeatherIconAnimation( const QRectF & rect, const int iDay );

	void paintTemperatures( QPainter * painter,
	                        const QRectF & pos,
	                        const YawpWeather & weather,
	                        const Plasma::FormFactor = Plasma::Planar );
	void paintWeatherIcon( QPainter * painter,
	                       const QRectF & pos,
	                       int iDayIndex,
	                       const YawpWeather * pWeather,
	                       bool bToolTip = false );
	void paintTooltipIconTemp( QPainter * painter, const QRectF & rect, const YawpDay * pDay );

	void drawBackground ( QPainter * painter, QRectF rect );
	void paintPanelInformation( QPainter * painter );

	void paintCurrentPage( QPainter * painter, bool bAnimation = true );
	void paintSkeletonPage( QPainter * painter );
	void paintSatellitePage( QPainter * painter );
	void paintTopWeatherInfos( QPainter * painter, int iDayIndex,
	                           bool bShowFancyTemp = false );
	void paintWeatherPreview( QPainter * painter );
	void paintWeatherDetails( QPainter * painter );
	void paintForecastDayNames( QPainter * painter, const bool bDayNames );

	void setCityIndex( int iIndex );
	QString createVisualCityName( const CityWeather * pCity ) const;
	void initPanelLayoutObject( const Plasma::FormFactor form );
	void createPanelTooltip();

	void updateCitySubMenu();

	/*** when the Transition is one of the Rolling/Sliding or Open/Closing Animation
	*    than return this transition or the opponent of it, depending on the Parameter >forward<
	*/
	inline PageAnimator::Transition getSlidingTransition( const PageAnimator::Transition tr, const bool forward ) const;

	inline void drawImage   ( QPainter * painter, const QRectF & rect, const QString & name );

	/** Alignment needs to be an integer to pass flags like Qt::WordWrap to the QPainter::drawText() function.
	*/
	inline void drawText    ( QPainter * painter, const QRectF & rect, int align, const QString & text );
	inline void drawGreyText( QPainter * painter, const QRectF & rect, int align, const QString & text );

	/*** return the absolute area for the buttons ***/
	inline QRectF getButtonRect( const int button ) const;
	inline QRectF getCityArrowRect( const bool bForward ) const;

	inline void setRenderOptions( QPainter * painter, const bool bUse );

	/*** setup m_timeline and m_pageAnimator with the value from m_configData.iAnimationDuration )
	     for the next animation progress ***/
	inline void setupAnimationTimeLine();
	inline void setupWeatherServiceModel();
	inline void stopPendingEngineConnection();
	

	Plasma::Svg                  m_svg;
	Plasma::Svg                  m_customSvg;
	QStringList                  m_vButtonNames;

	QPointer<YawpConfigDialog>   m_pConfigDlg;
	Yawp::ConfigData             m_configData;
	Yawp::Storage                m_storage;


	/**   Just in case the city name is too long, we trimm the cityname and save this one,
	 *    to decrease the number of determining the string.
	 */
	QString                      m_sCityVisualName;

	/**   Model which holds and controls the weatherdata of all cities */
	WeatherServiceModel        * m_pWeatherModel;

	/**   State machine that controls the current state of yawp and incloses the logic in one class. */
	StateMachine                 m_stateMachine;

	KAboutData                 * m_aboutData;

	 /**   Contextual actions - this list holds all actions we want to show in a popup menu */
	QList<QAction *>             m_actions;

	/**   We need this private member variable to disable the menu-entry, while we are updating the data.
	 */
	QAction                    * m_pManualUpdate;

	/**   This list holds a action for all currently configured city, so that the user can change
	 *    the currently shown city using the popup-menu.
	 */
	KActionMenu                * m_pCitySubMenu;

	/**   Controlls the actions in the m_citySubMenu to make them exclusive-checkable */
	QActionGroup               * m_pGrpActionCities;


	/**   Animation information */
	QTimeLine                    m_timeline;
	PageAnimator                 m_pageAnimator;
	AnimationType                m_tAnimationType;	// current active animation, or NoAnimation
	short                        m_iAnimationIndex;	// currently animated weather icon
	bool                         m_bSlidingDayNames; // true == Show Dayname,otherwise show date
	bool                         m_bBusy;

	/**   The desktop layout object determines the rectangels in the desktop and tooltip areas. */
	DesktopLayout                m_desktopLayout;

	/**   Laout the items in the panel */
	AbstractPanelLayout        * m_pPanelLayout;

	/**   Currently used layout, the m_pPanelLayout is only != NULL when we are in panelmode.
	*     But it might be possible that we draw the popup tooltip for the panel.
	*     Some functions like drawText(...) need the currently used Layout.
	*/
	AbstractPanelLayout        * m_pCurrLayout;
	
	// timer-id for a pending connecion to the weather engine
	int                          m_iIdPendingEngineConnection;
};

#endif
