/*
 *  acm : an aerial combat simulator for X
 *  Copyright (C) 1991,1992,1997  Riley Rainey
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; version 2 dated June, 1991.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program;  if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA.
 */

#include "../V/Vlib.h"
#include "pm.h"
#include "hud.h"
#include "instruments.h"
#include "prompt.h"

#define windows_IMPORT
#include "windows.h"

#define WIN_MIN_WIDTH 150
#define WIN_MIN_HEIGHT 150

#define HDG_LENGTH      (6*33+1)
#define HDG_MIN_INTERVAL	500
#define HDG_MIN_SIZE		5
#define HDG_MAJ_INTERVAL	1000
#define HDG_MAJ_SIZE		10
#define HDG_DIVISOR		1000.0
#define HDG_FORMAT		"%2.2g"

#define VEL_LENGTH		ALT_LENGTH
#define VEL_ORIENT		0
#define VEL_SCALE		(153.0 / (double) VEL_LENGTH)
#define VEL_INDEX_SIZE		32
#define VEL_MIN_INTERVAL	10
#define VEL_MIN_SIZE		9
#define VEL_MAJ_INTERVAL	50
#define VEL_MAJ_SIZE		17
#define VEL_DIVISOR		10.0
#define VEL_FORMAT		"%3.3g"

#define ALT_LENGTH		219
#define ALT_ORIENT		scale_ORIENT_RIGHT
#define ALT_SCALE		(1530.0 / (double) ALT_LENGTH)
#define ALT_INDEX_SIZE		32
#define ALT_MIN_INTERVAL	100
#define ALT_MIN_SIZE		9
#define ALT_MAJ_INTERVAL	500
#define ALT_MAJ_SIZE		17
#define ALT_DIVISOR		1000.0
#define ALT_FORMAT		"%4.3g"

#define HUD_OFFSET      units_DEGtoRAD(3.0)
/*
	HUD drawing angular offset vs. nose pointer. Real HUD devices offer
	a quite small angle of view, limited to about +/-6 DEG. This offset
	angle allows to organize the drawing around a point that is so many
	DEG below the nose.  Because the AoA is commonly between 3 and 4
	DEG, looking at the center of the HUD drawing the pilot will see
	the point toward he is actually flying or it is aiming to.
*/

static int mymin(int a, int b){ if(a<=b) return a; else return b; }


