/*
 * whistory.c -- Move list window for WinBoard by F. Gracia
 * $Id$
 *
 * Copyright 2005 Free Software Foundation, Inc.
 *
 * ------------------------------------------------------------------------
 * 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; either version 2 of the License, or
 * (at your option) any later version.
 *
 * 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.
 * ------------------------------------------------------------------------
 */
//
	//	La versión original de Wilkin Ng incluía los comentarios
	// a las jugadas en el presente listado (lo que parece absurdo,
	// pues esta función ya se realiza bien aparte), tenía unos
	// botones de selección en el recuadro, que también me parecen
	// inútiles o contraproducentes, y, por último, tenía varios
	// gazapos, carencias e insuficiencias.
	// El uso continuo de 'static' me ha dado muchos
	// problemas al hacer llamadas desde otros ficheros, pero ya
	// está resuelto (basta con quitar 'static').
//

#include "config.h"

#include <windows.h> /* required for all Windows applications */
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <io.h>
#include <fcntl.h>
#include <math.h>
#include <commdlg.h>
#include <dlgs.h>

#include "common.h"
#include "winboard.h"
#include "frontend.h"
#include "backend.h"
/* #include "analyst.h" */
#include "whistory.h"

/* Module globals */
int historyX, historyY, historyW, historyH;

//

HWND historyDialog = NULL;	// identificador de la propia caja
HMENU hMenu;
BOOLEAN walkingEnabled = FALSE;	// recorrido de jugadas
extern BOOLEAN gameTruncated;		// indicador de truncamiento

//

/* Imports from winboard.c */
extern HINSTANCE hInst;
extern HWND hwndMain;
void HistoryPopDown P((void));

// #define HISTORY_TIMER_ID 80


// extern char * commentList[];

/*
// Llevada a 'whistory.h'

struct History
{
  HWND dialog;		// asidero del recuadro de jugadas
  char up;			// 
  char moveblack;
  unsigned long flags[MAX_MOVES];
  int  idletimer;

	// última línea añadida (número de jugada completa)
	// empezando a contar desde 1
  int lastline;
  int lastselected;
  int lastmove;	// última semijugada presentada (contada desde 1)
  char last_has_tactic;
  char last_has_mate;

  int firstM;// necessary?
  int currentM;
  int process_click;
} listOfMoves = {0};

*/

// sartas de las jugadas presentadas en la lista,
// pero en versión internacional (antes de ser traducidas)
// char historyMoves[MAX_MOVES][2 * MOVE_LEN];

History listOfMoves = {0};

static int 
FlagB(int line)
{
	return listOfMoves.flags[line] & 0x80000000;
}

static int 
FlagW(int line)
{
   return listOfMoves.flags[line] & 0x40000000;
}

/*
static int 
FlagComment(int line)
{
   return listOfMoves.flags[line] & 0x20000000;
}
*/

// registro del número de la última jugada
// contenida en la línea 'line'
static int 
FlagMoveNum(int line)
{
   return listOfMoves.flags[line] & 0x0000ffff;
}

// registro de que la línea tiene una jugada completa
static void 
SetBWFlag(int line)
{
   listOfMoves.flags[line] &= 0x3fffffff;
   listOfMoves.flags[line] |= 0xC0000000;
}

// registro de que la línea tiene la semijugada negra
static void 
SetBFlag(int line)
{
   listOfMoves.flags[line] &= 0x3fffffff;
   listOfMoves.flags[line] |= 0x80000000;
}

// registro de que la línea tiene la semijugada blanca
static void
SetWFlag(int line)
{
   listOfMoves.flags[line] &= 0x3fffffff;
   listOfMoves.flags[line] |= 0x40000000;
}

/*
static void
SetCommentFlag(int line)
{
   listOfMoves.flags[line] &= 0xDfffffff;
   listOfMoves.flags[line] |= 0x20000000;
}
*/

// registro del número de jugada completa
// (línea del listado)
static void
SetMoveNumFlag(int movenum, int line)
{
   listOfMoves.flags[line] &= 0xffff0000;
   listOfMoves.flags[line] |= movenum;
}


