/*
 *   Copyright (C) 2008 Petri Damstén <damu@iki.fi>
 *   Copyright (C) 2010 Matthias Fuchs <mat69@gmx.net>
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Library General Public License version 2 as
 *   published by the Free Software Foundation
 *
 *   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 Library 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 COMICPROVIDERWRAPPER_H
#define COMICPROVIDERWRAPPER_H

#include "comicprovider.h"

#include <QBuffer>
#include <QImage>
#include <QImageReader>
#include <QByteArray>

namespace Kross {
    class Action;
}
namespace Plasma {
    class Package;
}
class ComicProviderKross;

class ImageWrapper : public QObject
{
        Q_OBJECT
        Q_PROPERTY( QImage image READ image WRITE setImage )
        Q_PROPERTY( QByteArray rawData READ rawData WRITE setRawData )
    public:
        explicit ImageWrapper( QObject *parent = 0, const QByteArray &image = QByteArray() );

        QImage image() const;
        /**
         * Sets the image, rawData is changed to the new set image
         */
        void setImage( const QImage &image );
        QByteArray rawData() const;

        /**
         * Sets the rawData, image is changed to the new rawData
         */
        void setRawData( const QByteArray &rawData );

    public slots:
        /**
         * Returns the numbers of images contained in the image
         * 0 if there is just one image, > 0 if the image format supports animation (the number of frames),
         * -1 if there was an error
         * @since 4600
         */
        int imageCount() const;

        /**
         * Returns an image, if it did not work an null image is returned
         * For animations returns the next frame upon each call, if there are no frames left returns a null image
         * @see imageCount()
         * @since 4600
         */
        QImage read();

    private:
        void resetImageReader();

    private:
        QImage mImage;
        mutable QByteArray mRawData;
        QBuffer mBuffer;
        QImageReader mImageReader;
};

class DateWrapper : public QObject
{
        Q_OBJECT
        Q_PROPERTY( QDate date READ date WRITE setDate )
    public:
        explicit DateWrapper( QObject *parent = 0, const QDate &date = QDate() );

        QDate date() const;
        void setDate( const QDate &date );
        static QDate fromVariant( const QVariant &variant );

    public slots:
        QObject* addDays( int ndays );
        QObject* addMonths( int nmonths );
        QObject* addYears( int nyears );
        int day() const;
        int dayOfWeek() const;
        int dayOfYear() const;
        int daysInMonth() const;
        int daysInYear() const;
        int daysTo( const QVariant d ) const;
        bool isNull() const;
        bool isValid() const;
        int month() const;
        bool setDate( int year, int month, int day );
        int toJulianDay() const;
        QString toString( const QString &format ) const;
        QString toString( int format = 0 ) const;
        int weekNumber() const;
        int year() const;

    private:
        QDate mDate;
};

class StaticDateWrapper : public QObject
{
        Q_OBJECT
        Q_ENUMS( DateType )
    public:
        enum DateType {
            TextDate = Qt::TextDate,
            ISODate = Qt::ISODate,
            SystemLocaleShortDate = Qt::SystemLocaleShortDate,
            SystemLocaleLongDate = Qt::SystemLocaleLongDate,
            DefaultLocaleShortDate = Qt::DefaultLocaleShortDate,
            DefaultLocaleLongDate = Qt::DefaultLocaleLongDate
        };

        StaticDateWrapper( QObject *parent = 0 );

    public slots:
        QObject* currentDate();
        QObject* fromJulianDay( int jd );
        QObject* fromString( const QString & string, int format = Qt::TextDate );
        QObject* fromString( const QString & string, const QString & format );
        bool isLeapYear ( int year );
        bool isValid ( int year, int month, int day );
        QString longDayName ( int weekday );
        QString longMonthName ( int month );
        QString shortDayName ( int weekday );
        QString shortMonthName ( int month );
};