void
windows_set_layout(craft * c, viewer * u, int width, int height,
	_BOOL hud_mode)
{
	double    xres, yres, eye, xscale, yscale;
	int       w, xo, yo, stripe_height;
	Alib_Rect      view;


	void set_slot(Alib_Rect *r, int row, int col)
	{
		Alib_setRect(r, xo + col * w, yo - row * w - w,
			xo + col * w + w, yo - row * w);
	}


	if( width < WIN_MIN_WIDTH )  width = WIN_MIN_WIDTH;
	if( height < WIN_MIN_HEIGHT )  height = WIN_MIN_HEIGHT;


	if( hud_mode ){
		/* HUD mode: at least 2/3 of the vertical space to the cockpit view */
		w = mymin(width / 5, height / 3);
		stripe_height = 0;
		Alib_setRect(&view, 0, 0, width, height - w);
		Alib_setRect(&u->stripe, 0, 0, 0, 0);
	} else {
		/* Classic instruments: at least 1/3 of the vertical space to the
		   cockpit view. The stripe is 1/8 of the slot. */
		w = mymin(width / 5, (int) (height * 2.0/3.0 / (1.0 + 1.0 + 1.0/8.0)));
		stripe_height = w/8;
		Alib_setRect(&view, 0, 0, width, height - stripe_height - w - w);
		Alib_setRect(&u->stripe, 0, view.b.y, width, height - 2*w);
	}

	/*
		Open the Viewport if required, but set dummy parameters.

		FIXME: the Viewport should be opened or resized only after all
		the layout has been calculated; I open it here just because I
		need the screen resolution. The screen resolution is a property
		of the window, so it should stay in Alib since it may be useful
		for 2D graphics too.
	*/

	if( u->v == NULL ){
		Alib_Rect r;
		Alib_setRect(&r, 0, 0, width, height);
		u->v = Vlib_new(u->gui, u->w, &r, &(Alib_Point){0,0}, 1.0);
	}

	xres = u->v->xres / 100;  /* horiz. screen resolution (pixels/cm) */
	yres = u->v->yres / 100;  /* vert. screen resolution (pixels/cm) */

	/* Apply zoom factor to actual eye distance from screen */

	eye = eye_to_screen_cm * u->zoom/100.0;

	/*
		Resize AWindow. This must be done before resizing Viewport because
		this latter compute its rect field as intersection with AWindow.
	*/

	Alib_resize(u->w, width, height);

	/*
		Resize Viewport
	*/

	{
		double h;
		Alib_Point focus;

		/* Distance of the focus projection from bottom border (pixels): */
		h = yres * eye * tan(downward_view_angle_rad);

		/*
			For higher zoom factors the pilot may end up looking the
			terrain rather than the target craft. Correct:
		*/

		if( u->zoom > 200 && view.b.y - h < 0.0 )
			h = view.b.y;

		/* Nose pointer position (pixel): */
		Alib_setPoint(&focus, RectMiddleX(view), view.b.y - h);

		/*
			Organize HUD drawing center HUD_OFFSET DEG below the horizon:
		*/
		u->hud_yCenter = focus.y + yres * eye * tan(HUD_OFFSET);

		VResizeViewport(u->v, &view, &focus, 0.01*eye);
	}

	/*
		(xo,yo) is the left-bottom corner of the panel:
	*/
	xo = (width - 5 * w) / 2;
	yo = height;

	set_slot(&u->lights, 0, 0);
	set_slot(&u->tuner, 0, 1);
	set_slot(&u->indicator, 0, 2);
	set_slot(&u->gear, 0, 3);
	set_slot(&u->engine, 0, 4);
	set_slot(&u->turn, 1, 0);
	set_slot(&u->anemometer, 1, 1);
	set_slot(&u->attitude, 1, 2);
	set_slot(&u->altimeter, 1, 3);
	set_slot(&u->vsi, 1, 4);

	/*
		To save space, the radar altimeter occupies the right part of the
		lights slot. So, reduce lights slot width:
	*/
	{
		int h;

		h = (int) (0.2 * w);
		u->radar_altimeter = u->lights;
		u->radar_altimeter.a.x = u->lights.b.x - h;
		u->lights.b.x -= h;
	}

	/*
		Scale factor for HUD graphics.

		FIXME. The magic numeric factor below follows from an
		"experimental" measurement and it accounts for the fixed layout
		under which the screen was originally designed. A more elegant,
		deterministic formula would require to eliminate all the fixed
		constants that appear in the renderer and HUD modules.
	*/
	xscale = 0.5 * 1.53e-3 * eye * xres;
	yscale = 0.5 * 1.53e-3 * eye * yres;

	u->xscaleFactor = xscale;
	u->yscaleFactor = yscale;

	/*
		Fill in the scale structures for the airspeed/altitude HUD scales.
	*/

	u->altScale.xorg = u->v->focus.x + (int) (xscale * 160);
	u->altScale.length = (int) (ALT_LENGTH * yscale);
	u->altScale.yorg = u->hud_yCenter + (u->altScale.length / 2);
	u->altScale.orientation = ALT_ORIENT;
	u->altScale.scale = ALT_SCALE / yscale;
	u->altScale.minorInterval = ALT_MIN_INTERVAL;
	u->altScale.minorSize = (int) (ALT_MIN_SIZE * yscale);
	u->altScale.majorInterval = ALT_MAJ_INTERVAL;
	u->altScale.majorSize = (int) (ALT_MAJ_SIZE * yscale);
	u->altScale.indexSize = (int) (ALT_INDEX_SIZE * xscale);
	u->altScale.divisor = ALT_DIVISOR;
	u->altScale.format = ALT_FORMAT;
	u->altScale.pixel = HUDColor;
	u->altScale.fontSize = (int) (14.0 * xscale + 0.5);

	u->velScale.xorg = u->v->focus.x - (int) (xscale * 160);
	u->velScale.length = (int) (VEL_LENGTH * yscale);
	u->velScale.yorg = u->hud_yCenter + (u->velScale.length / 2);
	u->velScale.orientation = VEL_ORIENT;
	u->velScale.scale = VEL_SCALE / yscale;
	u->velScale.minorInterval = VEL_MIN_INTERVAL;
	u->velScale.minorSize = (int) (VEL_MIN_SIZE * yscale);
	u->velScale.majorInterval = VEL_MAJ_INTERVAL;
	u->velScale.majorSize = (int) (VEL_MAJ_SIZE * yscale);
	u->velScale.indexSize = (int) (VEL_INDEX_SIZE * xscale);
	u->velScale.divisor = VEL_DIVISOR;
	u->velScale.format = VEL_FORMAT;
	u->velScale.pixel = HUDColor;
	u->velScale.fontSize = (int) (14.0 * xscale + 0.5);

	/* Compass scale in HUD: */
	u->hdgScale.xorg = u->v->focus.x - (int) (xscale * HDG_LENGTH / 2.0 + 0.5);
	u->hdgScale.yorg = u->hud_yCenter - u->velScale.length / 2 - 130.0 * yscale;
	u->hdgScale.length = (int) (HDG_LENGTH * xscale);
	u->hdgScale.orientation = scale_ORIENT_LEFT;    /* really orient TOP */
	u->hdgScale.scale = (2727.0 / (double) HDG_LENGTH) / xscale;
	u->hdgScale.minorInterval = HDG_MIN_INTERVAL;
	u->hdgScale.minorSize = (int) (HDG_MIN_SIZE * xscale);
	u->hdgScale.majorInterval = HDG_MAJ_INTERVAL;
	u->hdgScale.majorSize = (int) (HDG_MAJ_SIZE * xscale);
	u->hdgScale.indexSize = (int) (10 * yscale);
	u->hdgScale.divisor = HDG_DIVISOR;
	u->hdgScale.format = HDG_FORMAT;
	u->hdgScale.pixel = HUDColor;
	u->hdgScale.fontSize = (int) (14.0 * xscale + 0.5);

	/*
		Clean instruments panel area
	*/

	{
		Alib_Rect r;

		Alib_setRect(&r, 0, view.b.y, width, height);
		Alib_setClipRect(u->w, &r);
		Alib_fillRect(u->w, &r, panelBackgroundColor);
	}

	/*
		Disable/Enable instruments:
	*/
	if( hud_mode ){
		instruments_disable(u);
		hud_enable(u);
	} else {
		hud_disable(u);
		instruments_enable(u);
	}

	u->hud_mode = hud_mode;
}


static void windows_setZoom(viewer *u, int zoom)
{
	if( 91 <= zoom && zoom <= 109 )
		zoom = 100;
	else if( zoom < 10 )
		zoom = 10;
	else if( zoom > 400 )
		zoom = 400;
	if( zoom != u->zoom ){
		u->zoom = zoom;
		windows_set_layout(u->c, u, gui_getWidth(u->gui), gui_getHeight(u->gui), u->hud_mode);
	}
	char s[20];
	sprintf(s, "%d%%", u->zoom);
	prompt_viewer_print(u, s);
}


void windows_zoom_in(viewer *u)
{
	windows_setZoom(u, 12*u->zoom / 10);
}


void windows_zoom_out(viewer *u)
{
	windows_setZoom(u, 10*u->zoom / 12);
}