// Añade a la lista gestionada por el recuadro
// una línea con la notación de una semijugada blanca
static void 
AddMoveW(int movenum, char presentMove[][2 * MOVE_LEN])
{
    // movenum is the last move (starting from 1)
   char line[MOVE_LEN + 5];
//
   char line1[MOVE_LEN + 5];
   char transBuf[MOVE_LEN + 5];

	line[0] = NULLCHAR;
	line1[0] = NULLCHAR;
	transBuf[0] = NULLCHAR;

	// actualizar el registro histórico
	// (las jugadas se cuentan desde 0)
	// strcpy (historyMoves[movenum - 1], presentMove[0]);

	if (toTranslate)
		TranslateMoveList(transBuf, presentMove[0]);
	else
		sprintf(transBuf, presentMove[0]);
//
   listOfMoves.lastline++;
   if (appData.debugMode)
		sprintf(line,"line %d (%d) %0.3d. %s", listOfMoves.lastline,
						movenum-1, movenum/2+1, presentMove); 
//   else
//	sprintf(line, "%d. %s", movenum / 2 + 1, movelist); 
	// intento de tabulación de las jugadas blancas y negras
	// (no funcionará más que con tipos monoespaciados,
	// como el Courier)
	sprintf(line1, "%d.", movenum / 2 + 1);
	switch (strlen(line1))
	{
		case 2:
			sprintf(line, "  %d. %s", movenum / 2 + 1, transBuf);
			break;
		case 3:
			sprintf(line, " %d. %s", movenum / 2 + 1, transBuf);
			break;
		case 4:
			sprintf(line, "%d. %s", movenum / 2 + 1, transBuf);
			break;
		default:
			break;
	}
   
	SendDlgItemMessage(listOfMoves.dialog, OPT_HistoryText, 
                    LB_ADDSTRING, (WPARAM) 0, 
                    (LPARAM) line);

   listOfMoves.lastmove = movenum;

   // registro del número (cuenta desde cero)
	// de la jugada inicial de la línea
   SetMoveNumFlag(movenum - 1, listOfMoves.lastline);
   SetWFlag(listOfMoves.lastline);
}


// Añade a la lista gestionada por el recuadro
// una línea con la notación de una semijugada negra
// (cuando es la primera de una partida, pues de lo
// contrario se hace a través de AddMoveWB())
static void 
AddMoveB(int movenum, char presentMove[][2 * MOVE_LEN])
{
   char line[MOVE_LEN + 5];
//
   char line1[MOVE_LEN + 5];
   char transBuf[MOVE_LEN + 5];

	line[0] = NULLCHAR;
	line1[0] = NULLCHAR;
	transBuf[0] = NULLCHAR;

	// actualizar el registro histórico
	// (las jugadas se cuentan desde 0)
	// strcpy (historyMoves[movenum - 1], presentMove[0]);

	if (toTranslate)
		TranslateMoveList(transBuf, presentMove[0]);
	else
		sprintf(transBuf, presentMove[0]);
//
   listOfMoves.lastline++;
   if (appData.debugMode)
		sprintf(line,"line %d (%d) %0.3d. ... %s",
						listOfMoves.lastline, movenum-1, movenum/2, presentMove); 
//   else
//	sprintf(line,"%d. ... %s", movenum / 2, movelist); 

	// intento de tabulación de las jugadas blancas y negras
	// (no funcionará más que con tipos monoespaciados,
	// como el Courier)
	sprintf(line1, "%d.", movenum / 2);
	switch (strlen(line1))
	{
		case 2: 
			sprintf(line, "  %d. ...   %s", movenum / 2, transBuf);
			break;
		case 3:
			sprintf(line, " %d. ...   %s", movenum / 2, transBuf);
			break;
		case 4:
			sprintf(line, "%d. ...   %s", movenum / 2, transBuf);
			break;
		default:
			break;
	}

   SendDlgItemMessage(listOfMoves.dialog, OPT_HistoryText, 
                    LB_ADDSTRING, (WPARAM) 0, 
                    (LPARAM) line);

   listOfMoves.lastmove = movenum;

   // registro del número (cuenta desde cero)
	// de la jugada inicial de la línea
   SetMoveNumFlag(movenum - 1, listOfMoves.lastline);
   SetBFlag(listOfMoves.lastline);
}


