#include <stdio.h>
#include MUT_H
#include MPH_H
#include "mbk_extern.h"
#include <math.h>
#include "g_visu.h"
#include "g_extern.c"

/* pan :
   move the window to another point. */
void
	pan(deltax, deltay)
LAMBDA deltax, deltay;
{
	xscreen += deltax;
	yscreen += deltay;
}

/* scroll :
   move the window in case of scrolling operation. */
void
	scroll(direction, move_size)
char direction;
LAMBDA move_size;
{
	switch (direction) {
		case NORTH:
			yscreen += move_size;
			break;
		case EAST:
			xscreen += move_size;
			break;
		case SOUTH:
			yscreen -= move_size;
			break;
		case WEST:
			xscreen -= move_size;
			break;
	}
}

/* zoom :
   decrease the visualised part of the circuit. */
int
	zoom(fact)
long fact;
{
	/* Backup values for a mooz event */
	zoomTrack.x = xscreen;
	zoomTrack.y = yscreen;
	zoomTrack.dx = dxscreen;
	zoomTrack.dy = dyscreen;
	zoomTrack.scale = scale;

	/* Calculate the new scale value */
	dxscreen -= fact * dxscreen / 20;
	scale = (float)dxWin / dxscreen;

	/* Cast to long avoids side effects for drawing */
	if (scale > 1)
		scale = (float)((long)scale);

	/* If no variation of scale (due to the cast) then it's increased */
	if (scale == zoomTrack.scale)
		scale++;

	/* If scale is too high then recovers old value and exit */
	if (scale > MAX_ZOOM) {
		scale = zoomTrack.scale;
		dxscreen = zoomTrack.dx;
		return 0;
	}

	/* Calculate the new window dimension */
	xscreen += zoomTrack.dx / 2;
	yscreen += dyscreen / 2;
	dyscreen = dyWin / scale;
	dxscreen = dxWin / scale;
	xscreen -= dxscreen / 2;
	yscreen -= dyscreen / 2;

	return 1;
}

/* loom :
   increase the visualised part of the circuit.
   externally called mooz now, because it's funnier! */
int
	loom(fact)
long fact;
{
	/* Backup values for an out event */
	zoomTrack.x = xscreen;
	zoomTrack.y = yscreen;
	zoomTrack.dx = dxscreen;
	zoomTrack.dy = dyscreen;
	zoomTrack.scale = scale;

	/* Calculate the new scale value */
	dxscreen += fact * dxscreen / 20;
	scale = (float)dxWin / dxscreen;

	/* Cast to long avoids side effects */
	if (scale > 1)
		scale = (float)((long)scale);

	/* If scale is too low then recovers old value and exit */
	if (scale < MIN_ZOOM) {
		scale = zoomTrack.scale;
		dxscreen = zoomTrack.dx;
		return 0;
	}

	/* Calculates the new window dimension */
	xscreen += zoomTrack.dx / 2;
	yscreen += dyscreen / 2;
	dyscreen = dyWin / scale;
	dxscreen = dxWin / scale;
	xscreen -= dxscreen / 2;
	yscreen -= dyscreen / 2;

	return 1;
}

/* fit :
   makes the whole circuit fit in the screen. */
#define min(x,y) ((x) < (y) ? (x) : (y))
#define max(x,y) ((x) > (y) ? (x) : (y))
void
	fit()
{
float scale1, scale2, scale3, scale4;
LAMBDA dx, dy;
extern phfig_list *xvisufig;
extern long xab2fig, yab2fig;
char buffer[200];

	/* Returns when no circuit is loaded */
	if (xvisufig == NULL) {
		scale = 1;
		dxscreen = dxWin / scale;
		dyscreen = dyWin / scale;
		xscreen = xvisu + (dxvisu - dxscreen) / 2;
		yscreen = yvisu + (dyvisu - dyscreen) / 2;
		return;
	}

	/* the origin of the screen becomes the origin of the bounding box */
	/* Two values of scale are calculated to take the min and fit correctly */
	scale1 = (float)dxWin / dxvisu;
	scale2 = (float)dyWin / dyvisu;
	scale3 = (float)dxWin / (xab2fig - xabfig);
	scale4 = (float)dyWin / (yab2fig - yabfig);
	/* The two values of scale are casted to avoid side effects on drawing */
	if (scale1 > 1)
		scale1 = (float)((long)scale1);
	if (scale2 > 1)
		scale2 = (float)((long)scale2);
	if (scale3 > 1)
		scale3 = (float)((long)scale3);
	if (scale4 > 1)
		scale4 = (float)((long)scale4);

	/* The lowest value is choosen */
	scale = min(scale1, min(scale2, min(scale3, scale4)));
	/* New window dimension */
	dxscreen = dxWin / scale;
	dyscreen = dyWin / scale;
	if (scale == scale1 || scale == scale2) {
		xscreen = xvisu + (dxvisu - dxscreen) / 2;
		yscreen = yvisu + (dyvisu - dyscreen) / 2;
	} else {
		xscreen = xabfig + (xab2fig - xabfig - dxscreen) / 2;
		yscreen = yabfig + (yab2fig - yabfig - dyscreen) / 2;
	}
}

/* resize :
   calculates the new dimension of window when resize event. */
void
	resize()
{
	/* New window dimension */
	dxscreen = dxWin / scale;
	dyscreen = dyWin / scale;
}

/* zoom_mouse :
   zoom upon a part of circuit delimited with the mouse. */
int
	zoom_mouse(x, y, dx, dy)
LAMBDA x, y, dx, dy;
{
float old_scale, scale2;

	/* Backup values for a loom_mouse event */
	zoomTrack.x = xscreen;
	zoomTrack.y = yscreen;
	zoomTrack.dx = dxscreen;
	zoomTrack.dy = dyscreen;
	zoomTrack.scale = scale;

	old_scale = scale;

	/* Two values of scale are calculated to take the min and fit correctly */
	scale = (float)dxWin / dx;
	scale2 = (float)dyWin / dy;

	/* The two values of scale are casted to avoid side effects on drawing */
	if (scale > 1)
		scale = (float)((long)scale);
	if (scale2 > 1)
		scale2 = (float)((long)scale2);

	/* The lowest value is choosen */
	if (scale > scale2)
		scale = scale2;

	/* exit if scale too high */
	if (scale > MAX_ZOOM) {
			scale = old_scale;
			return 0;
	}
	/* new window dimension */
	dxscreen = (long)(dxWin / scale);
	dyscreen = (long)(dyWin / scale);
	xscreen += x;
	yscreen += y;
	xy_move(xscreen + dxscreen / 2, yscreen + dyscreen / 2);
	return 1;
}

/* loom_mouse :
   restores old values of the globals variables. */
void
	loom_mouse()
{
	xscreen = zoomTrack.x;
	yscreen = zoomTrack.y;
	dxscreen = zoomTrack.dx;
	dyscreen = zoomTrack.dy;
	scale = zoomTrack.scale;
}

/* xy_move :
   makes the origine of the screen move to a new value. */
void
	xy_move(x, y)
LAMBDA x, y;
{
	xscreen = x - dxscreen / 2;
	yscreen = y - dyscreen / 2;
}
