/*
* countries.cc
* 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/
*/


#include "countries.h"
#include "vector2d.h"
#include "console.h"
#include "log.h"
#include <vector>
#include <fstream>
#include <algorithm>
using namespace std;


extern string user_data_dir;
extern string country_data_dir;

extern console cons;

bool area::operator< (const area& rhs) const {
 return num_vertices > rhs.num_vertices;
}

countries::countries () {
  name = "Countries";
	id = -1;
	p_cur_country = 0;
	area_id = 0;
	change_curve_name = 1;
}

countries::~countries () {
	widget_save ("d_countries", ctrls);
	save_params ();
}

void countries::load_params () {
  ifstream f (make_fname().c_str(), ios::in);
	string ignore;
	float step;
	f >> ignore >> id >> ignore >> area_id >> ignore >> step;
	pt.step.set_value (step);
	load_country (index[id]);
}

void countries::save_params () {
  ofstream f (make_fname().c_str(), ios::out);
	if (f) {
		f << "id " << id << endl;
		f << "area_id " << area_id << endl;
		f << "step " << int(pt.step.f_value) << endl;
	}
}

void countries::load_index () {
	string fname (country_data_dir + "index");
	ifstream f (fname.c_str(), ios::in);
	if (!f) {
		dlog << "couldnt read from : " << fname << endl;
		return;
	}
	f >> num_countries;
  index.resize (num_countries);
	for (int i = 0; i < num_countries; ++i) {
		f >> fname;
    index[i] = fname;
	}
	sort (index.begin (), index.end());
}


void countries::setup () {

	plugin::setup ();

	load_index ();

  widget* _ctrls [] = {&ol_country, &ol_area,  &lf_search, &pt.step, &pt.start, &pt.end, &close};
  for (int i = 0; i < 7; ++i) {
    ctrls.push_back (_ctrls[i]); 
  }

  num_ctrls = ctrls.size ();

  //for (int i = 0; i < num_ctrls; ++i) ctrls[i]->set_moveable(1);

	lf_search.set_text ("Country?");
	lf_search.set_listener (this);
	lf_search.fld.expr = 0;

	ol_country.set_text ("Country = ");
	ol_country.set_listener (this);
	ol_country.set_click_repeat (1);

	ol_area.set_listener (this);
	ol_area.set_click_repeat (1);
	ol_area.set_text ("Area = ");

  pt.start.set ("Start", 1, 1, MILLION, this, 0);
  pt.end.set ("End", 1, 1, MILLION, this, 0);
  pt.step.set ("Step", 1, 1, MILLION, this, 0);

  close.set_text ("Close");
  close.set_listener (&cll);

	widget_load ("d_countries", ctrls);

	load_params ();
	lf_search.fld.set_text (index[id]);

}

void countries::render () {
	if (p_cur_country) {
		points.clear ();
		area& a0 = p_cur_country->areas[area_id];
    int start = pt.start.f_value;
		float a0x = a0.x[start], a0y = a0.y[start];
		point<float> pa0 (a0x, a0y);
		points.push_back (pa0);
		for (int i = start + 1, j = pt.end.f_value, di = pt.step.f_value; i < j; i += di) points.push_back (point<float>(a0.x[i], a0.y[i]));
		if (close.state || (points.size () == 1)) points.push_back (pa0);
    gen_pts ();
  	ss.str("");
  	ss << p_cur_country->name;
	}
}