// Añade a la lista gestionada por el recuadro
// una línea con la notación de una jugada completa
static void 
AddMoveWB(int movenum, char presentMove[][2 * MOVE_LEN])
{
    // movenum is the last move (1-based)
   char line[MOVE_LEN + MOVE_LEN + 40];  // two moves 
//
   char line1[MOVE_LEN + 5];
   char transBuf[MOVE_LEN + 5];

	int i = 0;

	line[0] = NULLCHAR;
	line1[0] = NULLCHAR;
	transBuf[0] = NULLCHAR;

	// actualizar el registro histórico
	// (las jugadas se cuentan desde 0)
	// strcpy (historyMoves[movenum - 2], (presentMove - 1)[0]);

	if (toTranslate)
		// traducir primero la jugada blanca (la precedente)
		TranslateMoveList( transBuf, (presentMove - 1)[0] );
	else
		sprintf( transBuf, (presentMove - 1)[0] );
//		sprintf(transBuf, presentMove[movenum - 3]);

//
   listOfMoves.lastline++;
   if (appData.debugMode)
		sprintf(line, "line %d (%d) %0.3d. %s %s", listOfMoves.lastline,
						movenum-2, movenum/2, presentMove-1, presentMove);
//	else
//		sprintf(line, "%d. %s %s", movenum/2, movelist-1, movelist);
  
	// intento de tabulación de las jugadas blancas y negras
	// (no funcionará más que con tipos monoespaciados,
	// como el Courier)
	// si el listado empieza por una jugada negra
	if (strlen(transBuf) == 0)
		sprintf(transBuf, "... ");

	sprintf(line1, "%d.", movenum / 2);
	switch (strlen(line1))
	{
		case 2: 
			sprintf(line1, "  %d. %s", movenum / 2, transBuf);
			i = strlen(line1);
			break;
		case 3:
			sprintf(line1, " %d. %s", movenum / 2, transBuf);
			i = strlen(line1);
			break;
		case 4:
			sprintf(line1, "%d. %s", movenum / 2, transBuf);
			i = strlen(line1);
			break;
		default:
			break;
	}
	while ( i < 12)
	{
		strcat(line1, " ");
		i++;
	}


	// actualizar el registro histórico
	// (las jugadas se cuentan desde 0)
	// strcpy ( historyMoves[movenum - 1], presentMove[0]);

	// traducir ahora la jugada negra
	if (toTranslate)
		TranslateMoveList( transBuf, presentMove[0] );
	else
		sprintf( transBuf, presentMove[0] );
	// completar la línea
	sprintf(line, "%s%s", line1, transBuf);

   SendDlgItemMessage(listOfMoves.dialog, OPT_HistoryText, 
								LB_ADDSTRING, (WPARAM) 0, 
								(LPARAM) line);
   listOfMoves.lastmove = movenum;

   // registro del número (cuenta desde cero)
	// de la jugada inicial de la línea
   SetMoveNumFlag(movenum - 2, listOfMoves.lastline);
   SetBWFlag(listOfMoves.lastline);
}

// elimina de la lista gestionada por el recuadro
// la línea regristrada como última en 'listOfMoves'
static void 
DeleteLastLine()
{
	SendDlgItemMessage(listOfMoves.dialog, OPT_HistoryText, 
								LB_DELETESTRING, (WPARAM) listOfMoves.lastline, 
								(LPARAM) 0);
	// actualizar el registro histórico
	// (las jugadas se cuentan desde 0)
	// strcpy (historyMoves[listOfMoves.lastmove - 1], "");
	// strcpy (historyMoves[listOfMoves.lastmove], "");

   listOfMoves.lastline--;
}

