/*
* mouse_slider.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 "mouse_slider.h"
#include "console.h"
#include "viewwin.h"
#include "container.h"
#include "ui_list.h"

extern char BUFFER[];
extern void warp_mouse (int x, int y);
extern int line_height;

typedef std::list<mouse_slider_listener*>::iterator mouse_slider_listener_iterator;

mouse_slider_listener::mouse_slider_listener () {
  orient = Y;
  delta0 = 1.0;
  delta = 0.0;
  lim = vary = 0;
}

void mouse_slider_listener::togger (checkbutton* cb, const char* txt) {
  static const char* str[] = {"OFF", "ON"};
  if (cb) {
    cb->toggle ();
    cons << name << txt << str[cb->state] << eol;
  }
}

void mouse_slider_listener::togvary () {
  static const char* varyy = " varied change is ";
  togger (vary, varyy);
}

void mouse_slider_listener::toglim () {
  static const char* limm = " limit is ";
  togger (lim, limm);
}

mouse_slider::mouse_slider () {

	initx = inity = inityy = lowx = lowy = midx = midy = highx = highy = prevx = prevy = dx = dy = nmslx = nmsly = lmb_clicked = active = 0;

	int dirs [] = {arrow_button::left, arrow_button::right, arrow_button::down, arrow_button::up};
	arrow_button* abs [] = {&axl, &axr, &ayb, &ayt};
	for (int i = 0; i < 4; ++i) abs[i]->set (22, dirs[i], 0.5f, 0.5f, 0.5f); 

	sz = axl.size;
	sz_2 = sz / 2;
	szn = sz;
	szn_1 = szn + sz;

  shift = 0;

}

void mouse_slider::update_x_arrows () {
	int py = mouseyy - sz_2;
	axl.set_pos (mousex - szn_1, py);
	axr.set_pos (mousex + szn, py);
}

void mouse_slider::update_y_arrows () {
	int px = mousex - sz_2;
	ayb.set_pos (px, mouseyy - szn_1);
	ayt.set_pos (px, mouseyy + szn);
}

int mouse_slider::justx () {
	return (nmslx && CTRL);
}

int mouse_slider::justy () {
	return (nmsly && SHIFT);
}

void mouse_slider::draw () {

	glColor3f (0.5, 0.5, 0.75);
  glBegin (GL_LINES);
    glVertex2i (initx, inity);
    glVertex2i (mousex, mouseyy);
  glEnd ();

	/*pts[0]=initx; pts[1]=inity;
	pts[2]=mousex; pts[3]=mouseyy;
	glVertexPointer (2, GL_INT, 0, pts);
	glDrawArrays (GL_LINES, 0, 2);*/

  /*glEnable (GL_LINE_STIPPLE);
  glLineStipple (1, 0xa0b0);
  if (nmslx) {
    pts[0]=lowx; pts[1] = 0;
    pts[2]=lowx; pts[3] = view.ymax;
    pts[4]=highx; pts[5] = 0;
    pts[6]=highx; pts[7] = view.ymax;
    glDrawArrays (GL_LINES, 0, 4);
  }
  if (nmsly) {
    pts[0]=0; pts[1] = lowy;
    pts[2]=view.xmax; pts[3] = lowy;
    pts[4]=0;  pts[5] = highy;
    pts[6]=view.xmax; pts[7] = highy;
    glDrawArrays (GL_LINES, 0, 4);
  }
  glDisable (GL_LINE_STIPPLE);*/

	if (nmslx && !justy() ) {
		axl.draw ();
		axr.draw ();
    //printdx ();
	} 
	if (nmsly && !justx()) {
		ayb.draw ();
		ayt.draw ();
    //printdy ();
	}
}

