/*
* rect.h 
* box in Mondrian
* DIN Is Noise is copyright (c) 2006-2024 Jagannathan Sampath
* For more information, please visit https://dinisnoise.org/
*/

#ifndef __rect__
#define __rect__

#include "box.h"
#include "random.h"
#include <list>
#include <string>

struct slit;
struct rect;
struct ball;

// for rect splits
//
struct split {

  // orientation of split
	enum {NONE, HORIZONTAL, VERTICAL, BOTH}; // BOTH used by auto splitter

  // where to split rect 
  enum {NOTES, ANYWHERE};


};

struct split_data;
struct split_listener {
	virtual void split_over (split_data& sd) = 0;
};

struct split_data {

  rect* R;
  std::list<rect*>* lr;

  int split_at;

	int split_type;
  split_listener* lis;

  int start, end;
  int nsplits;

  // for NxN
  float sz;
  int n;

	split_data (int s, int e, int sa, int st, rect* r, std::list<rect*>* l = 0, split_listener* ls = 0, 
                        float zs = 0, int _n = 0) {
    split_at = sa;
		start = s;
		end = e;
		split_type = st;
		R = r;
		lr = l;
		lis = ls;
    sz = zs;
    n = _n;
    nsplits = 0;

	}

};
typedef std::list<split_data>::iterator split_iterator;

struct rect { // box in which balls bounce

  static int ref; // to log if we deleted all rects on exit
	std::string id; // used when saving

  rect* parent; // box in which this box is found

	// each box can have two children
	// no child means its a leaf
	//
  rect* child1; // child 1 of this box
  rect* child2; // child 2 of this box
	inline int is_leaf () {return child1 == 0 && child2 == 0;}

  int split; // ? type is HORIZONTAL or VERTICAL

	// slits occur on edges of the leaves
	static const int nedges = 4;
	int total_slits;
	std::list<slit*> slits [nedges]; // all slits of this box 
	int nslits [nedges]; // slits per edge
	int add_slit (slit* s, int e); // add slit to edge
	void update_slits (int e, float minn, float maxx); // on edge edit 

  // visual
  box<float> extents;
  float r, g, b; // color
  void set_color (float _r, float _g, float _b) { r = _r; g = _g; b = _b;}

  static rnd<float> rd; // to make random box color
  inline void make_random_color () {r = rd (); g = rd (); b = rd ();}

  std::list<ball*> balls; // balls bouncing in this box 
  void erase (ball* b); // erase ball found in this box

	// pitch intervals spanned by this box
  std::pair<float, float> hint; // along horizontal
  std::pair<float, float> vint; // along vertical
  void calc_intervals ();
	void get_horizontal_interval (std::pair<float, float>& invl, rect* _root);
	void get_vertical_interval (std::pair<float, float>& invl, rect* _root);

  float get_area () {return extents.width * extents.height;}

	rect ();
  ~rect () {--ref;}

  enum {EARLIEST, RANDOM, BIGGEST, LATEST, BALLED}; // see mondrian::pick_leaf ()


};

struct box_from_disk_t { // for loading boxes from disk
	rect* R;
	std::string parent;
	std::string child1, child2;
	box_from_disk_t () { R = 0; }
};

struct finding { // used by mondrian::find
  rect* found; // found box
  rect* sibling; // its sibling
	void clear () {found = sibling = 0;}
  finding () {clear ();}
};


typedef std::list<box_from_disk_t>::iterator box_from_disk_iterator;
typedef std::list<rect*>::iterator box_iterator;

#endif