/*
static int 
HasComment(int movenum)
{
	return commentList[movenum] != 0;
}

static void 
AddComment(int movenum)
{
   char * comment = commentList[movenum];
   char buf[100];
   char * str = &buf[0];
   strncpy(buf, comment, 98);
   buf[98] = 0;
   while (* str)
	{
		if (* str == '\n' || * str == '\r') 
			* str = ' ';
      str++;
	}

   SendDlgItemMessage(listOfMoves.dialog, OPT_HistoryText, 
								LB_ADDSTRING, (WPARAM) 0, 
								(LPARAM) buf);
   listOfMoves.lastline++;
   SetMoveNumFlag(movenum, listOfMoves.lastline);
   SetCommentFlag(listOfMoves.lastline);
}
*/

static void 
AddMove(int movenum, char presentMove[][2 * MOVE_LEN])
{
	// 'presentMove[0]' es aquí el comienzo de la jugada
	// 'movenum' (== 'listOfMoves.lastMove + 1'), con base 1,
	// no el origen del conjunto 'movelist' completo;
	// es una dirección que se va desplazando conforme
	// avanza la partida, por lo que '(presentMove - 1)[0]'
	// tiene sentido y se refiere a la jugada precedente
	// a 'movenum'.

   // la numeración de las jugadas comienza con 1
   if (!(movenum % 2) ) // si es par (jugada negra)
   {
		// solo la primera línea puede tener únicamente
		// la semijugada negra
		if (movenum > 1)
		{
			DeleteLastLine();	// borrar la semilínea blanca
			// y representar la jugada completa
			AddMoveWB(movenum, presentMove);
		}
		else
		{
			// semijugada negra
			AddMoveB(movenum, presentMove);
		}
	}
   else
	{
		// semijugada blanca
		AddMoveW(movenum, presentMove);
	}

/*
	if (movenum > 0 && HasComment(movenum - 1))
		if (movenum > 0)
      {
			AddMoveB(movenum, movelist);
		}
      else
      {
			DeleteLastLine();			// borrar la semilínea blanca
         AddMoveWB(movenum, movelist);
		}
		if (HasComment(movenum))
			AddComment(movenum);
	}
   else
	{
		AddMoveW(movenum, movelist);
		if (HasComment(movenum))
			AddComment(movenum);
	}
*/
}


// poner a cero la lista y las variables
// al comienzo de una partida
//static void 
// esta función tiene que ser accesible
// desde todas partes; no puede ser 'static'
void
InitHistory()
{   
	int i = 0;
 
   if ( historyDialog )
	{
		SendDlgItemMessage(listOfMoves.dialog, OPT_HistoryText,
										LB_RESETCONTENT, 0, 0);
	}
   listOfMoves.lastline = -1;
   listOfMoves.lastmove = 0;
   listOfMoves.lastselected = -1;
   listOfMoves.process_click = 0;
   for (i = 0; i < MAX_MOVES; i++)
   {
		listOfMoves.flags[i] = 0;
	}
/*
   for (i = 0; i < MAX_MOVES; i++)
   {
		historyMoves[i][0] = NULLCHAR;
	}
*/
//
	hMenu = GetMenu(hwndMain);
	SetMenuEnables(hMenu, noMoveEnables);
	walkingEnabled = FALSE;
//
}


// realzar la línea a la que pertenece la jugada indicada
static void 
HighlightLine(int current_move)
{
	// current_move se empieza a contar desde 0
   int i;
   int is_black = current_move & 1;
   int sel_line = listOfMoves.lastline;

   for (i = 0; i < listOfMoves.lastline; i++)
   {
//		if (FlagComment(i))
//			continue;
      if (FlagMoveNum(i) == current_move)
		{
			sel_line = i;
         break;
		}
      else if (is_black && FlagMoveNum(i) ==
								current_move - 1 && FlagB(i))
      {
			sel_line = i;
		}
	}
   if (sel_line != listOfMoves.lastselected)
	{
		listOfMoves.lastselected = sel_line;
      SendDlgItemMessage(listOfMoves.dialog, OPT_HistoryText,
										LB_SETCURSEL, sel_line, 0);
	}
}


