/* ============================================================
 *
 * This file is a part of digiKam project
 * http://www.digikam.org
 *
 * Date        : 2005-04-21
 * Description : a kio-slave to process date query on 
 *               digiKam albums. 
 *
 * Copyright (C) 2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
 * Copyright (C) 2006-2008 by Gilles Caulier <caulier dot gilles at gmail dot 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, 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.
 *
 * ============================================================ */

// C ansi includes.

extern "C"
{
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
}

// C++ includes.

#include <cstdlib>
#include <cstdio>
#include <ctime>

// TQt includes.

#include <tqfile.h>
#include <tqdatastream.h>
#include <tqregexp.h>
#include <tqbuffer.h>

// KDE includes.

#include <kio/global.h>
#include <kglobal.h>
#include <klocale.h>
#include <kinstance.h>
#include <kfilemetainfo.h>
#include <kdebug.h>

// Local includes.

#include "digikam_export.h"
#include "digikamdates.h"

kio_digikamdates::kio_digikamdates(const TQCString &pool_socket,
                                   const TQCString &app_socket)
                : SlaveBase("kio_digikamdates", pool_socket, app_socket)
{
}

kio_digikamdates::~kio_digikamdates()
{
}

static TQValueList<TQRegExp> makeFilterList( const TQString &filter )
{
    TQValueList<TQRegExp> regExps;
    if ( filter.isEmpty() )
        return regExps;

    TQChar sep( ';' );
    int i = filter.find( sep, 0 );
    if ( i == -1 && filter.find( ' ', 0 ) != -1 )
        sep = TQChar( ' ' );

    TQStringList list = TQStringList::split( sep, filter );
    TQStringList::Iterator it = list.begin();
    while ( it != list.end() ) {
        regExps << TQRegExp( (*it).stripWhiteSpace(), false, true );
        ++it;
    }
    return regExps;
}

static bool matchFilterList( const TQValueList<TQRegExp>& filters,
                             const TQString &fileName )
{
    TQValueList<TQRegExp>::ConstIterator rit = filters.begin();
    while ( rit != filters.end() ) {
        if ( (*rit).exactMatch(fileName) )
            return true;
        ++rit;
    }
    return false;
}

