/***************************** LICENSE START ***********************************

 Copyright 2014 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

#include "MvQFolderItemProperty.h"

#include <QApplication>

#include "IconObject.h"
#include "IconInfo.h"
#include "MvQMethods.h"

//========================================
//
//     MvQAbstractIconItemProperty
//
//========================================

MvQAbstractIconItemProperty::MvQAbstractIconItemProperty() :
    fm_(QApplication::font()),
    refFm_(QApplication::font())
{
    iconSize_ = refIconSize_;
    font_ = QApplication::font();
    refFont_ = QApplication::font();
    refFm_ = QFontMetrics(font_);
}

bool MvQAbstractIconItemProperty::setIconSize(int size)
{
    if (iconSize_ == size)
        return false;

    iconSize_ = size;
    update();

    return true;
}

int MvQAbstractIconItemProperty::textWidth(QString name)
{
    return MvQ::textWidth(fm_, name);
}

int MvQAbstractIconItemProperty::refTextWidth(QString name)
{
    return MvQ::textWidth(refFm_, name);
}

int MvQAbstractIconItemProperty::textHeight()
{
    return fm_.height();
}

int MvQAbstractIconItemProperty::refTextHeight()
{
    return refFm_.height();
}


//========================================
//
//     MvQClassicIconItemProperty
//
//========================================

MvQClassicIconItemProperty::MvQClassicIconItemProperty()
{
    textOffset_ = 5;
    height_ = iconSize_ + textOffset_ + textHeight() + 2 * paddingY_;
    refHeight_ = height_;
}

void MvQClassicIconItemProperty::update()
{
    if (iconSize_ != refIconSize_) {
        if (iconSize_ > 32) {
            float dScale = static_cast<float>(iconSize_) / 32.;
            int h = refFont_.pointSize();
            font_.setPointSize(2 * (static_cast<int>(h * dScale) / 2));
        }
        else {
            font_ = refFont_;
        }

        fm_ = QFontMetrics(font_);
        height_ = iconSize_ + textOffset_ + textHeight() + 2 * paddingY_;
        scaling_ = static_cast<float>(height_) / static_cast<float>(refHeight_);
    }
    else {
        font_ = refFont_;
        fm_ = refFm_;
        height_ = refHeight_;
        scaling_ = 1.;
    }
}


QPoint MvQClassicIconItemProperty::position(QString name, QPoint refPos)
{
    if (iconSize_ != refIconSize_) {
        // Ref centre
        int refTextW = refTextWidth(name) + 2 * paddingX_;
        int refW = (refTextW < 32) ? 32 : refTextW;
        int cx = refPos.x() + refW / 2;
        // int cy=refPos.y()+refHeight_/2;

        // Item width
        int textW = textWidth(name) + 2 * paddingX_;
        int w = (textW < iconSize_) ? iconSize_ : textW;

        int x = cx * ((iconSize_ > 32) ? (scaling_ + 1) * 0.5 : 1) - w / 2;
        int y = refPos.y() * scaling_;  // cy*scaling_-height_/2;
        return {x, y};
    }

    return refPos;
}

QPoint MvQClassicIconItemProperty::positionFromHotSpot(QString name, QPoint pos, QPointF hotSpotAtPos)
{
    // hotSpotAtPos is the relative position inside the icon pixmap
    QSize s = size(name);
    QPoint d(iconSize_ * hotSpotAtPos.x(), iconSize_ * hotSpotAtPos.y());
    return {pos.x() - d.x() - (s.width() - iconSize_) / 2, pos.y() - d.y() - paddingY_};
}


QSize MvQClassicIconItemProperty::size(QString name)
{
    int textW = textWidth(name) + 2 * paddingX_;
    // int textW=fm_.boundingRect(name).width()+2*paddingX_;
    int w = (textW < iconSize_) ? iconSize_ : textW;
    return {w, height_};
}

// Position of the top-left corner of the item at pos in the scene as if it had iconSize=32
QPoint MvQClassicIconItemProperty::referencePosition(QString name, QPoint pos)
{
    if (iconSize_ != refIconSize_) {
        // Item width
        int textW = textWidth(name) + 2 * paddingX_;
        int w = (textW < iconSize_) ? iconSize_ : textW;

        // Item centre
        int cx = (pos.x() + w / 2) / ((iconSize_ > 32) ? (scaling_ + 1) * 0.5 : 1);
        // int cy=pos.y()+height_/2;

        // Ref width
        int refTextW = refTextWidth(name) + 2 * paddingX_;
        int refW = (refTextW < 32) ? 32 : refTextW;

        // Ref
        int refX = cx - refW / 2;
        int refY = pos.y() / scaling_;  // cy/scaling_-refHeight_/2;

        return {refX, refY};
    }

    return pos;
}

QPoint MvQClassicIconItemProperty::adjsutReferencePosition(QString name, QString oriName, QPoint pos)
{
    // Ref width
    int oriW = refTextWidth(oriName) + 2 * paddingX_;
    if (oriW < 32)
        oriW = 32;
    int w = refTextWidth(name) + 2 * paddingX_;
    if (w < 32)
        w = 32;

    return QPoint(pos.x() - (w - oriW) / 2., pos.y());
}

QRect MvQClassicIconItemProperty::iconRect(QString name)
{
    QSize s = size(name);
    return {s.width() / 2 - iconSize_ / 2,
            paddingY_ + 1,
            iconSize_,
            iconSize_};
}


QRect MvQClassicIconItemProperty::textRect(QString name)
{
    return {paddingX_,
            paddingY_ + iconSize_ + textOffset_,
            textWidth(name),
            textHeight()};
}

// The reference position we store in the iconobject is the top-left corner of the item
// without the padding. This is how Desktop was first released and how MetviewUI worked.
// However, the reference position in the view is the top-left corner of the item
// including a (now) non-zero padding! So to get the position we want to store in the iconobject
// we need to add the padding to the reference position of the item in the view.
// We assume that the padding is the same for all the iconsizes.

QPoint MvQClassicIconItemProperty::storedPosition(QPoint viewRefPos)
{
    return viewRefPos + QPoint(paddingX_, paddingY_);
}

// The reference position we store in the iconobject is the top-left corner of the item
// without the padding at iconSize=32. This is how Desktop was first released and how MetviewUI worked.
// However, the reference position in the view is the top-left corner of the item
// including a (now) non-zero padding! So to get the position of the item in the view
// we need to subtract the padding from reference position stored in the iconobject.
// We assume that the padding is the same for all the iconsizes.

QPoint MvQClassicIconItemProperty::referencePosition(IconObject* obj)
{
    return {obj->info().x() - paddingX_,
            obj->info().y() - paddingY_};
}

QPoint MvQClassicIconItemProperty::referencePositionFromStored(QPoint storedPos)
{
    return {storedPos.x() - paddingX_,
            storedPos.y() - paddingY_};
}


//========================================
//
//     MvQSimpleIconItemProperty
//
//========================================

MvQSimpleIconItemProperty::MvQSimpleIconItemProperty()
{
    textOffset_ = 5;
    height_ = iconSize_ + 2 * paddingY_;
    refHeight_ = height_;
}


void MvQSimpleIconItemProperty::update()
{
    if (iconSize_ != refIconSize_) {
        if (iconSize_ > 32) {
            float dScale = static_cast<float>(iconSize_) / 32.;
            int h = refFont_.pointSize();
            font_.setPointSize(2 * (static_cast<int>(h * dScale) / 2));
        }
        else {
            font_ = refFont_;
        }

        fm_ = QFontMetrics(font_);
        height_ = iconSize_ + 2 * paddingY_;
        scaling_ = static_cast<float>(height_) / static_cast<float>(refHeight_);
    }
    else {
        font_ = refFont_;
        fm_ = refFm_;
        height_ = refHeight_;
        scaling_ = 1.;
    }
}


QPoint MvQSimpleIconItemProperty::position(QString, QPoint refPos)
{
    if (iconSize_ != refIconSize_) {
        int x = refPos.x() * ((iconSize_ > 32) ? (scaling_ + 1) * 0.5 : 1);
        int y = refPos.y() * scaling_;
        return {x, y};
    }

    return refPos;
}

QPoint MvQSimpleIconItemProperty::positionFromHotSpot(QString /*name*/, QPoint pos, QPointF hotSpotAtPos)
{
    // hotSpotAtPos is the relative position inside the icon pixmap
    QPoint d(iconSize_ * hotSpotAtPos.x(), iconSize_ * hotSpotAtPos.y());
    return {pos.x() - d.x() - paddingX_, pos.y() - d.y() - paddingY_};
}