country* countries::load_country (const string& which) {
	country& c = the_countries [which];
	if (c.num_areas ==  0) {
		string fname (country_data_dir + which);
		ifstream f (fname.c_str(), ios::in);
		if (!f) {
			dlog << "couldnt load from : " << fname << endl;
			return 0;
		}
		c.name = which;
		string ignore;
		while (!f.eof()) {
			f >> ignore >> c.num_areas;
			for (int i = 0; i < c.num_areas; ++i) {
				c.areas.push_back (area());
				area& ai = c.areas[i];
				f >> ignore >> ai.num_vertices;
				float l, b, r, t; f >> ignore >> l >> b >> r >> t;
				ai.bbox (l, b, r, t);

        /*dlog << "name = " << c.name << " ratio = " << ai.bbox.width * 1.0 / ai.bbox.height << endl;
        float fac = ai.bbox.width * 1.0 / ai.bbox.height - 1.0;*/

        int& q = ai.num_vertices;
        int n1 = q + 1;
        ai.x.resize (n1);
        ai.y.resize (n1);
				for (int p = 0; p < q; ++p) f >> ai.x[p] >> ai.y[p];
        ai.x[q] = ai.x[0];
        ai.y[q] = ai.y[0];
        ++q;
			}
		}
	}
	p_cur_country = &c;
	set_country (which);
	return &c;
}

void countries::picked (label& lbl, int dir) {
	if (&lbl == &ol_country.option) {
		id += dir;
		if (id < 0) id = num_countries - 1; else if (id >= num_countries) id = 0;
		string name (index[id]);
		load_country (name);
	} else if (&lbl == &ol_area.option) {
		if (p_cur_country) {
			area_id += dir;
			render_area ();
		}
	}
}

void countries::changed (field& f) {
	if (&f == &lf_search.fld) {
		string name (f.text); 
    for (int i = 0, j = name.size (); i < j; ++i) if (name[i] == ' ') name[i]= '_';
		int nid = find_id (name);
		if (nid == -1) {
			cons << RED << "Couldnt find " << name << eol; 
			if (name == "") f.set_text (index[id]);
		} else {
			id = nid;
			load_country (name);
		}
	} else {
		render ();
		if (cb_auto_apply.state) clicked (b_apply);
	}
}

void countries::render_area () {
	if (area_id < 0) area_id = p_cur_country->num_areas - 1; else if (area_id >= p_cur_country->num_areas) area_id = 0;
	stringstream ss; ss << "Area " << (area_id+1) << " of " << p_cur_country->num_areas;
	ol_area.set_text (ss.str());

  int n_1 = p_cur_country->areas[area_id].num_vertices - 1;
  pt.start.set_limits (0, n_1);
  pt.end.set_limits (0, n_1);
  pt.start.set_value (0);
  pt.end.set_value (n_1);

	render ();
	if (cb_auto_apply.state) clicked (b_apply);
}

void countries::set_country (const string& name) {
	ol_country.set_text (name);
	lf_search.set_text (name);
	area_id = 0;
	render_area ();
}

int countries::find_id (const string& name) {
	for (int i = 0, j = index.size (); i < j; ++i) if (index[i] == name) return i;
	return -1;
}

void countries::closer::changed (checkbutton& cb) {
  extern countries countries_;
  countries_.do_render ();
}

void area::calc_bbox () {
	if (num_vertices) {
		float xmin = x[0], ymin = y[0];
    float xmax = xmin, ymax = ymin;
		for (int i = 1, j = num_vertices; i < j; ++i) {
			float xi = x[i], yi = y[i];
			if (xi < xmin) xmin = xi; else if (xi > xmax) xmax = xi;
			if (yi < ymin) ymin = yi; else if (yi > ymax) ymax = yi;
		}
		bbox (xmin, ymin, xmax, ymax);
	}
}

void area::normalise () {
	float aspect_ratio = bbox.width * 1. / bbox.height;
	float xw = aspect_ratio * 2.0f, xwh = xw / 2.0f;
	for (int i = 0, j = num_vertices; i < j; ++i) {
		float xi = x[i], yi = y[i];
		float fx = (xi - bbox.left) * bbox.width_1;
		float fy = (yi - bbox.bottom) * bbox.height_1;
		float xj = -xwh + fx * xw; 
		float yj = -1 + fy * 2.0f;
		x[i] = xj;
		y[i] = yj;
	}
	bbox (-xwh, -1.0f, xwh, 1.0f);
}
