#include <Core/Interpolation/INTERPOLATED_COLOR_MAP.h>
#include <Core/Log/LOG.h>
#include <Core/Math_Tools/INTERVAL.h>
#include "QT_COLOR_MAP.h"
#include "QT_MATH.h"
#include <QColorDialog>
#include <QDoubleValidator>
#include <QGridLayout>
#include <QLineEdit>
#include <QPalette>
#include <QPushButton>
#include <QString>

namespace PhysBAM{
//#####################################################################
// Constructor
//#####################################################################
QT_COLOR_MAP::
QT_COLOR_MAP(QT_WINDOW& window,QT_COMPONENT& comp,CM& cm,bool& changed)
    :cm(cm),changed(changed),window(window),comp(comp)
{
    layout = new QGridLayout(this);
    QPushButton *cancel = new QPushButton("Cancel",this);
    QPushButton *apply = new QPushButton("Apply",this);
    QPushButton *accept = new QPushButton("Accept",this);
    QPushButton *rescale = new QPushButton("Rescale",this);
    QPushButton *sort = new QPushButton("Sort",this);
    QPushButton *push = new QPushButton("Push",this);
    QPushButton *pop = new QPushButton("Pop",this);
    QPushButton *reverse = new QPushButton("Reverse",this);
    QPushButton *rainbow = new QPushButton("Rainbow",this);
    QPushButton *jet = new QPushButton("Jet",this);
    QPushButton *hot = new QPushButton("Hot",this);
    connect(cancel,&QAbstractButton::clicked,this,&QT_COLOR_MAP::Action_Cancel);
    connect(apply,&QAbstractButton::clicked,this,&QT_COLOR_MAP::Action_Apply);
    connect(accept,&QAbstractButton::clicked,this,&QT_COLOR_MAP::Action_Accept);
    connect(rescale,&QAbstractButton::clicked,this,&QT_COLOR_MAP::Action_Rescale);
    connect(pop,&QAbstractButton::clicked,this,&QT_COLOR_MAP::Action_Pop);
    connect(push,&QAbstractButton::clicked,this,&QT_COLOR_MAP::Action_Push);
    connect(sort,&QAbstractButton::clicked,this,&QT_COLOR_MAP::Action_Sort);
    connect(reverse,&QAbstractButton::clicked,this,&QT_COLOR_MAP::Action_Reverse);
    connect(rainbow,&QAbstractButton::clicked,this,&QT_COLOR_MAP::Action_Rainbow);
    connect(jet,&QAbstractButton::clicked,this,&QT_COLOR_MAP::Action_Jet);
    connect(hot,&QAbstractButton::clicked,this,&QT_COLOR_MAP::Action_Hot);
    layout->addWidget(push,0,2);
    layout->addWidget(pop,1,2);
    layout->addWidget(sort,2,2);
    layout->addWidget(rescale,3,2);
    layout->addWidget(reverse,4,2);
    layout->addWidget(rainbow,5,2);
    layout->addWidget(jet,6,2);
    layout->addWidget(hot,7,2);
    layout->addWidget(cancel,8,2);
    layout->addWidget(apply,9,2);
    layout->addWidget(accept,10,2);
    layout->setColumnMinimumWidth(0,150);
    layout->setColumnMinimumWidth(1,150);
    layout->setColumnMinimumWidth(2,150);
    Rebuild_Colors();
}
//#####################################################################
// Destructor
//#####################################################################
QT_COLOR_MAP::
~QT_COLOR_MAP()
{
}
//#####################################################################
// Function Rebuild_Colors
//#####################################################################
void QT_COLOR_MAP::
Rebuild_Colors()
{
    while(color_widgets.m>cm.colors.control_points.m)
    {
        layout->removeWidget(color_widgets.Last().first);
        layout->removeWidget(color_widgets.Last().second);
        delete color_widgets.Last().first;
        delete color_widgets.Last().second;
        color_widgets.Pop();
    }
    while(color_widgets.m<cm.colors.control_points.m)
    {
        auto* col=new QPushButton("",this);
        QPalette palette;
        palette.setColor(QPalette::Button,{});
        col->setAutoFillBackground(true);
        col->setPalette(palette);
        QLineEdit* edit=new QLineEdit("",this);
        edit->setValidator(new QDoubleValidator(this));
        layout->addWidget(edit,color_widgets.m,0);
        layout->addWidget(col,color_widgets.m,1);
        int k=color_widgets.Append({edit,col});
        QObject::connect(col,&QPushButton::clicked,this,
            [this,col,k]()
            {
                QPalette palette=col->palette();
                QColor new_color=QColorDialog::getColor(
                    palette.color(QPalette::Button),this,"Select a color");
                palette.setColor(QPalette::Button,new_color);
                col->setAutoFillBackground(true);
                col->setPalette(palette);
                from_qt(cm.colors.control_points(k).second,new_color);
            });
        QObject::connect(edit,&QLineEdit::textEdited,this,
            [this,k](const QString &text)
            {
                cm.colors.control_points(k).first=text.toDouble();
            });
    }
    for(int i=0;i<cm.colors.control_points.m;i++)
    {
        const auto& a=cm.colors.control_points(i);
        color_widgets(i).first->setText(QString::number(a.first));
        QPalette palette;
        palette.setColor(QPalette::Button,to_qt_color(a.second));
        color_widgets(i).second->setPalette(palette);
    }
}
//#####################################################################
// Function Action_Cancel
//#####################################################################
void QT_COLOR_MAP::
Action_Cancel()
{
    QDialog::done(QDialog::Rejected);
}
//#####################################################################
// Function Action_Apply
//#####################################################################
void QT_COLOR_MAP::
Action_Apply()
{
    Action_Sort();
    if(apply_cmd) apply_cmd();
    window.update();
}
//#####################################################################
// Function Action_Accept
//#####################################################################
void QT_COLOR_MAP::
Action_Accept()
{
    Action_Apply();
    QDialog::done(QDialog::Accepted);
}
//#####################################################################
// Function Action_Sort
//#####################################################################
void QT_COLOR_MAP::
Action_Sort()
{
    cm.colors.control_points.Sort([](auto& a,auto& b){return a.first<b.first;});
    changed=true;
    Rebuild_Colors();
}
//#####################################################################
// Function Action_Push
//#####################################################################
void QT_COLOR_MAP::
Action_Push()
{
    std::pair<float,C> pr={};
    if(cm.colors.control_points.m)
        pr=cm.colors.control_points.Last();
    cm.colors.control_points.Append(pr);
    changed=true;
    Rebuild_Colors();
}
//#####################################################################
// Function Action_Pop
//#####################################################################
void QT_COLOR_MAP::
Action_Pop()
{
    if(cm.colors.control_points.m)
        cm.colors.control_points.Pop();
    changed=true;
    Rebuild_Colors();
}
//#####################################################################
// Function Action_Rescale
//#####################################################################
void QT_COLOR_MAP::
Action_Rescale()
{
    if(cm.colors.control_points.m==0) return;
    if(cm.colors.control_points.m==0)
        cm.colors.control_points(0).first=0;
    else
    {
        INTERVAL<float> iv;
        for(auto& p:cm.colors.control_points)
            iv.Enlarge_To_Include_Point(p.first);
        float sc=iv.Size();
        if(!sc) sc=1;
        for(auto& p:cm.colors.control_points)
            p.first=(p.first-iv.min_corner)/sc;
    }
    changed=true;
    Rebuild_Colors();
}
//#####################################################################
// Function Action_Reverse
//#####################################################################
void QT_COLOR_MAP::
Action_Reverse()
{
    if(cm.colors.control_points.m<=1) return;
    INTERVAL<float> iv;
    for(auto& p:cm.colors.control_points)
        iv.Enlarge_To_Include_Point(p.first);
    for(auto& p:cm.colors.control_points)
        p.first=iv.max_corner-p.first+iv.min_corner;
    cm.colors.control_points.Reverse();
    changed=true;
    Rebuild_Colors();
}
//#####################################################################
// Function Action_Hot
//#####################################################################
void QT_COLOR_MAP::
Action_Hot()
{
    cm.Initialize_Matlab_Hot(0,1,false,false);
    changed=true;
    Rebuild_Colors();
}
//#####################################################################
// Function Action_Jet
//#####################################################################
void QT_COLOR_MAP::
Action_Jet()
{
    cm.Initialize_Matlab_Jet(0,1,false,false);
    changed=true;
    Rebuild_Colors();
}
//#####################################################################
// Function Action_Rainbow
//#####################################################################
void QT_COLOR_MAP::
Action_Rainbow()
{
    cm.Initialize_Colors(0,1,false,false,false);
    changed=true;
    Rebuild_Colors();
}
}
