/*
* mesh.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 __MESH
#define __MESH

#include <list>
#include <vector>
#include "box.h"
#include "alarm.h"

// add mesh drone over time
struct add_mesh_drone : alarm_t {
  int i, j;
  int p, drop;
  void reset () {
    i = j = p = drop = 0;
    stop ();
  }
  add_mesh_drone () { reset (); }
};

struct drone;
struct mesh_data;

struct orderer_t {
	virtual void operator () (std::vector<int>& order, mesh_data* md = 0) = 0;
};

struct ascending_rows_orderer : orderer_t {
	void operator () (std::vector<int>& order, mesh_data* md = 0);
};

struct ascending_cols_orderer : orderer_t {
	void operator () (std::vector<int>& order, mesh_data* md = 0);
};

struct descending_rows_orderer : orderer_t {
	void operator () (std::vector<int>& order, mesh_data* md = 0);
};

struct descending_cols_orderer : orderer_t {
	void operator () (std::vector<int>& order, mesh_data* md = 0);
};

struct random_orderer : orderer_t {
	void operator () (std::vector<int>& order, mesh_data* md = 0);
};

struct dist_id {
	double d2;
	int id;
	dist_id (double _d2=0, int _id=0) : d2(_d2), id(_id) {}
};

struct comp_asc {
	bool operator() (dist_id a, dist_id b) {return a.d2 < b.d2;}
};
struct comp_des {
	bool operator() (dist_id a, dist_id b) { return a.d2 > b.d2;}
};

struct proximity_orderer : orderer_t {

	static int ROW, COL;

	enum {NEAREST, FARTHEST};
	int sort_opt;
	comp_asc asc;
	comp_des desc;

	std::vector<dist_id> v_dist_id;

	proximity_orderer (int so = NEAREST);
	void get_xy (float& x, float&y, int p, int q, mesh_data* md);
	void operator() (std::vector<int>& order, mesh_data* md = 0);

};

struct mesh_data {

  int mesh;
  int rows, cols;
  int rowcol;
  float row, col;
  float* meshp; 
	int n_meshp;

	int drone_pend;
	int drones_per_pend;
	int apply_to_am_bpm, apply_to_fm_bpm;

	std::vector<drone*> meshd;

	std::vector<int> order;
	orderer_t* orderer;
	void order_order ();

	mesh_data ();
	~mesh_data ();

	void set_mesh (int m, int r, int c);
	void gen_mesh_pts (const box<float>& region);
	void clear ();

};

struct poly {
  drone* drones[4];
  poly (drone* d0, drone* d1, drone* d2, drone* d3) { drones[0] = d0; drones[1] = d1; drones[2] = d2; drones[3] = d3;}
};

struct mesh {

  static int* gl_pts;
  static float* clr;
  static int n_glpts;

  int num_polys;
  std::list<poly> polys;
  void add_poly (drone* d0, drone* d1, drone* d2, drone* d3);
  void remove_poly (drone* pd);

  float r, g, b;
  void draw ();

  mesh ();
  static void destroy ();
  
};

typedef std::list<poly>::iterator poly_iterator;

#endif
