//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      GUI/Model/Mask/MaskUnitsConverter.cpp
//! @brief     Implements class MaskUnitsConverter
//!
//! @homepage  http://www.bornagainproject.org
//! @license   GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2018
//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
//
//  ************************************************************************************************

#include "GUI/Model/Mask/MaskUnitsConverter.h"
#include "Base/Axis/Frame.h"
#include "Base/Axis/FrameUtil.h"
#include "GUI/Model/Mask/MaskItems.h"
#include "GUI/Model/Mask/PointItem.h"

MaskUnitsConverter::MaskUnitsConverter(const Frame& frame)
    : m_frame(frame)
    , m_direction(UNDEFINED)
{
}

//! Converts mask from coordinates of Frame to axes bin-fraction coordinates.

void MaskUnitsConverter::convertToNbins(MaskItem* maskItem)
{
    m_direction = TO_NBINS;
    convertMask(maskItem);
}

//! Converts mask from bin-fraction coordinates to coordinates of Frame axes.

void MaskUnitsConverter::convertFromNbins(MaskItem* maskItem)
{
    m_direction = FROM_NBINS;
    convertMask(maskItem);
}

//! Converts single mask from/to bin-fraction coordinates

void MaskUnitsConverter::convertMask(MaskItem* maskItem)
{
    if (auto* rectItem = dynamic_cast<RectangleItem*>(maskItem)) {
        rectItem->setXLow(convert(rectItem->xLow(), Axis::X));
        rectItem->setYLow(convert(rectItem->yLow(), Axis::Y));
        rectItem->setXUp(convert(rectItem->xUp(), Axis::X));
        rectItem->setYUp(convert(rectItem->yUp(), Axis::Y));
    } else if (auto* poly = dynamic_cast<PolygonItem*>(maskItem)) {
        for (PointItem* pointItem : poly->points()) {
            pointItem->setPosX(convert(pointItem->posX(), Axis::X));
            pointItem->setPosY(convert(pointItem->posY(), Axis::Y));
        }
    } else if (auto* vlineItem = dynamic_cast<VerticalLineItem*>(maskItem)) {
        vlineItem->setPos(convert(vlineItem->pos(), Axis::X));
    } else if (auto* hlineItem = dynamic_cast<HorizontalLineItem*>(maskItem)) {
        hlineItem->setPos(convert(hlineItem->pos(), Axis::Y));
    } else if (auto* ellItem = dynamic_cast<EllipseItem*>(maskItem)) {
        double xc = ellItem->xCenter();
        double yc = ellItem->yCenter();
        double xR = ellItem->xRadius();
        double yR = ellItem->yRadius();

        double x2 = xc + xR;
        double y2 = yc + yR;

        if (m_direction == TO_NBINS) {
            FrameUtil::coordinatesToBinf(xc, yc, m_frame);
            FrameUtil::coordinatesToBinf(x2, y2, m_frame);
        } else {
            FrameUtil::coordinatesFromBinf(xc, yc, m_frame);
            FrameUtil::coordinatesFromBinf(x2, y2, m_frame);
        }
        ellItem->setXCenter(xc);
        ellItem->setYCenter(yc);
        ellItem->setXRadius(x2 - xc);
        ellItem->setYRadius(y2 - yc);
    }
}

//! Convert value of axis from/to bin-fraction coordinates.

double MaskUnitsConverter::convert(double value, Axis axis)
{
    auto axis_index = static_cast<size_t>(axis);

    ASSERT(axis_index == 0 || axis_index == 1);

    if (m_direction == TO_NBINS)
        return FrameUtil::coordinateToBinf(value, m_frame.axis(axis_index));
    if (m_direction == FROM_NBINS)
        return FrameUtil::coordinateFromBinf(value, m_frame.axis(axis_index));
    ASSERT(false);
}