// Elabora los datos correspondientes
// a una serie de jugadas o a la última realizada
void
HistorySet(char movelist[][2 * MOVE_LEN],
					int first, int last, int current)
{
   int i = 0, j = 0;
//	
	// 'movelist' es un sinónimo de la lista de jugadas
	// de la partida que se use como fuente.
	// En la mayoría de los casos es 'parseList' y no
	// 'moveList'; movelist[0] es la primera semijugada realizada.
	// 'first' funciona como un semáforo, siendo 0 si
	// son mano las blancas y 1 si lo son las negras. 
	// 'last' es el número absoluto de la última semijugada
	// realizada, siendo 0 cuando todavía no se ha empezado,
	// 1 es la primera jugada blanca, 2 la primera negra
	// (aunque no haya habido jugada blanca), etc.
	// 'current' es la jugada que se está procesando,
	// y adopta el valor 'last - 1' normalmente.
	// Estas oscilaciones alrededor del cero al inicio
	// de la partida son fuente de problemas y confusiones.
	
	// vaciar la lista previa si se ha producido
	// alguna modificación en las jugadas anteriores
	if (gameTruncated)
	{
		InitHistory();
		gameTruncated = FALSE;
	}

	// habilitar las opciones de recorrido de jugadas
	// en cuanto se haga la primera
	// (last == 1 si juegan las blancas;
	// last == 2 si juegan las negras),
	// cualquiera que sea el estado de la ventana de lista
	if (last && ! walkingEnabled && gameMode != Training)
	{
	   SetMenuEnables(hMenu, MoveEnables);
		walkingEnabled = TRUE;
	}
//

	// no seguir el proceso, si no se muestra la lista
   if (!HistoryDialog())
		return;
	// check if processing mouse click or beginning of game
//   if (listOfMoves.process_click || current < 0 )
	// mostrar la lista entera de las partidas recuperadas,
	// aun cuando se esté al comienzo
   if (listOfMoves.process_click)
		return;

//
	// sin este filtro, muestra una línea '1.' en blanco
	// al apretar la flecha derecha si juegan las negras,
	// aun cuando no se haya hecho todavía ninguna jugada;
	// esto no es completamente erróneo, pero sí incorrecto
	// (ahora no debería ser necesario, al haber
	// deshabilitado las flechas en estas circunstancias)
//	if (blackPlaysFirst && current == 0)
//		return;
	// regularizar la cuenta en el caso de la primera jugada blanca
	if (! blackPlaysFirst && current < 0)
		current = 0;
//
/*
//   if ( (last < listOfMoves.lastmove) ||	// si hay truncamiento
   if ( (last <= listOfMoves.lastmove) )	// (el truncamiento,
					// puede producirse ya en la primera jugada,
					// por lo que el '=' es necesario)

					// no reiniciar aquí, que se hace a ciegas,
					// si puede evitarse; reiniciar con más fundamento
					// antes de recurrir a la función

					// o es el inicio de la partida
					// a) moviendo las blancas
//					(first == 0 && last == 0 && current == -1)
					// o b) moviendo las negras
//					|| (blackPlaysFirst && first == 1 && current == 1) )
	{
		InitHistory();
	}

	if ( current < (last - 1) )
	{
		// estamos revisando jugadas pasadas
		// y alguna puede haber variado,
		// si se ha retrocedido;
		// compárense las dos listas
		for (i = 0; i <= current, j == 0; i++)
		{
			j = strcmp(movelist[i], historyMoves[i]);
		}

		if	( j != 0 )			// si ha habido algún cambio,
		{
			InitHistory();		// anular toda la lista previa
		}
	}
*/
	// añadir las nuevas jugadas, posteriores a 'lastmove'
   if (last > listOfMoves.lastmove)
	{   
		for (i = listOfMoves.lastmove + 1; i <= last; i++)
		{
			AddMove(i, &movelist[i - 1]);
//
			// no fiarse por completo del valor de 'last'
			// y añadir solo las jugadas efectivamente realizadas
			// (lo que permite llamar a la función sin problemas
			// cuando no se sabe cuántas jugadas se llevan hechas;
			// basta con dar a 'last' un valor razonablemente grande
			// (No vale, porque cuando son mano las negras
			// 'movelist[0]' es "" y la primera jugada está en
			// 'movelist[1]'.)

//			if (strlen(movelist[i - 1]) > 0)
//			{
//				AddMove(i, &movelist[i - 1]);
//			}
//			else
//				break;
		}
      listOfMoves.lastselected = listOfMoves.lastline;
      SendDlgItemMessage(listOfMoves.dialog, OPT_HistoryText,
									LB_SETCURSEL, listOfMoves.lastselected, 0);
	}

	// sin esta instrucción, el cursor no sigue
	// la revisión de las jugadas
	HighlightLine(current);
	return;
}


