/*
* item_list.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 "item_list.h"
#include "font.h"
#include "input.h"
#include "utils.h"
#include "tokenizer.h"

#include <sstream>
using namespace std;

extern int mousex, mouseyy;
extern char BUFFER [];
extern int line_height;

item_list::item_list () {
	cur = hov = -1;
	last = nsel = 0;
	sel_lis = 0; // selection
	set_listener (this); // click
}

void item_list::calc () {
	n = items.size ();
	n_1 = n - 1;
	nums.resize (n);
	for (int i = 0; i < n; ++i) {
		sprintf (BUFFER, " [%d]", i+1);
		nums[i] = BUFFER;
	}
}
void item_list::add (const string& item) {
  items.push_back ( itemt (item) );
	calc ();
}


void item_list::clear () {
  cur = hov = -1;
  last = nsel = 0;
  items.clear ();
}

void item_list::remove (int i) {
  nsel -= items[i].sel;
  items.erase (items.begin () + i);
	calc ();
	clamp (0, last, n_1);
}

void item_list::insert (int i, const string& t) {
	if (n && i < n) {
    items.insert (items.begin() + i, itemt(t));
		calc ();
	}
}

void item_list::set_pos (int x, int y) {
  posx = x;
  posy = y;
  extents.left = extents.right = posx;
  extents.top = extents.bottom = posy;
  for (int i = 0; i < n; ++i) extents.right = max (extents.right, posx + get_char_width (items[i].name));
  extents.bottom -= (n * line_height);
	yt = extents.top - line_height;
  extents.calc ();
}

void item_list::draw () {
  int x = extents.left, y = yt, xp = 0;
  for (int i = 0; i < n; ++i) {
    if (i == hov) glColor3f (0, 1, 0); 
		else if (items[i].sel) glColor3f (0, 1, 1);
		else glColor3f (clr.r, clr.g, clr.b);
    xp = draw_string (items[i].name, x, y);
		draw_string (nums[i], xp, y);
    y -= line_height;
  }
}

void item_list::select (int w) {
	for (int i = 0; i < n; ++i) items[i].sel = w;
	nsel = n * w;
	if (sel_lis) sel_lis->selected (*this, get_first ());
}

void item_list::select (int i, int j) {
	if (i > j) std::swap (i, j);
	nsel -= items[i].sel;
	for (int k = i, l = j + 1; k < l; ++k) items[k].sel = 1;
	last = j;
	nsel += (j - i + 1);
}

void item_list::invert_select () {
	for (int i = 0; i < n; ++i) {
		int& si = items[i].sel;
		nsel -= si;
		si = !si;
		nsel += si;
	}
	if (sel_lis) sel_lis->selected (*this, get_first ());
}

int item_list::select_these (tokenizer& tz) {
	int m; tz >> m;
	if (m) {
		select (0);
		for (int i = 0, j = 0; i < m; ++i) {
			tz >> j;
			items[j].sel = 1;
			++nsel;
		}
		if (sel_lis) sel_lis->selected (*this, get_first ());
	}
	return m;
}

int item_list::handle_input () {
	int r = button::handle_input ();
	if (hover && n) {
    hov = -1;
    int m = (mouseyy - extents.bottom) / line_height;
    if (m > -1 && m < n) hov = n_1 - m;
	}
	return r;
}

void item_list::clicked (button& b) {
	if (hov != -1) {
		cur = hov;
		if (SHIFT) 
			select (last, cur);
		else {
			int& shi = items[cur].sel;
			nsel -= shi;
			shi = !shi;
			nsel += shi;
			last = cur;
		}
		if (sel_lis) sel_lis->selected (*this, cur);
	}
}

string item_list::get_selected () {
	std::stringstream ss;
	for (int i = 0; i < n; ++i) if (items[i].sel) ss << i << spc;
	return ss.str ();
}

int item_list::get_first () {
	for (int i = 0; i < n; ++i) if (items[i].sel) return i;
	return -1;
}
