#include "cnkalman/ModelPlot.h"
#include <algorithm>

namespace cnkalman {
  ModelPlot::ModelPlot(const std::string &name, bool show) : show(show), name(name) {
#ifdef HAS_SCIPLOT
        plot.gnuplot("set title \"" + name + "\"");
        map.gnuplot("set title \"" + name + "\"");
        map.palette("paired");

        map.size(1600, 1600);
        map.gnuplot("set size square");
        map.border().none();

        plot.size(1600, 1200);
#endif
    }

    void ModelPlot::include_point_in_range(const FLT *X) {
        if(lock_range) return;

        for (int x = 0; x < 2; x++) {
            range[x * 2] = std::min(range[x * 2], X[x]);
            range[x * 2 + 1] = std::max(range[x * 2 + 1], X[x]);
        }
    }

    void ModelPlot::include_point_in_range(FLT x, FLT y) {
        FLT Xs[] = {x, y};
        include_point_in_range(Xs);
    }

    void ModelPlot::get_view(FLT &x, FLT &y, FLT &w, FLT &h) const {
        FLT dx = fmax(1, range[1] - range[0]);
        FLT dy = fmax(1, range[3] - range[2]);
        FLT R0 = range[0] - .1 * dx;
        FLT R1 = range[1] + .1 * dx;
        FLT R2 = range[2] - .1 * dy;
        FLT R3 = range[3] + .1 * dy;
        w = R1 - R0, h = R3 - R2;
        x = R1 - w / 2, y = R3 - h / 2;
        w = fmax(w, h);
        h = w;
    }

    ModelPlot::~ModelPlot() {

        FLT dx = fmax(1e-3, range[1] - range[0]);
        FLT dy = fmax(1e-3, range[3] - range[2]);
        range[0] -= .1 * dx;
        range[1] += .1 * dx;
        range[2] -= .1 * dy;
        range[3] += .1 * dy;
        FLT w = range[1] - range[0], h = range[3] - range[2];
        FLT x = range[1] - w / 2, y = range[3] - h / 2;
        w = fmax(w, h);
        range[0] = x - w / 2;
        range[1] = x + w / 2.;
        range[2] = y - w / 2;
        range[3] = y + w / 2.;
#ifdef HAS_SCIPLOT
        map.xrange(range[0], range[1]);
        map.yrange(range[2], range[3]);

        if (show) {
            plot.show();
            map.show();
        }
        plot.save(name + "-plot.svg");
        map.save(name + ".svg");
        map.save(name + ".png");
#endif
    }

    void ModelPlot::plot_cov(const cnkalman::KalmanModel &model, FLT deviations, const std::string &color) {
#ifdef HAS_SCIPLOT
        CN_CREATE_STACK_MAT(Pp, 2, 2);
        CN_CREATE_STACK_MAT(Evec, 2, 2);
        CN_CREATE_STACK_VEC(Eval, 2);
        static int idx = 1;

        cnCopy(&model.kalman_state.P, &Pp, 0);
        cnSVD(&Pp, &Eval, &Evec, 0, (enum cnSVDFlags)0);
        FLT angle = atan2(_Evec[2], _Evec[0]) *57.2958;
        FLT v1 = deviations*2*sqrt(_Eval[0]), v2 = deviations*2*sqrt(_Eval[1]);
        std::stringstream ss;
        ss << "set obj " << idx++ << " ellipse fc rgb \"" << color << "\" fs transparent solid .5 center "
           << (model.state[0]) << "," <<
           (model.state[1]) << " size "
           << v1 << "," << v2 <<
           " angle " << angle << " front\n";
        map.gnuplot(ss.str());
#endif
    }
}
