/* ============================================================
 *
 * This file is a part of digiKam project
 * http://www.digikam.org
 *
 * Date        : 2004-06-15
 * Description : digiKam album types
 *
 * Copyright (C) 2004-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.
 *
 * ============================================================ */

// KDE includes.

#include <klocale.h>

// Local includes.

#include "ddebug.h"
#include "albummanager.h"
#include "albumdb.h"
#include "album.h"

namespace Digikam
{

Album::Album(Album::Type type, int id, bool root)
{
    m_parent     = 0;
    m_next       = 0;
    m_prev       = 0;
    m_firstChild = 0;
    m_lastChild  = 0;
    m_clearing   = false;
    m_type       = type;
    m_id         = id;
    m_root       = root;
}

Album::~Album()
{
    if (m_parent)
        m_parent->removeChild(this);
    clear();
}

void Album::setParent(Album* parent)
{
    if (parent)
    {
        m_parent = parent;
        parent->insertChild(this);
    }
}

Album* Album::parent() const
{
    return m_parent;
}

Album* Album::firstChild() const
{
    return m_firstChild;
}

Album* Album::lastChild() const
{
    return m_lastChild;
}

Album* Album::next() const
{
    return m_next;
}

Album* Album::prev() const
{
    return m_prev;
}

void Album::insertChild(Album* child)
{
    if (!child)
        return;

    if (!m_firstChild)
    {
        m_firstChild  = child;
        m_lastChild   = child;
        child->m_next = 0;
        child->m_prev = 0;
    }
    else
    {
        m_lastChild->m_next = child;
        child->m_prev       = m_lastChild;
        child->m_next       = 0;
        m_lastChild         = child;
    }
}

void Album::removeChild(Album* child)
{
    if (!child || m_clearing)
        return;

    if (child == m_firstChild)
    {
        m_firstChild = m_firstChild->m_next;
        if (m_firstChild)
            m_firstChild->m_prev = 0;
        else
            m_firstChild = m_lastChild = 0;
    }
    else if (child == m_lastChild)
    {
        m_lastChild = m_lastChild->m_prev;
        if (m_lastChild)
            m_lastChild->m_next = 0;
        else
            m_firstChild = m_lastChild = 0;
    }
    else
    {
        Album* c = child;
        if (c->m_prev)
            c->m_prev->m_next = c->m_next;
        if (c->m_next)
            c->m_next->m_prev = c->m_prev;
    }
}

void Album::clear()
{
    m_clearing = true;

    Album* child = m_firstChild;
    Album* nextChild;
    while (child)
    {
        nextChild = child->m_next;
        delete child;
        child = nextChild;
    }

    m_firstChild = 0;
    m_lastChild  = 0;
    m_clearing   = false;
}

int Album::globalID() const
{
    switch (m_type)
    {
        case (PHYSICAL):
            return 10000 + m_id;
        case(TAG):
            return 20000 + m_id;
        case(DATE):
            return 30000 + m_id;
        case(SEARCH):
            return 40000 + m_id;
        default:
            DError() << "Unknown album type" << endl;
            return -1;
    }
}

int Album::id() const
{
    return m_id;
}

void Album::setTitle(const TQString& title)
{
    m_title = title;
}

TQString Album::title() const
{
    return m_title;
}

Album::Type Album::type() const
{
    return m_type;
}

void Album::setExtraData(const void* key, void* value)
{
    m_extraMap.replace(key, value);
}

void Album::removeExtraData(const void* key)
{
    m_extraMap.remove(key);
}

void* Album::extraData(const void* key) const
{
    typedef TQMap<const void*, void*> Map;
    Map::const_iterator it = m_extraMap.find(key);
    if (it == m_extraMap.end())
        return 0;

    return it.data();
}

bool Album::isRoot() const
{
    return m_root;
}

bool Album::isAncestorOf(Album* album) const
{
    bool val = false;
    Album* a = album;
    while (a && !a->isRoot())
    {
        if (a == this)
        {
            val = true;
            break;
        }
        a = a->parent();
    }
    return val;
}

// ------------------------------------------------------------------------------

PAlbum::PAlbum(const TQString& title, int id,  bool root)
      : Album(Album::PHYSICAL, id, root)
{
    setTitle(title);
    m_caption    = "";
    m_collection = "";
    m_date       = TQDate::currentDate();
}

PAlbum::~PAlbum()
{
}

void PAlbum::setCaption(const TQString& caption)
{
    m_caption = caption;

    AlbumDB* db = AlbumManager::instance()->albumDB();
    db->setAlbumCaption(id(), m_caption);
}

void PAlbum::setCollection(const TQString& collection)
{
    m_collection = collection;
    AlbumDB* db = AlbumManager::instance()->albumDB();
    db->setAlbumCollection(id(), m_collection);
}

void PAlbum::setDate(const TQDate& date)
{
    m_date = date;

    AlbumDB* db = AlbumManager::instance()->albumDB();
    db->setAlbumDate(id(), m_date);
}

TQString PAlbum::caption() const
{
    return m_caption;
}

TQString PAlbum::collection() const
{
    return m_collection;
}

TQDate PAlbum::date() const
{
    return m_date;
}

TQString PAlbum::url() const
{
    TQString u("");
    if (isRoot())
    {
        return "/";
    }
    else if (parent())
    {
        u = ((PAlbum*)parent())->url();
        if (!u.endsWith("/"))
            u += '/';
    }
    u += title();
    return u;
}

KURL PAlbum::kurl() const
{
    KURL u;
    u.setProtocol("digikamalbums");
    u.setUser(AlbumManager::instance()->getLibraryPath());
    // add an empty host. KURLDrag will eat away the user
    // attribute if a host is not present. probably a URL
    // specification
    u.setHost(" ");
    u.setPath(url());
    return u;
}

TQString PAlbum::prettyURL() const
{
    TQString u = i18n("My Albums") + url();
    return u;
}

TQString PAlbum::icon() const
{
    return m_icon;
}

KURL PAlbum::iconKURL() const
{
    KURL u;
    u.setPath( m_icon );
    return u;
}

TQString PAlbum::folderPath() const
{
    KURL u(AlbumManager::instance()->getLibraryPath());
    u.addPath(url());
    return u.path();
}

// --------------------------------------------------------------------------

TAlbum::TAlbum(const TQString& title, int id, bool root)
      : Album(Album::TAG, id, root)
{
    setTitle(title);
}

TAlbum::~TAlbum()
{
}

TQString TAlbum::tagPath(bool leadingSlash) const
{
    if (isRoot())
        return leadingSlash ? "/" : "";

    TQString u;

    if (parent())
    {
        u = ((TAlbum*)parent())->tagPath(leadingSlash);
        if (!parent()->isRoot())
            u += '/';
    }

    u += title();

    return u;
}

TQString TAlbum::prettyURL() const
{
    TQString u = i18n("My Tags") + tagPath(true);
    return u;
}

KURL TAlbum::kurl() const
{
    KURL url;
    url.setProtocol("digikamtags");

    if (isRoot())
    {
        url.setPath("/");
    }
    else if (parent())
    {
        TAlbum *p = static_cast<TAlbum*>(parent());
        url.setPath(p->kurl().path(1));
        url.addPath(TQString::number(id()));
    }
    else
    {
        url = KURL();
    }
    return url;
}


TQString TAlbum::icon() const
{
    return m_icon;
}

// --------------------------------------------------------------------------

int DAlbum::m_uniqueID = 0;

DAlbum::DAlbum(const TQDate& date, bool root, Range range)
      : Album(Album::DATE, root ? 0 : ++m_uniqueID, root)
{
    m_date  = date;
    m_range = range;

    // Set the name of the date album
    TQString dateTitle;

    if (m_range == Month)
        dateTitle = m_date.toString("MMMM yyyy");
    else 
        dateTitle = m_date.toString("yyyy");

    setTitle(dateTitle);
}

DAlbum::~DAlbum()
{
}

TQDate DAlbum::date() const
{
    return m_date;
}

DAlbum::Range DAlbum::range() const
{
    return m_range;
}

KURL DAlbum::kurl() const
{
    TQDate endDate;
    if (m_range == Month)
        endDate = m_date.addMonths(1);
    else 
        endDate = m_date.addYears(1);

    KURL u;
    u.setProtocol("digikamdates");
    u.setPath(TQString("/%1/%2/%3/%4")
              .arg(m_date.year())
              .arg(m_date.month())
              .arg(endDate.year())
              .arg(endDate.month()));

    return u;
}

// --------------------------------------------------------------------------

SAlbum::SAlbum(int id, const KURL& url, bool simple, bool root)
      : Album(Album::SEARCH, id, root),
              m_kurl(url), m_simple(simple)
{
    setTitle(url.queryItem("name"));
}

SAlbum::~SAlbum()
{
}

KURL SAlbum::kurl() const
{
    return m_kurl;
}

bool SAlbum::isSimple() const
{
    return m_simple;
}

// --------------------------------------------------------------------------

AlbumIterator::AlbumIterator(Album *album)
{
    m_root    = album;
    m_current = album ? album->firstChild() : 0;
}

AlbumIterator::~AlbumIterator()
{
}

AlbumIterator& AlbumIterator::operator++()
{
    if (!m_current)
        return *this;

    Album *album = m_current->firstChild();
    if ( !album )
    {
        while ( (album = m_current->next()) == 0  )
        {
            m_current = m_current->parent();

            if ( m_current == m_root )
            {
                // we have reached the root.
                // that means no more children
                m_current = 0;
                break;
            }

            if ( m_current == 0 )
                break;
        }
    }

    m_current = album;
    return *this;
}

Album* AlbumIterator::operator*()
{
    return m_current;
}

Album* AlbumIterator::current() const
{
    return m_current;
}

}  // namespace Digikam