void kio_digikamdates::special(const TQByteArray& data)
{
    bool folders = (metaData("folders") == "yes");

    TQString libraryPath;
    KURL    kurl;
    TQString url;
    TQString filter;
    int     getDimensions;
    int     recurseAlbums;
    int     recurseTags;

    TQDataStream ds(data, IO_ReadOnly);
    ds >> libraryPath;
    ds >> kurl;
    ds >> filter;
    ds >> getDimensions;
    ds >> recurseAlbums;
    ds >> recurseTags;

    url = kurl.path();

    TQValueList<TQRegExp> regex = makeFilterList(filter);

    if (m_libraryPath != libraryPath)
    {
        m_libraryPath = libraryPath;
        m_db.closeDB();
        m_db.openDB(libraryPath);
    }

    TQByteArray  ba;

    if (folders)       // Special mode to stats all dates from collection
    {
        TQMap<TQDateTime, int> datesStatMap;
        TQStringList          values;
        TQString              name, dateStr;
        TQDateTime            dateTime;

        m_db.execSql( "SELECT name, datetime FROM Images;", &values );

        for ( TQStringList::iterator it = values.begin(); it != values.end(); )
        {
            name    = *it;
            ++it;
            dateStr = *it;
            ++it;

            if ( !matchFilterList( regex, name ) )
                continue;

            dateTime = TQDateTime::fromString( dateStr, Qt::ISODate );
            if ( !dateTime.isValid() )
                continue;

            TQMap<TQDateTime, int>::iterator it2 = datesStatMap.find(dateTime);
            if ( it2 == datesStatMap.end() )
            {
                datesStatMap.insert( dateTime, 1 );
            }
            else
            {
                datesStatMap.replace( dateTime, it2.data() + 1 );
            }
        }

        TQDataStream os(ba, IO_WriteOnly);
        os << datesStatMap;
    }
    else
    {
        TQStringList subpaths = TQStringList::split("/", url, false);
        if (subpaths.count() == 4)
        {
            int yrStart = TQString(subpaths[0]).toInt();
            int moStart = TQString(subpaths[1]).toInt();
            int yrEnd   = TQString(subpaths[2]).toInt();
            int moEnd   = TQString(subpaths[3]).toInt();

            TQString moStartStr, moEndStr;
            moStartStr.sprintf("%.2d", moStart);
            moEndStr.sprintf("%.2d", moEnd);

            TQStringList values;

            m_db.execSql(TQString("SELECT Images.id, Images.name, Images.dirid, \n "
                                 "  Images.datetime, Albums.url \n "
                                 "FROM Images, Albums \n "
                                 "WHERE Images.datetime < '%1-%2-01' \n "
                                 "AND Images.datetime >= '%3-%4-01' \n "
                                 "AND Albums.id=Images.dirid \n "
                                 "ORDER BY Albums.id;")
                         .arg(yrEnd, 4)
                         .arg(moEndStr, 2)
                         .arg(yrStart, 4)
                         .arg(moStartStr, 2),
                         &values, false);

            TQ_LLONG     imageid;
            TQString     name;
            TQString     path;
            int         dirid;
            TQString     date;
            TQString     purl;
            TQSize       dims;
            struct stat stbuf;

            int  count = 0;
            TQDataStream* os = new TQDataStream(ba, IO_WriteOnly);

            for (TQStringList::iterator it = values.begin(); it != values.end();)
            {
                imageid = (*it).toLongLong();
                ++it;
                name  = *it;
                ++it;
                dirid = (*it).toInt();
                ++it;
                date  = *it;
                ++it;
                purl  = *it;
                ++it;

                if (!matchFilterList(regex, name))
                    continue;

                path = m_libraryPath + purl + '/' + name;
                if (::stat(TQFile::encodeName(path), &stbuf) != 0)
                    continue;

                dims = TQSize();
                if (getDimensions)
                {
                    KFileMetaInfo metaInfo(path);
                    if (metaInfo.isValid())
                    {
                        if (metaInfo.containsGroup("Jpeg EXIF Data"))
                        {
                            dims = metaInfo.group("Jpeg EXIF Data").
                                   item("Dimensions").value().toSize();
                        }
                        else if (metaInfo.containsGroup("General"))
                        {
                            dims = metaInfo.group("General").
                                   item("Dimensions").value().toSize();
                        }
                        else if (metaInfo.containsGroup("Technical"))
                        {
                            dims = metaInfo.group("Technical").
                                   item("Dimensions").value().toSize();
                        }
                    }
                }

                *os << imageid;
                *os << dirid;
                *os << name;
                *os << date;
                *os << static_cast<size_t>(stbuf.st_size);
                *os << dims;

                count++;

                if (count > 200)
                {
                    delete os;
                    os = 0;

                    SlaveBase::data(ba);
                    ba.resize(0);

                    count = 0;
                    os = new TQDataStream(ba, IO_WriteOnly);
                }
            }

            delete os;
        }
    }

    SlaveBase::data(ba);

    finished();
}

/* KIO slave registration */

extern "C"  
{
    DIGIKAM_EXPORT int kdemain(int argc, char **argv)
    {
        KLocale::setMainCatalogue("digikam");
        KInstance instance( "kio_digikamdates" );
        KGlobal::locale();

        if (argc != 4) {
            kdDebug() << "Usage: kio_digikamdates  protocol domain-socket1 domain-socket2"
                      << endl;
            exit(-1);
        }

        kio_digikamdates slave(argv[2], argv[3]);
        slave.dispatchLoop();

        return 0;
    }
}

