/* ============================================================
 *
 * This file is a part of digiKam project
 * http://www.digikam.org
 *
 * Date        : 2004-08-19
 * Description : Album item file tip adapted from tdefiletip 
 *               (konqueror - konq_iconviewwidget.cc)
 *
 * Copyright (C) 1998-1999 by Torben Weis <weis@kde.org>
 * Copyright (C) 2000-2002 by David Faure <david@mandrakesoft.com>
 * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
 * Copyright (C) 2006-2007 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.
 *
 * ============================================================ */

// TQt includes.

#include <tqtooltip.h>
#include <tqfileinfo.h>
#include <tqlabel.h>
#include <tqlayout.h>
#include <tqpixmap.h>
#include <tqdatetime.h>
#include <tqstylesheet.h>
#include <tqpainter.h>
#include <tqapplication.h>

// KDE includes.

#include <tdelocale.h>
#include <tdefileitem.h>
#include <kmimetype.h>
#include <tdeglobalsettings.h>
#include <tdeglobal.h>
#include <tdeversion.h>

// LibKDcraw includes.

#include <libkdcraw/version.h>
#include <libkdcraw/kdcraw.h>

#if KDCRAW_VERSION < 0x000106
#include <libkdcraw/dcrawbinary.h>
#endif

// Local includes.

#include "ddebug.h"
#include "dmetadata.h"
#include "albumiconview.h"
#include "albumiconitem.h"
#include "albumsettings.h"
#include "album.h"
#include "albumfiletip.h"

namespace Digikam
{

class AlbumFileTipPriv
{
public:

    AlbumFileTipPriv() : 
        maxStringLen(30), tipBorder(5)
    {
        corner   = 0;
        label    = 0;
        view     = 0;
        iconItem = 0;
    }

    const uint     maxStringLen;
    const uint     tipBorder;

    int            corner;

    TQLabel        *label;

    TQPixmap        corners[4];

    AlbumIconView *view;