/*void mouse_slider::printdx () {
  glColor3f (0, 1, 1);
	for (mouse_slider_listener_iterator i = mslx.begin (), j = mslx.end (); i != j; ++i) {
		mouse_slider_listener* mslx = *i;
    sprintf (BUFFER, "%0.3f", scale.value * mslx->delta0);
    draw_string (BUFFER, axr.extents.right + 5, axr.extents.midy);
  }
}

void mouse_slider::printdy () {
  glColor3f (0, 1, 1);
  int yt = ayt.extents.top, yb = ayb.extents.bottom - line_height;
  static const int dt = 3;
	for (mouse_slider_listener_iterator i = msly.begin (), j = msly.end (); i != j; ++i, yt += line_height, yb -= line_height) {
		mouse_slider_listener* msly = *i;
    double v = scale.value * msly->delta0;
    sprintf (BUFFER, "+%0.3f", v);
    draw_string (BUFFER, ayt.extents.midx + dt, ayt.extents.top);
    BUFFER[0]='-';
    draw_string (BUFFER, ayt.extents.midx + dt, ayb.extents.bottom - line_height);
  }
}*/

void mouse_slider::print (list<mouse_slider_listener*>& msll) {
	for (mouse_slider_listener_iterator i = msll.begin (), j = msll.end (); i != j; ++i) {
    mouse_slider_listener* msli = *i;
    cons << "Base = " << base << ", +- = " << (scale.value * msli->delta0) << eol;
  }
}

void mouse_slider::print (list<mouse_slider_listener*>& l1, list<mouse_slider_listener*>& l2) {
  print (l1);
  print (l2);
}

int mouse_slider::handle_input () {

  if (keypressed (SDLK_1)) {
    base = 10;
    scale.calcvalue (base, shift);
    print (mslx, msly);
  } else {
    for (Uint8 i = SDLK_2; i < SDLK_COLON; ++i) {
      if (keypressed(i)) {
        base = i - SDLK_0;
        scale.calcvalue (base, shift);
        print (mslx, msly);
        break;
      }
    }
  }

  if (keypressed (SDLK_q)) {
    scale /= base;
    --shift;
    print (mslx, msly);
  }
  else if (keypressed (SDLK_e)) {
    scale *= base;
    ++shift;
    print (mslx, msly);
  }


  if (keypressed (SDLK_0)) {
    if (nmslx) {
      for (mouse_slider_listener_iterator i = mslx.begin (), j = mslx.end (); i != j; ++i) {
        mouse_slider_listener* lxi = *i;
        lxi->toglim ();
      }
    }
    if (nmsly) {
      for (mouse_slider_listener_iterator i = msly.begin (), j = msly.end (); i != j; ++i) {
        mouse_slider_listener* lyi = *i;
        lyi->toglim ();
      }
    }
  } 
  else if (keypressed (SDLK_BACKQUOTE)) {
    if (nmslx) {
      for (mouse_slider_listener_iterator i = mslx.begin (), j = mslx.end (); i != j; ++i) {
        mouse_slider_listener* lxi = *i;
        lxi->togvary ();
      }
    }
    if (nmsly) {
      for (mouse_slider_listener_iterator i = msly.begin (), j = msly.end (); i != j; ++i) {
        mouse_slider_listener* lyi = *i;
        lyi->togvary ();
      }
    }
  } else if (keypressed (SDLK_SLASH)) {
    warp = !warp;
    if (warp) cons << GREEN << "Will warp mouse at boundary" << eol; else cons << RED << "Will not warp mouse at boundary" << eol;
  }

  if (warp) {

    if (mousex < lowx || mousex > highx) {
      warp_mouse (midx, mousey);
      initx = prevx = mousex;
    }

    if (mousey < lowy || mousey > highy) {
      warp_mouse (mousex, midy);
      inity = prevy = mouseyy; 
    }

  }

	int ua = 0;
	dx = dy = 0;
	if ( nmslx && !justy() ) {
    if (wheel) {
      mousex += wheel;
      warp_mouse (mousex, mousey);
    }
		dx = mousex - prevx;
		HOVER = 1;
		if (dx != 0) {
			for (mouse_slider_listener_iterator i = mslx.begin (), j = mslx.end (); i != j; ++i) (*i)->moused (dx, scale.value);
			ua = 1;
		}
	}

	if ( nmsly && !justx() ) {
    if (wheel) {
      mousey -= wheel;
      warp_mouse (mousex, mousey);
    }
		dy = mouseyy - prevy;
		HOVER = 1;
		if (dy != 0) {
			for (mouse_slider_listener_iterator i = msly.begin (), j = msly.end (); i != j; ++i) (*i)->moused (dy, scale.value);
			ua = 1;
		}
	}

	if (ua) {
		update_x_arrows ();
		update_y_arrows ();
	}

	prevx = mousex;
	prevy = mouseyy;

	if (is_lmb (this)) {
		lmb_clicked = 1;
	} else {
		if (lmb_clicked) deactivate ();
	}

	return 1;

}