QSize MvQSimpleIconItemProperty::size(QString name)
{
    int w = iconSize_ + textOffset_ + textWidth(name) + 2 * paddingX_;
    return {w, height_};
}


QPoint MvQSimpleIconItemProperty::referencePosition(QString, QPoint pos)
{
    if (iconSize_ != refIconSize_) {
        // Ref
        int refX = pos.x() / ((iconSize_ > 32) ? (scaling_ + 1) * 0.5 : 1);
        int refY = pos.y() / scaling_;
        return {refX, refY};
    }

    return pos;
}

QPoint MvQSimpleIconItemProperty::adjsutReferencePosition(QString /*name*/, QString /*oriName*/, QPoint /*pos*/)
{
    return {};
}

QRect MvQSimpleIconItemProperty::iconRect(QString /*name*/)
{
    return {paddingX_,
            paddingY_,
            iconSize_,
            iconSize_};
}


QRect MvQSimpleIconItemProperty::textRect(QString name)
{
    QSize s = size(name);
    return {paddingX_ + iconSize_ + textOffset_,
            (s.height() - textHeight()) / 2,
            textWidth(name),
            textHeight()};
}
// The reference position we store in the iconobject is the top-left corner of the item
// without the padding. This is how Desktop was first released and how MetviewUI worked.
// However, the reference position in the view is the top-left corner of the item
// including a (now) non-zero padding! So to get the position we want to store in the iconobject
// we need to add the padding to the reference position of the item in the view.
// We assume that the padding is the same for all the iconsizes.