// Restaura el tablero a la disposición que tenía
// en la línea n
static void 
HistoryClick(int n)
{
   int move_num = FlagMoveNum(n);	// obtener el número de jugada
   listOfMoves.process_click = 1;	// semáforo rojo

/*
   if (FlagComment(n))
	{
        
	}
   else
   {
		if (listOfMoves.moveblack && FlagB(n) && FlagW(n))
*/
	// la línea tiene una jugada completa
	if ( FlagB(n) && FlagW(n) )
		move_num += 2; // situarse tras el movimiento negro
   else
		move_num += 1; //  situarse tras el movimiento blanco
//	}
	// retrotraer el tablero a la situación
	// que tenía tras la última jugada
	// de la línea elegida 
   ToNrEvent(move_num);
   listOfMoves.process_click = 0;	// semáforo verde

	return;
}


// static void 
int
CheckListSelection()
{
	int sel = LB_ERR;		// índice de la línea seleccionada
   if ( historyDialog )
	{
//		int sel = SendDlgItemMessage(listOfMoves.dialog, OPT_HistoryText,
		sel = SendDlgItemMessage(listOfMoves.dialog, OPT_HistoryText,
												LB_GETCURSEL, 0, 0);
      if (sel >= 0 && sel != listOfMoves.lastselected)
		{
			listOfMoves.lastselected = sel;
         HistoryClick(sel);	// sincronizar el tablero
		}
	}
	// devolución del enfoque a la ventana principal
	SetFocus(hwndMain);
	
	return sel;
}

/*
void 
ReinitHistory()
{
   InitHistory();
   if (currentMove > 0)
	{
		BackwardEvent();
      ForwardEvent();
	}
   else
	{
		ForwardEvent();
		BackwardEvent();
	}
}
*/

LRESULT CALLBACK
HistoryDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	static HANDLE hwndText;
	static int sizeX, sizeY;
	int newSizeX, newSizeY;
	MINMAXINFO * mmi;
	RECT rect;
//
	extern char parseList[][2 * MOVE_LEN];
	int i = 0;
