/*
* rect.cc
* DIN Is Noise is copyright (c) 2006-2022 Jagannathan Sampath
* DIN Is Noise is released under GNU Public License 2.0
* For more information, please visit https://dinisnoise.org/
*/
#include "mondrian.h"
#include "container.h"
#include "console.h"
#include "utils.h"
#include <utility>
using namespace std;

rect::rect () {
	parent = child1 = child2 = 0; 
	total_slits = 0;
	for (int i = 0; i < 4; ++i) nslits[i] = 0;
	split = split::NONE;
	make_random_color ();
	++ref;
}

void rect::erase (ball* b) {::erase (balls, b);}

void rect::calc_intervals () {
  hint.first = extents.bottom;
  hint.second = extents.top;
  vint.first = extents.left;
  vint.second = extents.right;
}

void rect::get_vertical_interval (pair<float, float>& invl, rect* _root) {
	invl.first = 1.0f + (vint.first - _root->extents.left) * _root->extents.width_1;
	invl.second = 1.0f + (vint.second - _root->extents.left) * _root->extents.width_1;
}

void rect::get_horizontal_interval (pair<float, float>& invl, rect* _root) {
	invl.first = 1.0f + (hint.first - _root->extents.bottom) * _root->extents.height_1;
	invl.second = 1.0f + (hint.second - _root->extents.bottom) * _root->extents.height_1;
}

int rect::add_slit (slit* s, int e) {
	int result = 1;
	int& nse = nslits [e]; // number of slits on this edge
	// for all edges
	float lows [rect::nedges] = {extents.left, extents.bottom, extents.left, extents.bottom};
	float highs [rect::nedges] = {extents.right, extents.top, extents.right, extents.top};
	float low = lows[e];
	if (nse) { // slits already on this edge
		list<slit*>& ls = slits [e]; // slits of this edge
		for (slit_iterator i = ls.begin (), j = ls.end (); i != j; ++i) {
			slit* si = *i;
			if (s->mid < si->start) { 
				s->start = max (s->start, low);
				s->end = min (s->end, si->start);
				i = ls.insert (i, s); // inserts sorted

				slit_iterator ip (i); --ip; // slit b4 inserted slit
				slit_iterator in (i); ++in; // slit after inserted slit

				// handle animation of previous and next slits
				slit *ips = *ip, *ins = *in;
				if (ip != j && ips->fdr) ips->anim_end = min (ips->anim_end, s->start);
				if (in != j && ins->fdr) ins->anim_start = max (ins->anim_start, s->end);

				// handle edited slit 
				if (mondrian0.editing_slit) { 
					int hl = 0;
					slit* eds = mondrian0.slit_lip.slitt; // the edited slit
					if ((ip != j) && (*ip == eds)) { // edited slit is b4 inserted slit
						// slits editable high is inserted slits low
						mondrian0.slit_lip.set_high (s->start);
						hl = 1;
					} else if ((in != j) && (*in == eds)) { // slit after inserted slit is edited slit
						// slit's editable low is inserted slits high
						mondrian0.slit_lip.set_low (s->end);
						hl = 1;
					}
					if (hl && mondrian0.slit_lip.slitt->is_too_small()) mondrian0.remove_slit (mondrian0.slit_lip.slitt);
				}
				goto adder;
			}
			low = si->end;
		}

		// append slit
		// if last slit is currently edited slit, adjusts its high
		//
		slit* sl = ls.back ();
		if (sl == mondrian0.slit_lip.slitt) mondrian0.slit_lip.set_high (s->start);

	} /*else cons << console::cyan << "No slits on edge, adding first slit" << eol;*/

	// append slit
	s->start = max (s->start, low);
	s->end = min (s->end, highs[e]);
	slits[e].push_back (s);
	adder:
		s->anim_start = s->start;
		s->anim_end = s->end;
		++nse;
		++total_slits;
		/*cons << console::yellow << "Slit size = " << (s->end - s->start) << eol;
		cons << console::yellow << "Slits on edge = " << nse << eol;*/
		if (s->is_too_small()) result = 0; else s->calc_mid ();
	return result;
}

void rect::update_slits (int e, float minn, float maxx) {
	list<slit*>& ls = slits [e];
	for (slit_iterator i = ls.begin (), j = ls.end (); i != j;) {
		slit* si = *i;
		clamp (minn, si->start, maxx);
		clamp (minn, si->end, maxx);
		if (si->is_too_small()) {
			mondrian0.remove_slit (si);
			i = ls.begin ();
			j = ls.end ();
		} else {
			++i;
			si->calc_mid ();
		}
	}
}
