/*
* warper.cc
* DIN Is Noise is copyright (c) 2006-2024 Jagannathan Sampath
* For more information, please visit https://dinisnoise.org/
*/


#include "warper.h"
#include "vector2d.h"
#include "ui_list.h"
#include "console.h"

#include <vector>
using namespace std;

extern ui_list uis;

warper::warper () : x ("warpx.crv"), y ("warpy.crv"), ed ("warper.ed") {
  ed.add (&x, &lis);
	ed.add (&y, &lis);
  back_ed = 0;
  name = "Warper";
}

warper::~warper () {
	x.save ("warpx.crv");
	y.save ("warpy.crv");
  widget_save ("d_warper", ctrls);
}

void warper::setup () {

  plugin::setup ();

	ctrls.push_back (&b_edit);
  num_ctrls = ctrls.size ();

  b_edit.set_text ("Edit");

  widget_load ("d_warper", ctrls);

	b_edit.set_listener (this);

  for (int i = 0; i < num_ctrls; ++i) {
    widget* ci = ctrls[i];
    if (ci != &cb_auto_apply) ci->set_color (clr.r, clr.g, clr.b);
  }


	solx (&x);
	soly (&y);

	lis.wp = this;

}

void warper::clicked (button& b) {
  if (&b == &b_edit) {
    if (b_edit.text == "Edit") {
      b_edit.set_text ("Go back");
      back_ed = uis.crved;
      uis.set_current (&ed);
    } else {
      uis.set_current (back_ed);
      b_edit.set_text ("Edit");
    }
  } else plugin::clicked (b);
}

void warper::warp (float& x, float& y, const box<float>& bbox) {
	// normalise
	float nx = (x - bbox.left) * bbox.width_1;
	float ny = (y - bbox.bottom) * bbox.height_1; 
	// warp
	float wx = solx (nx);
	float wy = soly (ny); 
	// remap
	x = bbox.left + wx * bbox.width; 
	y = bbox.bottom + wy * bbox.height;
}

void warper::render () {}

int warper::apply (multi_curve& in) {

	// warp vertices, left and right tangents and evaluate
	//
	points_array& v = in.vertices;
	points_array& lt = in.left_tangents;
	points_array& rt = in.right_tangents;
	int n = v.size ();
	if (n < 2) return 0;

	box<float> bbox; 
	in.calc_bbox (bbox);

	for (int i = 0; i < n; ++i) {
		point<float>& vi = v[i];
		point<float>& lti = lt[i];
		point<float>& rti = rt[i];
		warp (vi.x, vi.y, bbox);
		warp (lti.x, lti.y, bbox);
		warp (rti.x, rti.y, bbox);
	}   

	for (int i = 0, j = n - 1; i < j; ++i) in.curv[i].eval_state = curve::EVAL_REQUIRED;
	in.evaluate ();

	return 1;

}

void warper::draw (curve_editor* ed) {}

void warp_listener::edited (curve_editor* ed, int i) {
	multi_curve* crv = ed->get_curve (i);
	if (crv == &wp->x) wp->solx (&wp->x); else wp->soly (&wp->y);
	if (wp->cb_auto_apply.state) {
  	multi_curve& in = *wp->back_ed->get_picked_curve (); 
		wp->apply (in);
	}
}