QPoint MvQSimpleIconItemProperty::storedPosition(QPoint viewRefPos)
{
    return viewRefPos +
           QPoint(paddingX_, paddingY_);
}

// The reference position we store in the iconobject is the top-left corner of the item
// without the padding. This is how Desktop was first released and how MetviewUI worked.
// However, the reference position in the view is the top-left corner of the item
// including a (now) non-zero padding! So to get the position of the item in the view
// we need to subtract the padding from reference position stored in the iconobject.
// We assume that the padding is the same for all the iconsizes.

QPoint MvQSimpleIconItemProperty::referencePosition(IconObject* obj)
{
    return {obj->info().x() - paddingX_,
            obj->info().y() - paddingY_};
}

QPoint MvQSimpleIconItemProperty::referencePositionFromStored(QPoint storedPos)
{
    return {storedPos.x() - paddingX_,
            storedPos.y() - paddingY_};
}


//========================================
//
//     MvQDetailedIconItemProperty
//
//========================================

MvQDetailedIconItemProperty::MvQDetailedIconItemProperty()
{
    textOffset_ = 5;
    height_ = iconSize_;
    refHeight_ = height_;
}

void MvQDetailedIconItemProperty::update()
{
    if (iconSize_ != refIconSize_) {
        if (iconSize_ > 32) {
            float dScale = static_cast<float>(iconSize_) / 32.;
            int h = refFont_.pointSize();
            font_.setPointSize(2 * (static_cast<int>(h * dScale) / 2));
        }
        else {
            font_ = refFont_;
        }

        fm_ = QFontMetrics(font_);
        height_ = iconSize_ + textOffset_ + fm_.height();
        scaling_ = static_cast<float>(height_) / static_cast<float>(refHeight_);
    }
    else {
        font_ = refFont_;
        fm_ = refFm_;
        height_ = refHeight_;
        scaling_ = 1.;
    }
}


QPoint MvQDetailedIconItemProperty::position(QString /*name*/, QPoint refPos)
{
    return refPos;
}

QPoint MvQDetailedIconItemProperty::positionFromHotSpot(QString /*name*/, QPoint pos, QPointF /*hotSpotAtPos*/)
{
    return pos;
}


QSize MvQDetailedIconItemProperty::size(QString name)
{
    int textW = MvQ::textWidth(fm_, name);
    int w = iconSize_ + textOffset_ + textW;
    return {w, height_};
}

QPoint MvQDetailedIconItemProperty::referencePosition(QString /*name*/, QPoint pos)
{
    return pos;
}

QPoint MvQDetailedIconItemProperty::adjsutReferencePosition(QString /*name*/, QString /*oriName*/, QPoint pos)
{
    return pos;
}

QRect MvQDetailedIconItemProperty::iconRect(QString name)
{
    QSize s = size(name);
    return {s.width() / 2 - iconSize_ / 2,
            paddingY_,
            iconSize_,
            iconSize_};
}


QRect MvQDetailedIconItemProperty::textRect(QString name)
{
    QSize s = size(name);
    return {0,
            paddingY_ + textOffset_,
            s.width(),
            s.height() - (iconSize_ + textOffset_ + 2 * paddingY_)};
}


