/*
* curve_editor.h
* DIN Is Noise is copyright (c) 2006-2024 Jagannathan Sampath
* DIN Is Noise is released under GNU Public License 2.0
* For more information, please visit https://dinisnoise.org/
*/


#ifndef __curve_editor
#define __curve_editor

#include <vector>
#include <map>
#include <list>
#include <string>
#include <fstream>

#include "curve.h"
#include "multi_curve.h"
#include "basic_editor.h"
#include "curve_listener.h"
#include "curve_samples.h"
#include "ui.h"
#include "mocap.h"
#include "beat2value.h"
#include "box_selector.h"
#include "curve_picker.h"
#include "checkbutton.h"
#include "state_button.h"
#include "capturer.h"
#include "point_modulator.h"
#include "hit.h"
#include "help.h"
#include "angle.h"

struct multi_curve;
struct curve_editor;
struct curve_library;
struct plugin;

struct mouse_macro {
  // for applying mouse capture to hit vertex/tangent of hit curve
  mocap mo; // mouse capture data
  hit_t hit; // hit curve & vertex/tangent
	state_button* sb; // button on capturer widget
	int paused;
  mouse_macro (const mocap& m, hit_t& h, state_button* b) : mo(m), hit(h), sb(b) { paused = 0;}
};

struct undo_t {
  int i;
  multi_curve curve;
  window win;
  undo_t (int ii, const multi_curve& mc, window& w) : i(ii), curve(mc), win(w) {}
};

typedef undo_t redo_t;

struct curve_info {

  multi_curve* curve;
  curve_listener* lisner;

	int picked;

  int visible;

  float lastrpm;
  float angle;
  float totang;
  int dir;

  int autoflip;
  anglet every0, every;
  int randoflip;
  rnd<float> rd;
  void randeg () {
    every = rd () * every0.deg;
  }
  double startt;

  curve_info  (multi_curve* c, curve_listener* l, int picked = 0);
  curve_info ();
  void init ();
};

struct curve_editor : basic_editor {

  // edited curves
  //
  std::vector <curve_info> curveinfo; 
  int curves;
  int curcrv;
  int curcrvchgd;
  int visibles;
  int setcrvvis (int i, int v);
  int onecurve () { return (curves == 1 || visibles == 1); }
  int savedrots;
  void add (multi_curve* crv, curve_listener* lsnr);
  void clear ();
  multi_curve* get_curve (int i);


  // curve editor features
  //

  int carry_tangents; // when vertex moves, their tangents move too.
  int mirror_tangents; // when 1 tangent of a vertex moves, the other moves too.

  // picking
	//

  std::vector <hit_t> hitlist;
  hit_t pik;
	multi_curve* get_picked_curve ();
	hit_t pick_cur_curve ();
	void set_picked_curve_name (const std::string& n);
  void curve_picked ();
	void hilite_item (int id);

  void hittest (multi_curve* crv, int crv_id, const points_array& points, unsigned int what);
  void hittest ();
  int filter_hitlist ();
  void clear_hit (hit_t& h);
  void calc_hit_params (hit_t& h);
  void set_pick_from_hitlist (int i);
  void picked_using_picker (int i);

  // vertex/tangent operations
	//
  enum {
    NOTHING = 0,
    MOVE_PICKED, 
    MOVE_ALL, 
    PICK_CURVE, 
    INSERT_VERTEX, 
    REMOVE_VERTEX, 
    FOLD_VERTEX, 
    UNFOLD_VERTEX, 
    FOLD_ALL, 
    UNFOLD_ALL, 
    MIRROR_VERTEX, 
    MIRROR_ALL, 
    COPY, 
    PASTE,
    ADD_VERTEX,
    START_CAPTURE,
    ASSIGN_CAPTURE,
    REMOVE_CAPTURE,
		MODULATE_POINT
  };

  int todo;
  int next_todo;
	int stop_todo ();

  void abs_nothing ();
  void quick_nothing ();

  void do_pick_curve ();

	int lmb_move;
	enum {PREP = 1, FINISH_ON_CLICK = 2};
	void prep_move ();
  int move ();
  int move (int);
  int move (hit_t& hit, float x, float y, int eval_now = 1);

  void fold_tangents_using_menu ();
  void unfold_tangents_using_menu ();
  void fold_all_tangents (hit_t& hit);
  void unfold_all_tangents (hit_t& hit);
  void fold_tangents_of_vertex (hit_t& hit);
  void unfold_tangents_of_vertex (hit_t& hit);

