/***************************************************************************
                          fov.cpp  -  description
                             -------------------
    begin                : Fri 05 Sept 2003
    copyright            : (C) 2003 by Jason Harris
    email                : kstars@30doradus.org
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "fov.h"
#include "Options.h"
#ifndef KSTARS_LITE
#include "kstars.h"
#endif
#include "kstarsdata.h"
#include "geolocation.h"
#include "skymap.h"
#include "projections/projector.h"

#include <algorithm>

#include <QPainter>
#include <QTextStream>
#include <QFile>
#include <QDebug>
#include <QStandardPaths>
#include "kspaths.h"

QList<FOV *> FOVManager::m_FOVs;

FOVManager::FOVManager()
{
}

FOVManager::~FOVManager()
{
    qDeleteAll(m_FOVs);
}

QList<FOV *> FOVManager::defaults()
{
    QList<FOV *> fovs;
    fovs << new FOV(i18nc("use field-of-view for binoculars", "7x35 Binoculars"), 558, 558, 0, 0, 0, FOV::CIRCLE,
                    "#AAAAAA")
         << new FOV(i18nc("use a Telrad field-of-view indicator", "Telrad"), 30, 30, 0, 0, 0, FOV::BULLSEYE, "#AA0000")
         << new FOV(i18nc("use 1-degree field-of-view indicator", "One Degree"), 60, 60, 0, 0, 0, FOV::CIRCLE,
                    "#AAAAAA")
         << new FOV(i18nc("use HST field-of-view indicator", "HST WFPC2"), 2.4, 2.4, 0, 0, 0, FOV::SQUARE, "#AAAAAA")
         << new FOV(i18nc("use Radiotelescope HPBW", "30m at 1.3cm"), 1.79, 1.79, 0, 0, 0, FOV::SQUARE, "#AAAAAA");
    return fovs;
}

bool FOVManager::save()
{
    QFile f;

    // TODO: Move FOVs to user database instead of file!!
    f.setFileName(KSPaths::writableLocation(QStandardPaths::GenericDataLocation) + "fov.dat");

    if (!f.open(QIODevice::WriteOnly))
    {
        qDebug() << "Could not open fov.dat.";
        return false;
    }

    QTextStream ostream(&f);
    foreach (FOV *fov, m_FOVs)
    {
        ostream << fov->name() << ':' << fov->sizeX() << ':' << fov->sizeY() << ':' << fov->offsetX() << ':'
                << fov->offsetY() << ':' << fov->rotation() << ':' << QString::number(fov->shape())
                << ':' //FIXME: is this needed???
                << fov->color() << endl;
    }
    f.close();

    return true;
}

const QList<FOV *> &FOVManager::readFOVs()
{
    qDeleteAll(m_FOVs);
    m_FOVs.clear();

    QFile f;
    f.setFileName(KSPaths::writableLocation(QStandardPaths::GenericDataLocation) + "fov.dat");

    if (!f.exists())
    {
        m_FOVs = defaults();
        save();
        return m_FOVs;
    }

    if (f.open(QIODevice::ReadOnly))
    {
        QTextStream istream(&f);
        while (!istream.atEnd())
        {
            QStringList fields = istream.readLine().split(':');
            bool ok;
            QString name, color;
            float sizeX, sizeY, xoffset, yoffset, rot;
            FOV::Shape shape;
            if (fields.count() == 8)
            {
                name  = fields[0];
                sizeX = fields[1].toFloat(&ok);
                if (!ok)
                {
                    return m_FOVs;
                }
                sizeY = fields[2].toFloat(&ok);
                if (!ok)
                {
                    return m_FOVs;
                }
                xoffset = fields[3].toFloat(&ok);
                if (!ok)
                {
                    return m_FOVs;
                }

                yoffset = fields[4].toFloat(&ok);
                if (!ok)
                {
                    return m_FOVs;
                }

                rot = fields[5].toFloat(&ok);
                if (!ok)
                {
                    return m_FOVs;
                }

                shape = FOV::intToShape(fields[6].toInt(&ok));
                if (!ok)
                {
                    return m_FOVs;
                }
                color = fields[7];
            }
            else
            {
                continue;
            }

            m_FOVs.append(new FOV(name, sizeX, sizeY, xoffset, yoffset, rot, shape, color));
        }
    }
    return m_FOVs;
}

void FOVManager::releaseCache()
{
    qDeleteAll(m_FOVs);
    m_FOVs.clear();
}

FOV::Shape FOV::intToShape(int s)
{
    return (s >= FOV::UNKNOWN || s < 0) ? FOV::UNKNOWN : static_cast<FOV::Shape>(s);
}

FOV::FOV(const QString &n, float a, float b, float xoffset, float yoffset, float rot, Shape sh, const QString &col)
{
    m_name  = n;
    m_sizeX = a;
    m_sizeY = (b < 0.0) ? a : b;

    m_offsetX  = xoffset;
    m_offsetY  = yoffset;
    m_rotation = rot;
    m_shape    = sh;
    m_color    = col;
    m_northPA  = 0;
    m_center.setRA(0);
    m_center.setDec(0);
    m_imageDisplay = false;
}

FOV::FOV()
{
    m_name  = i18n("No FOV");
    m_color = "#FFFFFF";

    m_sizeX = m_sizeY = 0;
    m_shape           = SQUARE;
    m_offsetX = m_offsetY = m_rotation = 0, m_northPA = 0;
    m_imageDisplay = false;
}

void FOV::draw(QPainter &p, float zoomFactor)
{
    p.setPen(QColor(color()));
    p.setBrush(Qt::NoBrush);

    p.setRenderHint(QPainter::Antialiasing, Options::useAntialias());

    float pixelSizeX = sizeX() * zoomFactor / 57.3 / 60.0;
    float pixelSizeY = sizeY() * zoomFactor / 57.3 / 60.0;

    float offsetXPixelSize = offsetX() * zoomFactor / 57.3 / 60.0;
    float offsetYPixelSize = offsetY() * zoomFactor / 57.3 / 60.0;

    p.save();

    if (m_center.ra().Degrees() > 0)
    {
        m_center.EquatorialToHorizontal(KStarsData::Instance()->lst(), KStarsData::Instance()->geo()->lat());
        QPointF skypoint_center = KStars::Instance()->map()->projector()->toScreen(&m_center);
        p.translate(skypoint_center.toPoint());
    }
    else
        p.translate(p.viewport().center());

    p.translate(offsetXPixelSize, offsetYPixelSize);
    p.rotate(m_rotation + m_northPA);

    QPointF center(0, 0);

    switch (shape())
    {
        case SQUARE:
        {
            QRect targetRect(center.x() - pixelSizeX / 2, center.y() - pixelSizeY / 2, pixelSizeX, pixelSizeY);
            if (m_imageDisplay)
            {
                //QTransform imageT;
                //imageT.rotate(m_rotation+m_northPA);
                //p.drawImage(targetRect, m_image.transformed(imageT));
                p.drawImage(targetRect, m_image);
            }
            p.drawRect(targetRect);
            p.drawRect(center.x(), center.y() - (3 * pixelSizeY / 5), pixelSizeX / 40, pixelSizeX / 10);
            p.drawLine(center.x() - pixelSizeX / 30, center.y() - (3 * pixelSizeY / 5), center.x() + pixelSizeX / 20,
                       center.y() - (3 * pixelSizeY / 5));
            p.drawLine(center.x() - pixelSizeX / 30, center.y() - (3 * pixelSizeY / 5), center.x() + pixelSizeX / 70,
                       center.y() - (0.7 * pixelSizeY));
            p.drawLine(center.x() + pixelSizeX / 20, center.y() - (3 * pixelSizeY / 5), center.x() + pixelSizeX / 70,
                       center.y() - (0.7 * pixelSizeY));
        }
        break;
        case CIRCLE:
            p.drawEllipse(center, pixelSizeX / 2, pixelSizeY / 2);
            break;
        case CROSSHAIRS:
            //Draw radial lines
            p.drawLine(center.x() + 0.5 * pixelSizeX, center.y(), center.x() + 1.5 * pixelSizeX, center.y());
            p.drawLine(center.x() - 0.5 * pixelSizeX, center.y(), center.x() - 1.5 * pixelSizeX, center.y());
            p.drawLine(center.x(), center.y() + 0.5 * pixelSizeY, center.x(), center.y() + 1.5 * pixelSizeY);
            p.drawLine(center.x(), center.y() - 0.5 * pixelSizeY, center.x(), center.y() - 1.5 * pixelSizeY);
            //Draw circles at 0.5 & 1 degrees
            p.drawEllipse(center, 0.5 * pixelSizeX, 0.5 * pixelSizeY);
            p.drawEllipse(center, pixelSizeX, pixelSizeY);
            break;
        case BULLSEYE:
            p.drawEllipse(center, 0.5 * pixelSizeX, 0.5 * pixelSizeY);
            p.drawEllipse(center, 2.0 * pixelSizeX, 2.0 * pixelSizeY);
            p.drawEllipse(center, 4.0 * pixelSizeX, 4.0 * pixelSizeY);
            break;
        case SOLIDCIRCLE:
        {
            QColor colorAlpha = color();
            colorAlpha.setAlpha(127);
            p.setBrush(QBrush(colorAlpha));
            p.drawEllipse(center, pixelSizeX / 2, pixelSizeY / 2);
            p.setBrush(Qt::NoBrush);
            break;
        }
        default:;
    }

    p.restore();
}

void FOV::draw(QPainter &p, float x, float y)
{
    float xfactor    = x / sizeX() * 57.3 * 60.0;
    float yfactor    = y / sizeY() * 57.3 * 60.0;
    float zoomFactor = std::min(xfactor, yfactor);
    switch (shape())
    {
        case CROSSHAIRS:
            zoomFactor /= 3;
            break;
        case BULLSEYE:
            zoomFactor /= 8;
            break;
        default:;
    }
    draw(p, zoomFactor);
}

void FOV::setShape(int s)
{
    m_shape = intToShape(s);
}

SkyPoint FOV::center() const
{
    return m_center;
}

void FOV::setCenter(const SkyPoint &center)
{
    m_center = center;
}

float FOV::northPA() const
{
    return m_northPA;
}

void FOV::setNorthPA(float northPA)
{
    m_northPA = northPA;
}

void FOV::setImage(const QImage &image)
{
    m_image = image;
}

void FOV::setImageDisplay(bool value)
{
    m_imageDisplay = value;
}