void mouse_slider::add (mouse_slider_listener* msl) {
	if (msl->orient == mouse_slider_listener::X) { nmslx += push_back (mslx, msl); } else { nmsly += push_back (msly, msl); }
}

void mouse_slider::remove (mouse_slider_listener* msl) {
	if (msl->orient == mouse_slider_listener::X) { nmslx -= erase (mslx, msl); } else { nmsly -= erase (msly, msl); }
  if (nmslx || nmsly) ; else deactivate ();
}

int mouse_slider::activate (int shft, int scalestyle) {

	if (nmslx == 0 && nmsly == 0) return active;

	lowx = margin; highx = view.xmax - lowx;
	lowy = margin; highy = view.ymax - lowy;
	midx = view.xmax / 2;
	midy = view.ymax / 2;
	prevx = mousex;
	prevy = mouseyy;
	initx = mousex;
	inity = mouseyy;
	inityy = mousey;

	string xchange, ychange;
	if (nmslx) {
		for (mouse_slider_listener_iterator i = mslx.begin (), j = mslx.end (); i != j; ++i) {
			mouse_slider_listener* msl = *i;
			xchange = xchange + msl->name + ", ";
		}
		update_x_arrows ();
	}

	if (nmsly) {
		for (mouse_slider_listener_iterator i = msly.begin (), j = msly.end (); i != j; ++i) {
			mouse_slider_listener* msl = *i;
			ychange = ychange + msl->name + ", ";
		}
		update_y_arrows ();
	}

  if (!active) {
    uis.widgets_of [uis.current].push_back (&mouse_slider0);
	  active = 1; 
    lmb_clicked = 0;
    is_lmb.tie = this;
  }

	cons << GREEN << "Just move";
	if (xchange != "") cons << " Left/Right or Wheel to change " << xchange;
	if (ychange != "") cons << " Up/Down or Wheel to change " << ychange;
	cons << "ESC or Right click to stop" << eol;

  shift = shft;
  if (scalestyle == scalet::CHANGING) base = 10.0; else base = 1.0;
  scale.style = scalestyle;
  scale.calcvalue (base, shift);

	return active;

}


int mouse_slider::deactivate () {

  if (active) {
  
    if (nmslx) {
      for (mouse_slider_listener_iterator i = mslx.begin (), j = mslx.end (); i != j; ++i) (*i)->after_slide(); 
      mslx.clear (); 
      nmslx = 0;
    }

    if (nmsly) {
      for (mouse_slider_listener_iterator i = msly.begin (), j = msly.end (); i != j; ++i) (*i)->after_slide(); 
      msly.clear (); 
      nmsly = 0;
    }

    active = 0;
    erase (uis.widgets_of[uis.current], &mouse_slider0);
    warp_mouse (initx, inityy);
    lmb_clicked = 0;
    is_lmb.clear (this);

    extern void draw_slit_cutter (int);
    draw_slit_cutter (0);

    cons << RED << "Stopped mouse slider" << eol;
    return 1;

  }

  scale.style = 1;
  return 0;

}

void activate_mouse_slider (int shift, int scalestyle) {
	if (MENU.show) MENU.toggle ();
  mouse_slider0.activate (shift, scalestyle);
}

void cant_mouse_slide () {
	cons << RED << "Mouse slider is already active!" << eol;
}

mouse_slider::~mouse_slider () {}

void mouse_slider::scalet::calcvalue (double& b, int s) { 
  if (style == CHANGING) {
    value = 1.0;
    if (s != 0) value *= pow (b, s);
  } else {
    value = b;
  }
}