  void insert ();
  void insert_using_menu ();

  void remove ();
  void remove_using_menu ();

	enum {MIRROR_X = 0, MIRROR_Y, MIRROR_BBX, MIRROR_BBY};
	int axis;
  void mirror (int whole_curve = 0);
  void mirror_using_menu ();

  void set_limit (float f);

  void copy_curve ();
  void copy_using_menu ();

  void replace ();
  void paste_using_menu ();

	void swap ();

  // scratch curve
  //
  int show_scratch_curve;
  points_array win_scratch_points, curv_scratch_points;
  multi_curve scratch_curve;
  void clear_scratch_curve ();
  void draw_scratch_curve ();
  void draw_replacement_curve_using_menu ();
  void add_vertex ();

  // load and save editor settings
  std::string settings_filename;

  // undo, redo
  //
  std::list <undo_t> undos;
  std::list <redo_t> redos;
  void dodo (std::list<undo_t>& do1, std::list<undo_t>& do2, std::string mesg);
  void do_undo ();
  void do_redo ();

  // copy & paste
  static multi_curve copy;
  void paste (hit_t& h);

  // curve library
  //
  curve_library* library;
  void add_curve ();
  void replace_curve ();
  void insert_curve ();
  void delete_curve ();
  void load_curve (int dir);
  void do_load_curve (int dir);

  // mouse capture
  //
  std::vector<mouse_macro> macros;
	capturer_t capturer;
  void start_mouse_capture_from_menu ();
  void assign_mouse_capture ();
  void assign_mouse_capture_from_menu ();
	void remove_mouse_capture (state_button* sb);
	void toggle_mouse_capture (std::vector<state_button*>& caps);

	// point modulation
	point_modulator pomo;
	void modulate_point ();
	void modulate_point (int);

  // settings
  //
  curve_editor (const std::string& settingsf);
  ~curve_editor ();
  void load (const std::string& fname);
  void save ();

  // ui
  int handle_input ();


  // curve selection ops
  void toggle (int k);
  void enable (int k);
  void enable_all ();
  int one_curve_enabled ();
  std::string selection ();

	// drawing
	//

	int draw_curve_only;
	void draw_curve (multi_curve* crv);
  void draw_tangents (multi_curve* crv);
  void draw_vertices (multi_curve* crv);
  void draw_handle (const point<float>& p);
  void draw_tangent (const point<float>& p, const point<float>& t);
  void draw_curves ();
  void draw_vertices ();
  void draw_tangents ();
	void draw_all ();
	void draw ();

	int draw_plugin_output;

	int mark_segments;
	void mark_curve_segments ();

	int guides;
	void draw_guides ();

#ifdef __SVG__
	// svg
  void write_curve (multi_curve* crv, std::ofstream& svg, float w, float h, float t, float left, float top, box<float>& bb);
	void write_svg (float h, float t, const std::string& fn, float left, float top);
	void write_samples (std::ofstream& svg);
#endif

#ifdef __HPGL__
	// hpgl
	void write_curve (multi_curve* crv, std::ofstream& hpgl, float scale, float penmag);
	void write_hpgl (float scale = 5000, float penmag = 100);
#endif

  void attach_library (curve_library* lib);

  void enter ();
  void bg ();

	void set_curve_style (multi_curve* crv);
	void toggle_curve_style ();

  void apply_mocap ();
	void apply_mocap (mouse_macro& m, int dir = 1);

  int fft_enabled;

  int waved;
  int samples_enabled;
  float hz;
  int nperiods;
  int offset;
  curve_samples cs;
  void set_hz (float zh);
  void set_periods (int p);
  void toggle_waveform_samples_display ();
  void render_curve_samples ();

  std::vector<beat2value*> bv;

  int label_vertices;
  void toggle_vertex_labels ();

  int overlay;

  std::string next_cursor_mesg;

  void setup_tools_menu ();


  void set_rpm (float r);
  void rotate ();
  void scale (float sx, float sy); 

  void apply_plugin (plugin* p);

  int hlabel_only;

  int mkr[8];

	void calc_visual_params ();

	multi_curve mix;

	static help helptext;

	static color vtxlbl;

	int esc ();

  void drawerlay ();

  int lmb_clicked;


};


extern curve_picker_t curve_picker;
void show_curve_picker ();

#define CRVED uis.crved 

#endif
