//! \file
//! \brief Common types used by Gallery

#ifndef IMAGETYPES_H
#define IMAGETYPES_H

#include <QStringList>
#include <QSharedPointer>
#include <QPair>
#include <QList>
#include <QHash>
#include <QMap>
#include <QMetaType>

#include "mythmetaexp.h"

// Define this to log/count creation/deletion of ImageItem heap objects.
// These are created liberally when processing images and are liable to leak.
// At idle there should be precisely 1 ImageItem for every image/dir displayed.
//#define MEMORY_DEBUG active
#ifdef MEMORY_DEBUG
#include <QDebug>
#endif

// Id of the (virtual) Gallery root node
#define GALLERY_DB_ID 0
// Id of the Storage Group (Photographs) node
#define PHOTO_DB_ID 1


//! Type of image node
// We need to use other names to avoid getting coflicts with the videolist.h file
enum ImageNodeType {
    kUnknown   = 0, //!< Unprocessable file type
    kDevice    = 1, //!< Storage Group and local mounted media
    kCloneDir  = 2, //!< A device sub dir comprised from multiple SG dirs
    kDirectory = 3, //!< A device sub directory
    kImageFile = 4, //!< A picture
    kVideoFile = 5  //!< A video
};


//! Image ordering
enum ImageSortOrder {
    kSortByNameAsc     = 1, //!< Name A-Z
    kSortByNameDesc    = 2, //!< Name Z-A
    kSortByModTimeAsc  = 3, //!< File modified time Earliest -> Latest
    kSortByModTimeDesc = 4, //!< File modified time Latest -> Earliest
    kSortByExtAsc      = 5, //!< Extension A-Z
    kSortByExtDesc     = 6, //!< Extension Z-A
    kSortBySizeAsc     = 7, //!< File size Smallest -> Largest
    kSortBySizeDesc    = 8, //!< File size Largest -> Smallest
    kSortByDateAsc     = 9, //!< Exif date Earliest -> Latest
    kSortByDateDesc    = 10 //!< Exif date Latest -> Earliest
};


// Convenience types
typedef QList<int>                ImageIdList;
typedef QPair<QString, QString>   StringPair;
typedef QHash<QString, QString>   NameHash;
typedef QMap<int, QString>        StringMap;
typedef QPair<int, QString>       ThumbPair;


//! Represents a picture, video or directory
class META_PUBLIC ImageItem
{
public:
    explicit ImageItem(int id = 0)
        : m_id(id),
          m_baseName(""),    m_filePath(""),     m_extension(""),
          m_device(0),       m_parentId(0),
          m_type(0),
          m_modTime(0),      m_size(0),
          m_date(0),         m_orientation(0),   m_comment(""),
          m_isHidden(false), m_userThumbnail(0),
          m_url(""),         m_thumbPath(""),
          m_dirCount(0),     m_fileCount(0)
#ifndef MEMORY_DEBUG
    {}
#else
    { qDebug() << QString("Created %1 (%2)").arg(m_id).arg(++GetItemCount()); }

    ~ImageItem()
    { qDebug() << QString("Deleted %1 (%2)").arg(m_id).arg(--GetItemCount()); }

    // Embeds a static var in header to avoid the need for a cpp
    static int& GetItemCount() { static int count; return count; }
#endif


    //! Uniquely identifies an image (file/dir). Assigned by Db auto-incremnent
    //! Remote (Storage Group) images are positive - as in Db.
    //! Local images are negative - the negated Db id
    int              m_id;

    // Db File attributes
    QString          m_baseName;    //!< File/Dir name with extension (no path)
    QString          m_filePath;    //!< Absolute for local images. Usually SG-relative for remotes
    QString          m_extension;   //!< Image file extension
    int              m_device;      //!< Id of media device. Always 0 (SG) for remotes, 1+ for local devices
    int              m_parentId;    //!< Id of parent dir
    int              m_type;        //!< Type of node: dir, video etc
    uint             m_modTime;     //!< Filesystem modified datestamp
    int              m_size;        //!< Filesize (files only)
    uint             m_date;        //!< Image creation date, from Exif metadata
    int              m_orientation; //!< Image orientation
    QString          m_comment;     //!< User comment, from Exif metadata

    // Db User attributes
    bool             m_isHidden;      //!< If true, image won't be shown
    int              m_userThumbnail; //!< Id of thumbnail to use as cover (dirs only)

    // Derived attributes
    QString          m_url;        //! Myth URL of image (abs filepath for locals)
    QString          m_thumbPath;  //!< Absolute path of thumbnail
    QList<ThumbPair> m_thumbNails; //! Id & URLs of thumbnail(s). 1 for a file, 4 for dirs
    int              m_dirCount;   //!< Number of child sub-dirs (dirs only)
    int              m_fileCount;  //!< Number of child images (dirs only)

    // Convenience functions
    bool IsDevice()     const { return m_type == kDevice; }
    bool IsDirectory()  const { return m_type <= kDirectory; }
    bool IsFile()       const { return m_type >  kDirectory; }
    bool IsLocal()      const { return IsLocalId(m_id); }

    //! Determine image type (local/remote) from its id. Root/Gallery is remote
    static bool    IsLocalId(int id)     { return id < GALLERY_DB_ID; }
    //! Parents of locals are locals or root
    static bool    IsLocalParent(int id) { return id <= GALLERY_DB_ID; }

    //! Converts a DB id (positive) to an id of a local image (negative)
    static int     ToLocalId(int id)     { return -id; }
    static QString ToLocalId(const QString &id) { return "-" + id; }

    //! Converts local image ids (negative) to Db ids (positive)
    static int     ToDbId(int id)        { return abs(id); }
    static QString ToDbId(QString ids)   { return ids.remove("-"); }


    /*!
     \brief Separates list of ids into a list of local ids and a list of remote ids
     \param ids List of local/remote image ids
     \return StringPair Pair <CSV of local ids, CSV of remote ids>
    */
    static StringPair PartitionIds(const ImageIdList &ids)
    {
        QStringList local, remote;
        foreach(int id, ids)
        {
            if (ImageItem::IsLocalId(id))
                local << QString::number(id);
            else
                remote << QString::number(id);
        }
        return qMakePair(local.join(","), remote.join(","));
    }

private:
    Q_DISABLE_COPY(ImageItem)
};

// Convenience containers
typedef QSharedPointer<ImageItem>  ImagePtr;
typedef QList<ImagePtr>            ImageList;
typedef QHash<QString, ImagePtr>   ImageHash;

// Read-only images alias
typedef const ImageItem            ImageItemK;
typedef QSharedPointer<ImageItemK> ImagePtrK;
typedef QList<ImagePtrK>           ImageListK;

Q_DECLARE_METATYPE(ImagePtrK)

#endif // IMAGETYPES_H