/*
* viewwin.cc
* DIN Is Noise is copyright (c) 2006-2022 Jagannathan Sampath
* For more information, please visit https://dinisnoise.org/
*/


#include "dingl.h"
#include "viewwin.h"
#include "main.h"
#include "log.h"

#include <iostream>
using namespace std;

viewport::viewport () {
  width = height = 0;
	width_change = height_change = -1;
  xmax = ymax = 0;
  xmax_1 = ymax_1 = 0;
}

viewport::~viewport () {
	dlog << "--- destroyed viewport: " << width << " x " << height << " ---" << endl;
}

void viewport::operator() (int w, int h) {
  if (w != width || h != height) {
    calc (w, h);
  }
}

void viewport::calc (int w, int h) {
	if (width != 0) width_change = w * 1.0f / width; else width_change = -1;
	if (height != 0) height_change = h * 1.0f / height; else height_change = -1;
  width = w;
  height = h;
  xmax = width - 1;
  ymax = height - 1;
  xmax_1 = 1.0f / xmax;
  ymax_1 = 1.0f / ymax;
	midx = width / 2;
	midy = height / 2;
  handle_factor = handle_radius * 1.0f / width;
}

bool viewport::inside (int x, int y) {
  bool xi = (x >= 0) && (x <= xmax);
  bool yi = (y >= 0) && (y <= ymax);
  return (xi && yi);
}

void window::calc_panxy () {
  pan_x = PAN_AMOUNT * width;
  pan_y = PAN_AMOUNT * height;
}

void window::calc_handle_radius () {
  handle_radius = viewport::handle_factor * width;
  handle_radius2 = handle_radius * handle_radius;
  sus_handle_radius = 2 * handle_radius;
}

window::window () : box<float>() {
  width_1 = height_1 = 0;
  aspect_ratio = 0;
}

window::window (float l, float b, float r, float t) {
  set (l, b, r, t);
}

void window::set (float l, float b, float r, float t) {
  operator() (l, b, r, t);
  aspect_ratio = width * height_1;
  calc_panxy ();
  calc_viewwin ();
  calc_handle_radius ();
  window::calc_repeats ();
}

void window::get (float& l, float& b, float& r, float& t) {
  l = left;
  b = bottom;
  r = right;
  t = top;
}

void window::panx (int dir) {
  float dpan = pan_x * dir;
  left = left + dpan;
  right = left + width;
  mousex += dpan;
}

void window::pany (int dir) {
  float dpan = pan_y * dir;
  bottom = bottom + pan_y * dir;
  top = bottom + height;
  mousey += dpan;
}

void window::zoom (int dir) {
  float dw = ZOOM_AMOUNT * width * dir, dh = dw / aspect_ratio, dw2 = dw / 2, dh2 = dh / 2;
  float l = left - dw2;
  float r = right + dw2;
  float b = bottom - dh2;
  float t = top + dh2;
  float w = r - l, h = t - b;
  if ((w > 0) && (h > 0)) set (l, b, r, t);
}

void window::locate_mouse () {
  extern viewport view;
  extern int mousex, mousey;
  view2win (mousex, mousey, window::mousex, window::mousey, view, *this);
  prev_mousex = mousex;
  prev_mousey = mousey;
}

void window::update_mouse () {
  extern int mousex, mousey;
  mousex_prev = window::mousex;
  mousey_prev = window::mousey;
  window::mousex += (mousex - prev_mousex) * vwx;
  window::mousey -= (mousey - prev_mousey) * vwy;
  prev_mousex = mousex;
  prev_mousey = mousey;
}

int window::diff_mouse (float& dx, float& dy) {
	dx = mousex - mousex_prev;
	dy = mousey - mousey_prev;
	if (dx || dy) return 1; else return 0;
}

void window::calc_viewwin () {
  extern viewport view;
  vwx = width / view.xmax;
  vwy = height / view.ymax;
  locate_mouse ();
}

void window::calc_repeats () {
  if (PAN_RATE > 0) PAN_REPEAT = 1. / PAN_RATE;
  if (ZOOM_RATE > 0) ZOOM_REPEAT = 1. / ZOOM_RATE;
}

void window::calc () {
  box<float>::calc ();
  calc_repeats ();
  calc_panxy ();
  calc_viewwin ();
  calc_handle_radius ();
}

void view2win (int vx, int vy, float& wx, float& wy, viewport& view, window& win) {
  float xr = vx * view.xmax_1;
  float yr = 1 - vy * view.ymax_1;
  wx = win.left + xr * win.width;
  wy = win.bottom + yr * win.height;
}

void win2view (float wx, float wy, int& vx, int& vy, window& win, viewport& view) {
  float xr = (wx - win.left) * win.width_1;
  float yr = (wy - win.bottom) * win.height_1;
  vx = (int) (xr * view.xmax + 0.5);
  vy = (int) (yr * view.ymax + 0.5);
}