QPoint MvQDetailedIconItemProperty::storedPosition(QPoint viewRefPos)
{
    return viewRefPos;
}

QPoint MvQDetailedIconItemProperty::referencePosition(IconObject*)
{
    return {};
}

QPoint MvQDetailedIconItemProperty::referencePositionFromStored(QPoint storedPos)
{
    return storedPos;
}


//============================================
//
//   MvQFolderItemProperty
//
//============================================

MvQFolderItemProperty::MvQFolderItemProperty() :
    viewMode_(Desktop::IconViewMode),
    current_(nullptr)

{
    prop_[Desktop::IconViewMode] = new MvQClassicIconItemProperty;
    prop_[Desktop::SimpleViewMode] = new MvQSimpleIconItemProperty;
    prop_[Desktop::DetailedViewMode] = new MvQDetailedIconItemProperty;
    current_ = prop_[viewMode_];
    iconSize_ = current_->iconSize();
}

MvQFolderItemProperty::~MvQFolderItemProperty()
{
    QMap<Desktop::FolderViewMode, MvQAbstractIconItemProperty*>::iterator it = prop_.begin();
    while (it != prop_.end()) {
        delete it.value();
        ++it;
    }
}

int MvQFolderItemProperty::iconSize()
{
    return iconSize_;
}

float MvQFolderItemProperty::scaling()
{
    return current_->scaling();
}

QFont MvQFolderItemProperty::font()
{
    return current_->font();
}

int MvQFolderItemProperty::textHeight()
{
    return current_->textHeight();
}

int MvQFolderItemProperty::textOffset()
{
    return current_->textOffset();
}

int MvQFolderItemProperty::paddingX() const
{
    return current_->paddingX();
}

int MvQFolderItemProperty::paddingY() const
{
    return current_->paddingY();
}

void MvQFolderItemProperty::setViewMode(Desktop::FolderViewMode mode)
{
    viewMode_ = mode;
    QMap<Desktop::FolderViewMode, MvQAbstractIconItemProperty*>::iterator it = prop_.find(mode);
    if (it != prop_.end()) {
        current_ = it.value();
        current_->setIconSize(iconSize_);
    }
}

/*void MvQFolderItemProperty::setTextPosMode(TextPosMode tp)
{
    textPosMode_=tp;
    QMap<TextPosMode,MvQAbstractIconItemProperty*>::iterator it=prop_.find(tp);
    if( it != prop_.end())
    {
        current_=it.value();
    }
} */

bool MvQFolderItemProperty::setIconSize(int size)
{
    if (iconSize_ == size)
        return false;

    iconSize_ = size;
    current_->setIconSize(iconSize_);

    return true;
}

/*	retVal=it.value()->setIconSize(size);

    QMap<TextPosMode,MvQAbstractIconItemProperty*>::iterator it = prop_.begin();
    while(it != prop_.end())
    {
        if(it.value() == current_)
        {
            retVal=it.value()->setIconSize(size);
        }
        else
        {
            it.value()->setIconSize(size);
        }
        ++it;
    }

    return retVal;
}  */

QPoint MvQFolderItemProperty::position(QString name, QPoint refPos)
{
    return current_->position(name, refPos);
}

QPoint MvQFolderItemProperty::positionFromHotSpot(QString name, QPoint pos, QPointF hotSpotAtPos)
{
    return current_->positionFromHotSpot(name, pos, hotSpotAtPos);
}

QSize MvQFolderItemProperty::size(QString name)
{
    return current_->size(name);
}

QPoint MvQFolderItemProperty::referencePosition(QString name, QPoint pos)
{
    return current_->referencePosition(name, pos);
}

QPoint MvQFolderItemProperty::adjsutReferencePosition(QString name, QString oriName, QPoint pos)
{
    return current_->adjsutReferencePosition(name, oriName, pos);
}

QRect MvQFolderItemProperty::textRect(QString name)
{
    return current_->textRect(name);
}

QRect MvQFolderItemProperty::iconRect(QString name)
{
    return current_->iconRect(name);
}

QPoint MvQFolderItemProperty::storedPosition(QPoint viewRefPos)
{
    return current_->storedPosition(viewRefPos);
}

QPoint MvQFolderItemProperty::referencePosition(IconObject* obj)
{
    return current_->referencePosition(obj);
}

QPoint MvQFolderItemProperty::referencePositionFromStored(QPoint storedPos)
{
    return current_->referencePositionFromStored(storedPos);
}