//
	switch (message)
	{
		case WM_INITDIALOG: 
			/* Initialize the dialog items */
			if (! historyDialog)
			{
		      historyDialog = hDlg;
				listOfMoves.dialog = hDlg;
//				CheckDlgButton(hDlg, IDC_WHITE_MOVE, 1);
//				listOfMoves.idletimer = SetTimer(listOfMoves.dialog,
//														(UINT) HISTORY_TIMER_ID,
//														(UINT) 300 /*millisec*/,
//														NULL);
				// ubicación de la ventana en la zona deseada
				GetClientRect(hDlg, &rect);	// coordenadas de la caja
				sizeX = rect.right;		// coordenadas actuales
				sizeY = rect.bottom;

				// #define CW_USEDEFAULT       ((int)0x80000000) (winuser.h)

				if (historyX != CW_USEDEFAULT &&
						historyY != CW_USEDEFAULT &&
						historyW != CW_USEDEFAULT &&
						historyH != CW_USEDEFAULT)
				{
					WINDOWPLACEMENT wp;
					// coordenadas recuperadas de Winboard.ini
					EnsureOnScreen(&historyX, &historyY);
					wp.length = sizeof(WINDOWPLACEMENT);
					wp.flags = 0;
					wp.showCmd = SW_SHOW;
					wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
					wp.rcNormalPosition.left = historyX;
					wp.rcNormalPosition.right = historyX + historyW;
 					wp.rcNormalPosition.top = historyY;
					wp.rcNormalPosition.bottom = historyY + historyH;
					SetWindowPlacement(hDlg, &wp);	// reubicarla

					GetClientRect(hDlg, &rect);
					newSizeX = rect.right;
					newSizeY = rect.bottom;
					ResizeEditPlusButtons(hDlg, GetDlgItem(hDlg,
													OPT_HistoryText), sizeX, sizeY,
													newSizeX, newSizeY);
					sizeX = newSizeX;
					sizeY = newSizeY;
				}
			}
//
			InitHistory();
			// si la partida ha comenzado antes de que se
			// quiera ver la notación de su desarrollo,
			// o si se la ha cargado desde un archivo de disco,
			// hay que ponerse al día
			if ( ( blackPlaysFirst && strlen(parseList[1]) > 0 )
						|| ( ! blackPlaysFirst && strlen(parseList[0]) > 0) )
			{
				i = 1;
				while ((strlen(parseList[i]) > 0) && (i < MAX_MOVES))
					i++;
				HistorySet(parseList, 0, i, 0);
			}

			return TRUE;		// no enfocar este recuadro

		case WM_SIZE:
			newSizeX = LOWORD(lParam);
			newSizeY = HIWORD(lParam);
			ResizeEditPlusButtons(hDlg, GetDlgItem(hDlg, OPT_HistoryText),
												sizeX, sizeY, newSizeX, newSizeY);
			sizeX = newSizeX;
			sizeY = newSizeY;
			break;

		case WM_GETMINMAXINFO:
			/* Prevent resizing window too small */
			mmi = (MINMAXINFO *) lParam;
			// anchura mínima de una línea para
			// que se vea una jugada completa
			mmi->ptMinTrackSize.x = 160;
			mmi->ptMinTrackSize.y = 200;
			break;
/*
		case WM_TIMER:
			switch (wParam)
			{
				case HISTORY_TIMER_ID:
					CheckListSelection();
					break;
			}
			break;
*/

		// He tenido que introducir esto porque,
		// por alguna razón que ignoro,
		// ha dejado de cerrarse el recuadro
		// cuando se pulsa su botón de cierre (aspa)
		case WM_SYSCOMMAND:
			switch (wParam)
			{
				case SC_CLOSE:
					HistoryPopDown();
					return (BOOLEAN) 0;	// ya está hecho
				default:
					break;
			}
			return FALSE;
//			return TRUE;	// esto congela
			// la totalidad del recuadro,
			// que no puede ya desplazarse
			// ni cambiarse de tamaño (¡!)

		case WM_COMMAND:
			// "If an application processes this message,
			// it should return zero." (ayuda de WM_COMMAND)
			switch (LOWORD(wParam))
			{
				case OPT_HistoryText:	// pulsaciones sobre la lista
					switch (HIWORD(wParam))
					{
						case LBN_SELCHANGE:  // esto pasa con un solo clic
							break;						
						case LBN_DBLCLK:		// doble clic
							// identificar la línea seleccionada
//							i = SendDlgItemMessage(listOfMoves.dialog,
//										OPT_HistoryText,
//										LB_GETCURSEL, 0, 0);
							// y reponer el tablero al estado que tenía
							// tras su última jugada
//							HistoryClick(i);
							CheckListSelection();
							return (BOOLEAN) 0;
//							break;
						default:
							break;
					}	// switch (HIWORD(wParam))
			}	// switch (LOWORD(wParam))
			break;
		// se ha pulsado una tecla estando enfocado el recuadro
		// y la lista tiene el estilo 'Want key input'
		case WM_VKEYTOITEM:
			switch (LOWORD(wParam))	// código de la tecla pulsada
			{
				// se ha pulsado la tecla 'entrada'
				// o 'retorno de carro'
//				case VK_ENTER:
					// (el compilador no reconoce este símbolo,
					// aunque está listado en la Ayuda SDK)
				case VK_RETURN:
					// (Ceballos: 177 le asigna este símbolo,
					// que funciona, pero que
					// en cambio no se reseña en SDK)
					// sincronizar el tablero con la
					// línea seleccionada de la lista,
					i = CheckListSelection();
					// pero manteniéndola seleccionada
					return (BOOLEAN) i;
/*
				// (lo que sigue no funciona:
				// las teclas siguen interpretándose
				// en el tablero y no en la lista)
				case VK_LEFT:
				case VK_UP:
					i = SendDlgItemMessage(listOfMoves.dialog,
										OPT_HistoryText,
										LB_GETCURSEL, 0, 0);
					// desplazar la selección una línea hacia arriba
					return (BOOLEAN) (i - 1);
				case VK_RIGHT:
				case VK_DOWN:
					i = SendDlgItemMessage(listOfMoves.dialog,
										OPT_HistoryText,
										LB_GETCURSEL, 0, 0);
					// desplazar la selección una línea hacia abajo
					return (BOOLEAN) (i + 1);
*/
				default:
					break;
			}	// switch (LOWORD(wParam))
			// se ha hecho todo lo que había que hacer;
			// no se haga nada más
//			return (BOOLEAN) -2;
			// ejecútese la acción predeterminada
			// (situarse al inicio de la lista)
//			return (BOOLEAN) -1;
			// ejecútese la acción predeterminada
			// sobre el valor devuelto como índice
//			return (BOOLEAN) 0;	// o superior;
			break;
		default:
			break;
	}	// switch (message)

	return FALSE;		// no hay nada más que hacer