    AlbumIconItem *iconItem;
};

AlbumFileTip::AlbumFileTip(AlbumIconView* view)
            : TQFrame(0, 0, WStyle_Customize | WStyle_NoBorder | WStyle_Tool |
                     WStyle_StaysOnTop | WX11BypassWM)
{
    d = new AlbumFileTipPriv;
    d->view = view;
    hide();

    setPalette(TQToolTip::palette());
    setFrameStyle(TQFrame::Plain | TQFrame::Box);
    setLineWidth(1);

    TQVBoxLayout *layout = new TQVBoxLayout(this, d->tipBorder+1, 0);

    d->label = new TQLabel(this);
    d->label->setMargin(0);
    d->label->setAlignment(TQt::AlignHCenter | TQt::AlignVCenter);

    layout->addWidget(d->label);
    layout->setResizeMode(TQLayout::Fixed);

    renderArrows();
}

AlbumFileTip::~AlbumFileTip()
{
    delete d;
}

void AlbumFileTip::setIconItem(AlbumIconItem* iconItem)
{
    d->iconItem = iconItem;

    if (!d->iconItem || 
        !AlbumSettings::instance()->showToolTipsIsValid())
    {
        hide();
    }
    else
    {
        updateText();
        reposition();
        if (isHidden())
            show();
    }
}

void AlbumFileTip::reposition()
{
    if (!d->iconItem)
        return;

    TQRect rect = d->iconItem->clickToOpenRect();
    rect.moveTopLeft(d->view->contentsToViewport(rect.topLeft()));
    rect.moveTopLeft(d->view->viewport()->mapToGlobal(rect.topLeft()));

    TQPoint pos = rect.center();
    // d->corner:
    // 0: upperleft
    // 1: upperright
    // 2: lowerleft
    // 3: lowerright

    d->corner = 0;
    // should the tooltip be shown to the left or to the right of the ivi ?

    TQRect desk = TDEGlobalSettings::desktopGeometry(rect.center());
    if (rect.center().x() + width() > desk.right())
    {
        // to the left
        if (pos.x() - width() < 0) 
        {
            pos.setX(0);
            d->corner = 4;
        } 
        else 
        {
            pos.setX( pos.x() - width() );
            d->corner = 1;
        }
    }

    // should the tooltip be shown above or below the ivi ?
    if (rect.bottom() + height() > desk.bottom())
    {
        // above
        pos.setY( rect.top() - height() - 5);
        d->corner += 2;
    }
    else
    {
        pos.setY( rect.bottom() + 5 );
    }

    move( pos );
}

void AlbumFileTip::renderArrows()
{
    int w = d->tipBorder;

    // -- left top arrow -------------------------------------

    TQPixmap& pix0 = d->corners[0];
    pix0.resize(w, w);
    pix0.fill(colorGroup().background());

    TQPainter p0(&pix0);
    p0.setPen(TQPen(TQt::black, 1));

    for (int j=0; j<w; j++)
        p0.drawLine(0, j, w-j-1, j);

    p0.end();

    // -- right top arrow ------------------------------------

    TQPixmap& pix1 = d->corners[1];
    pix1.resize(w, w);
    pix1.fill(colorGroup().background());

    TQPainter p1(&pix1);
    p1.setPen(TQPen(TQt::black, 1));

    for (int j=0; j<w; j++)
        p1.drawLine(j, j, w-1, j);

    p1.end();

    // -- left bottom arrow ----------------------------------

    TQPixmap& pix2 = d->corners[2];
    pix2.resize(w, w);
    pix2.fill(colorGroup().background());

    TQPainter p2(&pix2);
    p2.setPen(TQPen(TQt::black, 1));

    for (int j=0; j<w; j++)
        p2.drawLine(0, j, j, j);

    p2.end();

    // -- right bottom arrow ---------------------------------

    TQPixmap& pix3 = d->corners[3];
    pix3.resize(w, w);
    pix3.fill(colorGroup().background());

    TQPainter p3(&pix3);
    p3.setPen(TQPen(TQt::black, 1));

    for (int j=0; j<w; j++)
        p3.drawLine(w-j-1, j, w-1, j);

    p3.end();
}

bool AlbumFileTip::event(TQEvent *e)
{
    switch ( e->type() )
    {
        case TQEvent::Leave:
        case TQEvent::MouseButtonPress:
        case TQEvent::MouseButtonRelease:
        case TQEvent::FocusIn:
        case TQEvent::FocusOut:
        case TQEvent::Wheel:
            hide();
        default:
            break;
    }

    return TQFrame::event(e);
}

void AlbumFileTip::resizeEvent(TQResizeEvent* e)
{
    TQFrame::resizeEvent(e);
    reposition();
}

void AlbumFileTip::drawContents(TQPainter *p)
{
    if (d->corner >= 4)
    {
        TQFrame::drawContents( p );
        return;
    }

    TQPixmap &pix = d->corners[d->corner];

    switch ( d->corner )
    {
        case 0:
            p->drawPixmap( 3, 3, pix );
            break;
        case 1:
            p->drawPixmap( width() - pix.width() - 3, 3, pix );
            break;
        case 2:
            p->drawPixmap( 3, height() - pix.height() - 3, pix );
            break;
        case 3:
            p->drawPixmap( width() - pix.width() - 3, height() - pix.height() - 3, pix );
            break;
    }

    TQFrame::drawContents(p);
}

void AlbumFileTip::updateText()
{
    TQString tip, str;
    TQString unavailable(i18n("unavailable"));

    TQString headBeg("<tr bgcolor=\"orange\"><td colspan=\"2\">"
                    "<nobr><font size=\"-1\" color=\"black\"><b>");
    TQString headEnd("</b></font></nobr></td></tr>");

    TQString cellBeg("<tr><td><nobr><font size=\"-1\" color=\"black\">");
    TQString cellMid("</font></nobr></td>"
                    "<td><nobr><font size=\"-1\" color=\"black\">");
    TQString cellEnd("</font></nobr></td></tr>");

    TQString cellSpecBeg("<tr><td><nobr><font size=\"-1\" color=\"black\">");
    TQString cellSpecMid("</font></nobr></td>"
                        "<td><nobr><font size=\"-1\" color=\"steelblue\"><i>");
    TQString cellSpecEnd("</i></font></nobr></td></tr>");

    tip = "<table cellspacing=\"0\" cellpadding=\"0\" width=\"250\" border=\"0\">";

    AlbumSettings* settings = AlbumSettings::instance();
    const ImageInfo* info   = d->iconItem->imageInfo();
    TQFileInfo fileInfo(info->kurl().path());
    KFileItem fi(KFileItem::Unknown, KFileItem::Unknown, info->kurl());
    DMetadata metaData(info->kurl().path());

    // -- File properties ----------------------------------------------

    if (settings->getToolTipsShowFileName()  ||
        settings->getToolTipsShowFileDate()  ||
        settings->getToolTipsShowFileSize()  ||
        settings->getToolTipsShowImageType() ||
        settings->getToolTipsShowImageDim())
    {
        tip += headBeg + i18n("File Properties") + headEnd;

        if (settings->getToolTipsShowFileName())
        {
            tip += cellBeg + i18n("Name:") + cellMid;
            tip += info->kurl().fileName() + cellEnd;
        }

        if (settings->getToolTipsShowFileDate())
        {
            TQDateTime modifiedDate = fileInfo.lastModified();
            str = TDEGlobal::locale()->formatDateTime(modifiedDate, true, true);
            tip += cellBeg + i18n("Modified:") + cellMid + str + cellEnd;
        }

        if (settings->getToolTipsShowFileSize())
        {
            tip += cellBeg + i18n("Size:") + cellMid;
            str = i18n("%1 (%2)").arg(TDEIO::convertSize(fi.size()))
                                .arg(TDEGlobal::locale()->formatNumber(fi.size(), 0));
            tip += str + cellEnd;
        }

        TQSize   dims;
#if KDCRAW_VERSION < 0x000106
        TQString rawFilesExt(KDcrawIface::DcrawBinary::instance()->rawFiles());
#else
        TQString rawFilesExt(KDcrawIface::KDcraw::rawFiles());
#endif
        TQString ext = fileInfo.extension(false).upper();

        if (!ext.isEmpty() && rawFilesExt.upper().contains(ext))
        {
            str = i18n("RAW Image");
            dims = metaData.getImageDimensions();
        }
        else
        {
            str = fi.mimeComment();

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

        if (settings->getToolTipsShowImageType())
        {
            tip += cellBeg + i18n("Type:") + cellMid + str + cellEnd;
        }

        if (settings->getToolTipsShowImageDim())
        {
            TQString mpixels;
            mpixels.setNum(dims.width()*dims.height()/1000000.0, 'f', 2);
            str = (!dims.isValid()) ? i18n("Unknown") : i18n("%1x%2 (%3Mpx)")
                .arg(dims.width()).arg(dims.height()).arg(mpixels);
            tip += cellBeg + i18n("Dimensions:") + cellMid + str + cellEnd;
        }
    }

    // -- Photograph Info ----------------------------------------------------
    // NOTE: If something is changed here, please updated imageproperties section too.

    if (settings->getToolTipsShowPhotoMake()  ||
        settings->getToolTipsShowPhotoDate()  ||
        settings->getToolTipsShowPhotoFocal() ||
        settings->getToolTipsShowPhotoExpo()  ||
        settings->getToolTipsShowPhotoMode()  ||
        settings->getToolTipsShowPhotoFlash() ||
        settings->getToolTipsShowPhotoWB())
    {
        PhotoInfoContainer photoInfo = metaData.getPhotographInformations();

        if (!photoInfo.isEmpty())
        {
            TQString metaStr;
            tip += headBeg + i18n("Photograph Properties") + headEnd;

            if (settings->getToolTipsShowPhotoMake())
            {
                str = TQString("%1 / %2").arg(photoInfo.make.isEmpty() ? unavailable : photoInfo.make)
                                        .arg(photoInfo.model.isEmpty() ? unavailable : photoInfo.model);
                if (str.length() > d->maxStringLen) str = str.left(d->maxStringLen-3) + "...";
                metaStr += cellBeg + i18n("Make/Model:") + cellMid + TQStyleSheet::escape( str ) + cellEnd;
            }

            if (settings->getToolTipsShowPhotoDate())
            {
                if (photoInfo.dateTime.isValid())
                {
                    str = TDEGlobal::locale()->formatDateTime(photoInfo.dateTime, true, true);
                    if (str.length() > d->maxStringLen) str = str.left(d->maxStringLen-3) + "...";
                    metaStr += cellBeg + i18n("Created:") + cellMid + TQStyleSheet::escape( str ) + cellEnd;
                }
                else
                    metaStr += cellBeg + i18n("Created:") + cellMid + TQStyleSheet::escape( unavailable ) + cellEnd;
            }

            if (settings->getToolTipsShowPhotoFocal())
            {
                str = photoInfo.aperture.isEmpty() ? unavailable : photoInfo.aperture;

                if (photoInfo.focalLength35mm.isEmpty())
                    str += TQString(" / %1").arg(photoInfo.focalLength.isEmpty() ? unavailable : photoInfo.focalLength);
                else 
                    str += TQString(" / %1").arg(i18n("%1 (35mm: %2)").arg(photoInfo.focalLength).arg(photoInfo.focalLength35mm));

                if (str.length() > d->maxStringLen) str = str.left(d->maxStringLen-3) + "...";
                metaStr += cellBeg + i18n("Aperture/Focal:") + cellMid + TQStyleSheet::escape( str ) + cellEnd;
            }

            if (settings->getToolTipsShowPhotoExpo())
            {
                str = TQString("%1 / %2").arg(photoInfo.exposureTime.isEmpty() ? unavailable : photoInfo.exposureTime)
                                        .arg(photoInfo.sensitivity.isEmpty() ? unavailable : i18n("%1 ISO").arg(photoInfo.sensitivity));
                if (str.length() > d->maxStringLen) str = str.left(d->maxStringLen-3) + "...";
                metaStr += cellBeg + i18n("Exposure/Sensitivity:") + cellMid + TQStyleSheet::escape( str ) + cellEnd;
            }

            if (settings->getToolTipsShowPhotoMode())
            {

                if (photoInfo.exposureMode.isEmpty() && photoInfo.exposureProgram.isEmpty())
                    str = unavailable;
                else if (!photoInfo.exposureMode.isEmpty() && photoInfo.exposureProgram.isEmpty())
                    str = photoInfo.exposureMode;
                else if (photoInfo.exposureMode.isEmpty() && !photoInfo.exposureProgram.isEmpty())
                    str = photoInfo.exposureProgram;
                else 
                    str = TQString("%1 / %2").arg(photoInfo.exposureMode).arg(photoInfo.exposureProgram);
                if (str.length() > d->maxStringLen) str = str.left(d->maxStringLen-3) + "...";
                metaStr += cellBeg + i18n("Mode/Program:") + cellMid + TQStyleSheet::escape( str ) + cellEnd;
            }

            if (settings->getToolTipsShowPhotoFlash())
            {
                str = photoInfo.flash.isEmpty() ? unavailable : photoInfo.flash;
                if (str.length() > d->maxStringLen) str = str.left(d->maxStringLen-3) + "...";
                metaStr += cellBeg + i18n("Flash:") + cellMid + TQStyleSheet::escape( str ) + cellEnd;
            }

            if (settings->getToolTipsShowPhotoWB())
            {
                str = photoInfo.whiteBalance.isEmpty() ? unavailable : photoInfo.whiteBalance;
                if (str.length() > d->maxStringLen) str = str.left(d->maxStringLen-3) + "...";
                metaStr += cellBeg + i18n("White Balance:") + cellMid + TQStyleSheet::escape( str ) + cellEnd;
            }

            tip += metaStr;
        }
    }

    // -- digiKam properties  ------------------------------------------
    
    if (settings->getToolTipsShowAlbumName() ||
        settings->getToolTipsShowComments()  ||
        settings->getToolTipsShowTags()      ||
        settings->getToolTipsShowRating())
    {
        tip += headBeg + i18n("digiKam Properties") + headEnd;

        if (settings->getToolTipsShowAlbumName())
        {
            PAlbum* album = info->album();
            if (album)
                tip += cellSpecBeg + i18n("Album:") + cellSpecMid + album->url().remove(0, 1) + cellSpecEnd;
        }

        if (settings->getToolTipsShowComments())
        {
            str = info->caption();
            if (str.isEmpty()) str = TQString("---");
            tip += cellSpecBeg + i18n("Caption:") + cellSpecMid + breakString(str) + cellSpecEnd;
        }

        if (settings->getToolTipsShowTags())
        {
            TQStringList tagPaths = info->tagPaths(false);

            str = tagPaths.join(", ");
            if (str.isEmpty()) str = TQString("---");
            if (str.length() > d->maxStringLen) str = str.left(d->maxStringLen-3) + "...";
            tip += cellSpecBeg + i18n("Tags:") + cellSpecMid + str + cellSpecEnd;
        }

        if (settings->getToolTipsShowRating())
        {
            str.fill( 'X', info->rating() );
            if (str.isEmpty()) str = TQString("---");
            tip += cellSpecBeg + i18n("Rating:") + cellSpecMid + str + cellSpecEnd;
        }
    }

    tip += "</table>";

    d->label->setText(tip);
}

TQString AlbumFileTip::breakString(const TQString& input)
{
    TQString str = input.simplifyWhiteSpace();
    str = TQStyleSheet::escape(str);
    uint maxLen = d->maxStringLen;

    if (str.length() <= maxLen)
        return str;

    TQString br;

    uint i = 0;
    uint count = 0;

    while (i < str.length())
    {
        if (count >= maxLen && str[i].isSpace())
        {
            count = 0;
            br.append("<br>");
        }
        else
        {
            br.append(str[i]);
        }

        i++;
        count++;
    }

    return br;
}

}  // namespace Digikam