class ComicProviderWrapper : public QObject
{
        Q_OBJECT
        Q_ENUMS( IdentifierType )
        Q_ENUMS( RequestType )
        Q_ENUMS( PositionType )
        Q_ENUMS( RedirectedUrlType )
        Q_PROPERTY( bool identifierSpecified READ identifierSpecified )
        Q_PROPERTY( QString textCodec READ textCodec WRITE setTextCodec )
        Q_PROPERTY( QString comicAuthor READ comicAuthor WRITE setComicAuthor )
        Q_PROPERTY( QString websiteUrl READ websiteUrl WRITE setWebsiteUrl )
        Q_PROPERTY( QString shopUrl READ shopUrl WRITE setShopUrl )
        Q_PROPERTY( QString title READ title WRITE setTitle )
        Q_PROPERTY( QString additionalText READ additionalText WRITE setAdditionalText )
        Q_PROPERTY( QVariant identifier READ identifier WRITE setIdentifier )
        Q_PROPERTY( QVariant nextIdentifier READ nextIdentifier WRITE setNextIdentifier )
        Q_PROPERTY( QVariant previousIdentifier READ previousIdentifier WRITE setPreviousIdentifier )
        Q_PROPERTY( QVariant firstIdentifier READ firstIdentifier WRITE setFirstIdentifier )
        Q_PROPERTY( QVariant lastIdentifier READ lastIdentifier WRITE setLastIdentifier )
        Q_PROPERTY( bool isLeftToRight READ isLeftToRight WRITE setLeftToRight )
        Q_PROPERTY( bool isTopToBottom READ isTopToBottom WRITE setTopToBottom )
        Q_PROPERTY( int apiVersion READ apiVersion )
    public:
        enum PositionType {
            Left = 0,
            Top,
            Right,
            Bottom
        };
        enum RequestType {
            Page = ComicProvider::Page,
            Image = ComicProvider::Image,
            User = ComicProvider::User
        };
        enum IdentifierType {
            DateIdentifier   = ComicProvider::DateIdentifier,
            NumberIdentifier = ComicProvider::NumberIdentifier,
            StringIdentifier = ComicProvider::StringIdentifier
        };

        enum RedirectedUrlType {
            PreviousUrl = 0,
            CurrentUrl = 1,
            NextUrl = 2,
            FirstUrl = 3,
            LastUrl = 4,
            UserUrl = 10
        };

        ComicProviderWrapper( ComicProviderKross *parent );
        ~ComicProviderWrapper();

        int apiVersion() const { return 4600; }

        ComicProvider::IdentifierType identifierType() const;
        QImage comicImage();
        void pageRetrieved( int id, const QByteArray &data );
        void pageError( int id, const QString &message );
        void redirected( int id, const KUrl &newUrl );

        bool identifierSpecified() const;
        QString textCodec() const;
        void setTextCodec( const QString &textCodec );
        QString comicAuthor() const;
        void setComicAuthor( const QString &author );
        QString websiteUrl() const;
        void setWebsiteUrl( const QString &websiteUrl );
        QString shopUrl() const;
        void setShopUrl( const QString &shopUrl );
        QString title() const;
        void setTitle( const QString &title );
        QString additionalText() const;
        void setAdditionalText( const QString &additionalText );
        QVariant identifier();
        void setIdentifier( const QVariant &identifier );
        QVariant nextIdentifier();
        void setNextIdentifier( const QVariant &nextIdentifier );
        QVariant previousIdentifier();
        void setPreviousIdentifier( const QVariant &previousIdentifier );
        QVariant firstIdentifier();
        void setFirstIdentifier( const QVariant &firstIdentifier );
        QVariant lastIdentifier();
        void setLastIdentifier( const QVariant &lastIdentifier );
        bool isLeftToRight() const;
        void setLeftToRight( bool ltr );
        bool isTopToBottom() const;
        void setTopToBottom( bool ttb );

        QVariant identifierVariant() const;
        QVariant firstIdentifierVariant() const;
        QVariant lastIdentifierVariant() const;
        QVariant nextIdentifierVariant() const;
        QVariant previousIdentifierVariant() const;

    public slots:
        void finished() const;
        void error() const;

        void requestPage( const QString &url, int id, const QVariantMap &infos = QVariantMap() );
        void requestRedirectedUrl( const QString &url, int id, const QVariantMap &infos = QVariantMap() );
        void combine( const QVariant &image, PositionType position = Top );
        QObject* image();

        void init();

    protected:
        QVariant callFunction( const QString &name, const QVariantList &args = QVariantList() );
        const QStringList& extensions() const;
        bool functionCalled() const;
        QVariant identifierToScript( const QVariant &identifier );
        QVariant identifierFromScript( const QVariant &identifier ) const;
        void setIdentifierToDefault();
        void checkIdentifier( QVariant *identifier );

    private:
        Kross::Action *mAction;
        ComicProviderKross *mProvider;
        QStringList mFunctions;
        bool mFuncFound;
        ImageWrapper *mKrossImage;
        static QStringList mExtensions;
        Plasma::Package *mPackage;

        QByteArray mTextCodec;
        QString mWebsiteUrl;
        QString mShopUrl;
        QString mTitle;
        QString mAdditionalText;
        QVariant mIdentifier;
        QVariant mNextIdentifier;
        QVariant mPreviousIdentifier;
        QVariant mFirstIdentifier;
        QVariant mLastIdentifier;
        int mRequests;
        bool mIdentifierSpecified;
        bool mIsLeftToRight;
        bool mIsTopToBottom;
};

#endif