/*
			switch (LOWORD(wParam))
			{
				// tratamiento de pulsaciones
				// de botones que ahora no hay
				case OPT_HistoryReinit:
					ReinitHistory();
					break;
				case IDCANCEL:
					HistoryPopDown();
					return TRUE;
				case IDC_BLACK_MOVE:
					listOfMoves.moveblack = 1;
					listOfMoves.lastselected = -1;
					break;
				case IDC_WHITE_MOVE:
					listOfMoves.moveblack = 0;
					listOfMoves.lastselected = -1;
					break;
				default:
					return FALSE;
			}	// switch (LOWORD(wParam))
			return TRUE;
		default:
			break;
   }	// switch (message)
	return FALSE;
*/
}


BOOLEAN 
IsHistoryWindUp()
{
	return listOfMoves.up;
}

HWND 
HistoryDialog()
{
	return listOfMoves.dialog;
}

VOID 
HistoryPopUp()
{
	FARPROC lpProc;
//  
	CheckMenuItem(GetMenu(hwndMain), IDM_ShowHistory, MF_CHECKED);
	appData.showHistory = TRUE;
//
	if ( historyDialog )
   {
		SendMessage(listOfMoves.dialog, WM_INITDIALOG, 0, 0);
		if (!listOfMoves.up)
			ShowWindow(listOfMoves.dialog, SW_SHOW);
   }
   else
   {
		lpProc = MakeProcInstance((FARPROC)HistoryDialogProc, hInst);
		CreateDialog(hInst, MAKEINTRESOURCE(DLG_History),
												hwndMain, (DLGPROC)lpProc);
		FreeProcInstance(lpProc);
   }
	listOfMoves.up = TRUE;
}

VOID 
HistoryPopDown(void)
{
//
	CheckMenuItem(GetMenu(hwndMain), IDM_ShowHistory, MF_UNCHECKED);
	appData.showHistory = FALSE;
//
	if ( historyDialog )
		ShowWindow(listOfMoves.dialog, SW_HIDE);
	listOfMoves.up = FALSE;
}


VOID 
HistoryHighlight(int index)
{
	if (listOfMoves.dialog == NULL)
		return;
	SendDlgItemMessage(listOfMoves.dialog, OPT_HistoryText, 
									LB_SETCURSEL, index - 1, 0);
}


VOID 
HistoryDestroy()
{
	HistoryPopDown();
}

VOID 
ShowHistoryProc()
{
	if (listOfMoves.up)
	{
		HistoryPopDown();
   }
	else
	{
		HistoryPopUp();
   }
}
