/*
 * wFGmodifications.c -- Additional features for WinBoard by F. Gracia
 * $Id: : wFGmodifications.h,v 2.1 2004/07/08 gracia $
 *
 * Copyright 1995 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.
 * ------------------------------------------------------------------------
 */

#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"
#include "wFGmodifications.h"
#include "defaults.h"


extern HINSTANCE hInst;
extern HWND hwndMain;
extern int boton1, boton2;

/*-----------------------------------------------------*
 *																		 *
 * Conversión a PGN de otras notaciones ajedrecísticas *
 *																		 *
 *-----------------------------------------------------*/

extern char line1[MSG_SIZ];
extern int fenModeCount;
extern int oddStylesCount;
extern int positionCount;

Boolean 
ConvertPositionsEvent(void)
{

	FILE * f, * d;
   char line[MSG_SIZ];
   char fileTitle[MSG_SIZ];	// tampón para nombre pelado del fichero
   char fileName[MSG_SIZ];		// tampón para ruta completa del fichero
   char fenTranslation[MSG_SIZ];
	Board initial_position;    // tablero receptor provisional
	int oldModeCount, style12Count, conversionCount, j;

	char * p;
	HWND hwnd = NULL;

   fenModeCount = 0;
	oldModeCount = 0;
	style12Count = 0;
	conversionCount = 0;
	oddStylesCount = 0;
   line[0] = NULLCHAR;
	line1[0] = NULLCHAR;
   fileName[0] = NULLCHAR;
   fileTitle[0] = NULLCHAR;
	fenTranslation[0] = NULLCHAR;
	p = NULL;

	// selección del archivo y acceso a él para leerlo
	f = OpenFileDialog(hwnd, (BOOLEAN) READ, "", "pos", POSITION_FILT,
								 fileToExplore, NULL, fileTitle, fileName);
	if (f == NULL)
		return FALSE;
	else
		// explorarlo en busca de posiciones de cualquier tipo
		ScanFileForPositions( f, & positionCount,	& fenModeCount,
										& oldModeCount, & style12Count );
	
	if (positionCount == 0)
	{
		// Si no las hay, informar del resultado y terminar
		sprintf(line, noFEN, fileTitle);
      MessageBox(NULL, line, "WinBoard",
									MB_OK | MB_ICONEXCLAMATION);
		fclose(f);
		return TRUE;
	}

	// Si las hay,
	if (positionCount == fenModeCount)
	{
		// a) y son exclusivamente FEN,
		// informar del resultado y terminar
		sprintf(line, alreadyFEN, fileTitle);
      MessageBox(NULL, line, "WinBoard",
									MB_OK | MB_ICONEXCLAMATION);
		fclose(f);
		return TRUE;
	}
	else if ( oldModeCount || style12Count)
	{
		oddStylesCount = oldModeCount + style12Count;
		// b) están formuladas también en otras notaciones,
		//		- informar del resultado
		//		- preguntar si se quieren almacenar en un archivo nuevo
		//			(y si todas las que haya o solo las no FEN)
		sprintf( line1, "\"%s\"", fileTitle);
		decision = FALSE;
		boton1 = 1;			// solo las no FEN
		ConversionPopUp();
	}

	// Si no se contesta afirmativamente,
	if ( decision != TRUE || boton1 == 0 )
	{
		// terminemos
		fclose(f);
		return FALSE;
	}

	//	En caso contrario, obtener la ruta y el nombre
	// del archivo de destino, crearlo y dejarlo abierto
	// para escritura destructiva;
	// predeterminar su nombre con el del archivo base
	strcpy(fileName, fileTitle);
	if ( p = strrchr(fileName, '.') )
	{
		// 'fileName' es el dato que se muestra en
		// la línea de edición del recuadro,
		// (aunque 'fileTitle' sea el nombre pelado),
		// pero sin la ruta, si es la misma presentada
		p++;
		* p = NULLCHAR;
		strcat(fileName, "fen");	
	}

	if (boton2 == 2)
		j = OVERWRITE;
	else
		j = APPEND;

	d = OpenFileDialog(hwnd, (BOOLEAN) j, "", "fen", POSITION_FILT,
								 fileToSave, NULL, fileTitle, fileName);
	if (d == NULL)
	{
		fclose(f);
		return FALSE;
	}
	else
	{
		// Volver a explorar la totalidad del archivo originario
		// grabando las sartas FEN resultantes
	   fseek(f, 0, SEEK_SET);

		// Poner un encabezamiento que pueda
		// ser de utilidad
		sprintf(fenTranslation, "\n");
		fprintf(d, fenTranslation);
		sprintf(fenTranslation, conversionTitle1, line1);
		fprintf(d, fenTranslation);
		sprintf(line, "%s %s.%s", PRODUCT, VERSION, PATCHLEVEL);
		sprintf(fenTranslation, conversionTitle2, line);
		fprintf(d, fenTranslation);
		sprintf(fenTranslation, "\n");
		fprintf(d, fenTranslation);
		fprintf(d, fenTranslation);

		// ¿qué se quería grabar?
		if ( boton1 == 1 )		// solo las no FEN
		{
			while ( fgets(line, MSG_SIZ, f) != NULL
						&& (conversionCount < oddStylesCount) )
			{
				if ( ParseOldMode(f, initial_position,
							line,	fenTranslation) ||
							ParseStyle12(initial_position,
							line, fenTranslation) )
				{
					strcat( fenTranslation, "\n");
					fprintf(d, fenTranslation);
				}
				else
					continue;

				conversionCount++;
			}
		}
		else if ( boton1 == 2 )		// todas
		{
			while ( fgets(line, MSG_SIZ, f) != NULL
						&& (conversionCount < positionCount) )
			{
				if ( ParseFEN(initial_position, &blackPlaysFirst, line) )
				{
					strcat(line, "\n");	// añadir el retorno de carro
					fprintf(d, line);
				}
				else if ( ParseOldMode(f, initial_position, line,
							fenTranslation) || ParseStyle12(initial_position,
							line, fenTranslation) )
				{
					strcat( fenTranslation, "\n");
					fprintf(d, fenTranslation);
				}
				else
					continue;
				
				conversionCount++;
			}
		}
		else if ( boton1 == 3 )		// solo las FEN
		{
			while (fgets(line, MSG_SIZ, f) != NULL
						&& (conversionCount < fenModeCount))
			{
				if ( ParseFEN(initial_position, &blackPlaysFirst, line) )
				{
					strcat(line, "\n");	// añadir el retorno de carro
					fprintf(d, line);
				}
				else
					continue;
				
				conversionCount++;
			}
		}
	}

	// Cerrar los ficheros de origen y de destino
	fclose(f);
	if (fclose(d) != 0)
	{
		sprintf(line, closeFileError, fileTitle);
		DisplayError(line, 0);
		return FALSE;
	}
	else
	{
		// Informar del resultado y terminar.
		sprintf(line, conversionDone, conversionCount, fileTitle);
      MessageBox(NULL, line, "WinBoard",
									MB_OK | MB_ICONEXCLAMATION);
	}
	return TRUE;
}


// Recuadro de conversión
VOID
ConversionPopUp( void )
{

	FARPROC lpProc;

	lpProc = MakeProcInstance((FARPROC)ConversionProc, hInst);
	DialogBox(hInst, MAKEINTRESOURCE(DLG_Conversion),
											hwndMain, (DLGPROC)lpProc);
	FreeProcInstance(lpProc);
}


/* Process messages for Conversion dialog box */
LRESULT CALLBACK
ConversionProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
//	extern char line1[MSG_SIZ];
//	extern int fenModeCount;
//	extern int oddStylesCount;

	char fenModeSt[MSG_SIZ];
	char oddModeSt[MSG_SIZ];

	switch (message)
	{
		case WM_INITDIALOG: /* message: initialize dialog box */
			/* Initialize the dialog items */
			/* Center the dialog over the application window */
			CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
			
			// predeterminar el botón 'Sólo las no FEN'
			switch (boton1)
			{
				case 0:
				case 1:			// solo las no FEN
					CheckDlgButton(hDlg, IDC_RADIO1, BST_CHECKED);
					break;
				case 2:			// todas
					CheckDlgButton(hDlg, IDC_RADIO2, BST_CHECKED);
					break;
				case 3:			// solo las FEN
					CheckDlgButton(hDlg, IDC_RADIO3, BST_CHECKED);
					break;
				case 4:			// ninguna
					CheckDlgButton(hDlg, IDC_RADIO4, BST_CHECKED);
					break;
				default:
					CheckDlgButton(hDlg, IDC_RADIO1, BST_CHECKED);
					break;
			}
			// predeterminar el botón 'añadir'
			switch (boton2)
			{
				case 1:			// añadir
					CheckDlgButton(hDlg, IDC_RADIO5, BST_CHECKED);
					break;
				case 2:			// sobrescribir
					CheckDlgButton(hDlg, IDC_RADIO6, BST_CHECKED);
					break;
				default:
					CheckDlgButton(hDlg, IDC_RADIO5, BST_CHECKED);
					break;
			}
			// desactivar las opciones inaplicables
			if (fenModeCount == 0)
			{
				EnableWindow(GetDlgItem(hDlg, IDC_RADIO2), FALSE);
				EnableWindow(GetDlgItem(hDlg, IDC_RADIO3), FALSE);
			}
			
			sprintf( fenModeSt, "%d", fenModeCount);
			sprintf( oddModeSt, "%d", oddStylesCount);

			// presentar el resultado de la exploración
			SetWindowText( GetDlgItem(hDlg, OPT_ConversionText3),
											line1); 
			SetWindowText( GetDlgItem(hDlg, OPT_ConversionText1),
											fenModeSt); 
			SetWindowText( GetDlgItem(hDlg, OPT_ConversionText2),
											oddModeSt); 
			// mostrar la caja
			ShowWindow(hDlg, SW_SHOW);
			
			return TRUE;

		case WM_COMMAND: /* message: received a command */
			switch (LOWORD(wParam))
			{
				// registrar la selección
				case IDC_RADIO1:		// BN_CLICKED:
					boton1 = 1;
					return FALSE;

				case IDC_RADIO2:
					boton1 = 2;
					return FALSE;

				case IDC_RADIO3:
					boton1 = 3;
					return FALSE;

				case IDC_RADIO4:
					boton1 = 0;
					return FALSE;

				case IDC_RADIO5:
					boton2 = 1;
					return FALSE;

				case IDC_RADIO6:
					boton2 = 2;
					return FALSE;

				// adelante
				case IDOK:
					decision = TRUE;
					break;

				// no hagamos nada
				case IDCANCEL:
					EndDialog(hDlg, TRUE); /* Exit the dialog */
				
				default:
					return FALSE;
			}

			EndDialog(hDlg, TRUE); /* Exit the dialog */
			return TRUE;
   }
	return FALSE;
}



/*-----------------------------------------------------------------*
 *																						 *
 * Ampliación de las posibilidades a la hora de salvar una partida *
 *																						 *
 *-----------------------------------------------------------------*/




	CurrentGame currentGame;	// estructura definida en 'common.h'

	extern BOOLEAN salva;
	extern FILE * lastLoadGameFP, * lastLoadPositionFP;
	extern int lastLoadGameNumber, lastLoadPositionNumber;
	extern int lastLoadGameUseList;
	extern char lastLoadGameTitle[MSG_SIZ], lastLoadPositionTitle[MSG_SIZ];


// Asignación de valores iniciales a 'currentGame'
void
InitCurrentGameData(void)
{
	currentGame.recorded = FALSE;	// relación con fichero de disco
	currentGame.modified = FALSE;	// diferencia con lo grabado
	currentGame.replace = FALSE;	// sustituir o copiar a continuación
	currentGame.inFile[0] = NULLCHAR;	// ruta completa del fichero
	currentGame.opened = NULL;		// apertura independiente
	//	ubicaciones de la partida en el fichero (byte desde el origen)
	currentGame.firstInsertionPoint = SEEK_SET;	// inicio de la partida
	currentGame.secondInsertionPoint = SEEK_END;	// fin de la partida
	currentGame.serialNumber = 0;	// número de orden (empezando por 1)
	currentGame.totalNumber = 0;	// total de partidas en el fichero
											// (empezando por 1)
	currentGame.lastSelected = 0;
}


BOOLEAN
ModifiedGameEvent(void)
{

	FILE * f;
	char * defName;
	ListGame * lp;	// referencia a una ficha de la lista
	HWND hwnd = NULL;
	char fileTitle[MSG_SIZ];
	char mensaje[MSG_SIZ];

	fileTitle[0] = NULLCHAR;
	mensaje[0] = NULLCHAR;

	// informar de la situación y presentar las alternativas
	ModifiedGamePopUp();

	switch (boton1)
	{
		case 0:			// operación cancelada
			break;
		case 1:			// guardar los cambios,

			switch (boton2)
			{
				case 3:			// reemplazando a la antigua
					currentGame.replace = TRUE;
					currentGame.lastSelected = 3;
					// si se ejecuta sin problemas,
					if ( ReplaceInFile() )
					{
						// reelaboración de la lista
						UpdateRecordedData(&saveList);
						// y actualización de datos
						// obtengamos la ficha correspondiente
						lp = (ListGame *) ListElem( &saveList,
												currentGame.serialNumber - 1 );
						if (lp != NULL)
						{
							currentGame.serialNumber = lp->number;
							// registrar dónde empieza
							currentGame.firstInsertionPoint = lp->offset;
							// y dónde acaba
							currentGame.secondInsertionPoint = lp->end;
						}
						// actualicemos algunos otros datos
						currentGame.modified = FALSE;
						return TRUE;
					}
					else
					{
						// información del error
						sprintf(mensaje, lastFileNotAccessible,
									currentGame.inFile); 
//					   DisplayError(mensaje, 0);
				      MessageBox(NULL, mensaje, "WinBoard",
											MB_OK|MB_ICONEXCLAMATION);
						break;
					}

				case 4:			// grabar a continuación de la antigua
					currentGame.replace = FALSE; 
					currentGame.lastSelected = 4;
					// si se ejecuta sin problemas,
					if ( ReplaceInFile() )
					{
						// registrar que el fichero tiene una partida más
						currentGame.serialNumber ++;
						// reelaboración de la lista
						UpdateRecordedData(&saveList);
						// obtengamos la ficha correspondiente
						lp = (ListGame *) ListElem( &saveList,
												currentGame.serialNumber - 1 );
						if (lp != NULL)
						{
							currentGame.serialNumber = lp->number;
							// registrar dónde empieza
							currentGame.firstInsertionPoint = lp->offset;
							// y dónde acaba
							currentGame.secondInsertionPoint = lp->end;
						}
						// actualizar los datos
						currentGame.modified = FALSE;
						if (currentGame.opened != NULL)
						{
							lastLoadGameNumber = currentGame.serialNumber;
						}
						return TRUE;
					}
					else
					{
						// información del error
						sprintf(mensaje, lastFileNotAccessible,
									currentGame.inFile); 
//					   DisplayError(mensaje, 0);
				      MessageBox(NULL, mensaje, "WinBoard",
											MB_OK|MB_ICONEXCLAMATION);
						break;
					}

				case 5:			// insertar al final del fichero
					currentGame.lastSelected = 5;
					f = fopen(currentGame.inFile, "a");
					if (f != NULL)
					{
						SaveGame(f, 0, "");
						// registrar que el fichero tiene una partida más
						currentGame.serialNumber ++;
						// reelaboración de la lista
						UpdateRecordedData(&saveList);
						// y actualización de los datos
						// Obtengamos la ficha correspondiente
						// (que es la última)
						lp = (ListGame *) ListElem(&saveList,
												currentGame.totalNumber - 1);
						if (lp != NULL)
						{
							currentGame.serialNumber = lp->number;
							// registrar dónde empieza
							currentGame.firstInsertionPoint = lp->offset;
							// y dónde acaba
							currentGame.secondInsertionPoint = lp->end;
						}

						if (currentGame.opened != NULL)
						{
							lastLoadGameNumber = currentGame.serialNumber;
						}
						currentGame.modified = FALSE;
						return TRUE;
					}
					else
					{
						// información del error
						sprintf(mensaje, lastFileNotAccessible,
									currentGame.inFile); 
//					   DisplayError(mensaje, 0);
				      MessageBox(NULL, mensaje, "WinBoard",
											MB_OK|MB_ICONEXCLAMATION);
						break;
					}

				case 6:			// elegir el fichero al modo originario
					currentGame.lastSelected = 6;
					defName = DefaultFileName(appData.oldSaveStyle ?
														"gam" : "pgn");
					strcpy(fileTitle, currentGame.inFile); 
					f = OpenFileDialog(hwnd, TRUE, defName,
								appData.oldSaveStyle ? "gam" : "pgn",
								GAME_FILT,
								saveToFile, NULL,
								// devuelve el nombre del fichero abierto
								fileTitle,
								// obtener aquí la ruta completa
								mensaje);
					if (f != NULL)
					{
						SaveGame(f, 0, "");
						if ( (strcmp(mensaje, currentGame.inFile)) != 0 )
						{
							// si el fichero previo está abierto,
							if ( currentGame.opened )
							{
								fclose( currentGame.opened ); // ciérrese
								// e invalídense los datos de
								// de LoadGame(), por lo menos
								lastLoadGameFP = NULL;
								lastLoadGameNumber = 0;
								lastLoadGameUseList = FALSE;
								lastLoadGameTitle[0] = NULLCHAR;
							}
							// pues es un fichero distinto
							InitCurrentGameData();
							strcpy( currentGame.inFile, mensaje);
						}
						// reelaboración de la lista
						UpdateRecordedData( &saveList );
						// la partida actual es la última
						// obtengamos su ficha
						lp = (ListGame *) ListElem( &saveList,
												currentGame.totalNumber - 1 );
						if (lp != NULL)
						{
							currentGame.serialNumber = lp->number;
							// registrar dónde empieza
							currentGame.firstInsertionPoint = lp->offset;
							// y dónde acaba
							currentGame.secondInsertionPoint = lp->end;
						}
						// actualicemos algunos otros datos
						if (currentGame.opened != NULL)
						{
							lastLoadGameNumber = currentGame.serialNumber;
						}
						currentGame.modified = FALSE;
						currentGame.recorded = TRUE;
						return TRUE;
					}
				default:
					break;
			}
			
		case 2:			// descartar las modificaciones
			currentGame.modified = FALSE;
			return TRUE;
		default:
			break;
	}
	return FALSE;
}


// Reelaboración de la lista solicitada referente
// al fichero 'currentGame.inFile'
BOOLEAN
UpdateRecordedData(List * lista)
{
	FILE * f;
	int error;

	// reelaboración de la lista
	f = fopen(currentGame.inFile, "rb");
	error = GameListBuild(f, lista);
	fclose(f);

	if (error)
	{
		DisplayError(noGameList, error);
		return FALSE;
/*
		// suponer que no había ninguna partida previa
		currentGame.totalNumber = 1;
		currentGame.serialNumber = 1;
*/
	}
	else
	{
		// sepamos cuántas partidas hay
		currentGame.totalNumber = ListTotal(&saveList);
	}
	return TRUE;
}


// Presentación del recuadro en la pantalla
VOID
ModifiedGamePopUp( void )
{
  FARPROC lpProc;

  lpProc = MakeProcInstance((FARPROC)ModifiedGameProc, hInst);
  DialogBox(hInst, MAKEINTRESOURCE(DLG_ModifiedGame),
											hwndMain, (DLGPROC)lpProc);
  FreeProcInstance(lpProc);
}


// Procesamiento de los mensajes del recuadro de salvaguardia
LRESULT CALLBACK
ModifiedGameProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
//	char mensaje[MSG_SIZ];
//	mensaje[0] = NULLCHAR;

	switch (message)
	{
		case WM_INITDIALOG: // organización inicial del recuadro
			
			// centrado sobre la imagen de la aplicación
			CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));

			if (salva)
			{
				// predeterminar el botón 'Sí'
				CheckDlgButton(hDlg, IDC_RADIO1, BST_CHECKED);
				boton1 = 1;
				if ( currentGame.lastSelected == 0 )
				{
					// predeterminar el botón 'añadir al final'
					CheckDlgButton(hDlg, IDC_RADIO5, BST_CHECKED);
					boton2 = 5;
				}
				else
				{
					// predeterminar el botón elegido previamente
					switch (currentGame.lastSelected)
					{
						case 3:
							CheckDlgButton(hDlg, IDC_RADIO3,
													BST_CHECKED);
							break;
						case 4:
							CheckDlgButton(hDlg, IDC_RADIO4,
													BST_CHECKED);
							break;
						case 5:
							CheckDlgButton(hDlg, IDC_RADIO5,
													BST_CHECKED);
							break;
						case 6:
							CheckDlgButton(hDlg, IDC_RADIO6,
													BST_CHECKED);
							break;
						default:
							break;
					}
					boton2 = currentGame.lastSelected;
				}
			}
			else
			{
				// predeterminar el botón 'No'
				CheckDlgButton(hDlg, IDC_RADIO2, BST_CHECKED);

				// desactivar las opciones inaplicables
				EnableWindow(GetDlgItem(hDlg, IDC_RADIO3), FALSE);
				EnableWindow(GetDlgItem(hDlg, IDC_RADIO4), FALSE);
				EnableWindow(GetDlgItem(hDlg, IDC_RADIO5), FALSE);
				EnableWindow(GetDlgItem(hDlg, IDC_RADIO6), FALSE);
			
				boton1 = 2;
			}
			// mostrar la caja
			ShowWindow(hDlg, SW_SHOW);
		
			return TRUE;

		case WM_COMMAND:
			switch (LOWORD(wParam))
			{
				// no hagamos nada
				case IDCANCEL:
					boton1 = 0;
					EndDialog(hDlg, TRUE);			// cerrar el recuadro
					return TRUE;
				// adelante
				case IDOK:
					EndDialog(hDlg, TRUE);			// cerrar el recuadro
					return TRUE;

				// registrar la selección
				case IDC_RADIO1:		// BN_CLICKED:
					boton1 = 1;
					
					// activar las distintas alternativas
					EnableWindow(GetDlgItem(hDlg, IDC_RADIO3), TRUE);
					EnableWindow(GetDlgItem(hDlg, IDC_RADIO4), TRUE);
					EnableWindow(GetDlgItem(hDlg, IDC_RADIO5), TRUE);
					EnableWindow(GetDlgItem(hDlg, IDC_RADIO6), TRUE);

					if (	currentGame.lastSelected == 0 )
					{
						// predeterminar el botón 'añadir al final'
						CheckDlgButton(hDlg, IDC_RADIO5, BST_CHECKED);
						boton2 = 5;
					}
					else
					{
						// predeterminar el botón elegido previamente
						switch (currentGame.lastSelected)
						{
							case 3:
								CheckDlgButton(hDlg, IDC_RADIO3,
														BST_CHECKED);
								break;
							case 4:
								CheckDlgButton(hDlg, IDC_RADIO4,
														BST_CHECKED);
								break;
							case 5:
								CheckDlgButton(hDlg, IDC_RADIO5,
														BST_CHECKED);
								break;
							case 6:
								CheckDlgButton(hDlg, IDC_RADIO6,
														BST_CHECKED);
								break;
							default:
								break;
						}
						boton2 = currentGame.lastSelected;
					}

					return FALSE;

				case IDC_RADIO2:
					boton1 = 2;

					// desactivar las opciones inaplicables
					EnableWindow(GetDlgItem(hDlg, IDC_RADIO3), FALSE);
					EnableWindow(GetDlgItem(hDlg, IDC_RADIO4), FALSE);
					EnableWindow(GetDlgItem(hDlg, IDC_RADIO5), FALSE);
					EnableWindow(GetDlgItem(hDlg, IDC_RADIO6), FALSE);
					
					return FALSE;

				case IDC_RADIO3:
					boton2 = 3;
					return FALSE;

				case IDC_RADIO4:
					boton2 = 4;
					return FALSE;

				case IDC_RADIO5:
					boton2 = 5;
					return FALSE;

				case IDC_RADIO6:
					boton2 = 6;
					return FALSE;

				default:
					break;
			}
		default:
			break;
   }
	return FALSE;
}


// Reemplaza una partida modificada de un fichero;
// los detalles de la operación se contienen
// en la estructura 'currentGame':
//		- si 'currentGame.replace == TRUE' la nueva
// versión sustituye a la antigua; si es falso,
// se copia tras ella
//		- los puntos en que ha de producirse la inserción se
// precisan en 'CurrentGame.firstInsertionPoint' y
// 'currentGame.secondInsertionPoint' como distancias
// en byte al origen del fichero
//		- la ruta del fichero que hay que modificar se encuentra
// en 'currentGame.InFile'

int
ReplaceInFile(void)
{

	FILE * fi, * ff, * fg;
	char fichero1[MSG_SIZ];
	char fichero2[MSG_SIZ];
	char mensaje[MSG_SIZ];
	char * p;
	int punto = '.';
	unsigned long int trozo = 0L;
	int n = 0;
	int c = 0;

	fi = ff = fg = NULL;
	fichero1[0] = fichero2[0] = mensaje[0] = NULLCHAR;

	// comprobacionres relativas a la validez de
	// los datos de 'currentGame', que servirán de base
	// a las operaciones
	if ( ! (currentGame.recorded && currentGame.modified) ||
				currentGame.inFile[0] == NULLCHAR )
		return FALSE;

	// creación de un fichero temporal (se hace en 'C:\')
	// para albergar la partida modificada;
	// atribución de un nombre único
	tmpnam( fichero1 );
	if (fichero1[0] == NULLCHAR)
	{
		// caso de fallo
		MessageBox(NULL, noTempFile, "WinBoard",
							MB_OK|MB_ICONEXCLAMATION);
		return FALSE;
	}
	else
	{
		fi = fopen( fichero1, "a+b" );
		if (fi == NULL)
		{
			// caso de fallo
			MessageBox(NULL, noTempFile, "WinBoard",
							MB_OK|MB_ICONEXCLAMATION);
			return FALSE;
		}
	}


	// (no parece buena idea aplicar el método a las posiciones,
	// que por naturaleza son 'instantáneas', y en las que
	// resulta bastante arbitrario hablar de 'modificación'
	// y por ende mucho más peliagudo de detectar)
//	   if (partida)
			SaveGame(fi, 0, NULL);
//		else
//			SavePosition(fi);

	// creación de otro fichero temporal para la totalidad
	// de las partidas
	// atribución de un nombre único (se hace en 'C:\')
	tmpnam( fichero2 );
	if (fichero2[0] == NULLCHAR)
	{
		// caso de fallo
		MessageBox(NULL, noTempFile, "WinBoard",
							MB_OK|MB_ICONEXCLAMATION);
		// cerrar todos los archivos implicados
		fclose(fi);
		// eliminar los transitorios
		remove( fichero1 );
		return FALSE;
	}
	else
	{
		// creación y apertura en modo binario
		// escritura al final del archivo
		ff = fopen( fichero2, "a+b" );

		if (ff == NULL)
		{
			// caso de fallo
			MessageBox(NULL, noTempFile, "WinBoard",
							MB_OK|MB_ICONEXCLAMATION);
			// cerrar todos los archivos implicados
			fclose(ff);
			fclose(fi);
			// eliminar los transitorios
			remove( fichero1 );
			remove( fichero2 );
			return FALSE;
		}
	}

	// 1) copia de la parte inicial inmodificada,
	// si la hubiere, del fichero originario al temporal
	// abrir el fichero originario para copiar sus datos
	fg = fopen( currentGame.inFile, "rb" );

	if (fg == NULL)
	{
		// caso de fallo
		MessageBox(NULL, noOriginalFile, "WinBoard",
							MB_OK|MB_ICONEXCLAMATION);
		// cerrar todos los archivos implicados
		fclose(ff);
		fclose(fi);
		// eliminar los transitorios
		remove( fichero1 );
		remove( fichero2 );
		return FALSE;
	}

	if (currentGame.firstInsertionPoint > SEEK_SET)
	{
		if (currentGame.replace)
		{
			// copiar hasta el comienzo de la partida originaria
			trozo = 	BoundedFileCopy(fg, ff,
								currentGame.firstInsertionPoint);
			if ( (trozo - currentGame.firstInsertionPoint) != 0 )
			{
				// caso de fallo
				MessageBox(NULL, copyError, "WinBoard",
										MB_OK|MB_ICONEXCLAMATION);
				// cerrar todos los archivos implicados
				fclose(fg);
				fclose(ff);
				fclose(fi);
				// eliminar los transitorios
				remove( fichero1 );
				remove( fichero2 );
				return FALSE;
			}
		}
		else
		{
			// copiar hasta el final de la partida originaria
			trozo = 	BoundedFileCopy(fg, ff,
								currentGame.secondInsertionPoint);
			if ( (trozo - currentGame.secondInsertionPoint) != 0 )
			{
				// caso de fallo
				MessageBox(NULL, copyError, "WinBoard",
										MB_OK|MB_ICONEXCLAMATION);
				// cerrar todos los archivos implicados
				fclose(ff);
				fclose(fg);
				fclose(fi);
				// eliminar los transitorios
				remove( fichero1 );
				remove( fichero2 );
				return FALSE;
			}
		}
	}


	// 2) copia de la parte modificada
	fi = fopen( fichero1, "rb" );
	FileCopy(fi, ff);
	n = 1;
	n = fclose(fi);		// devuelve cero si todo va bien
	// eliminarlo, pues ya no sirve para nada;
	remove( fichero1 );

	// 3) copia de la parte final inmodificada, si la hubiere,
	// del fichero originario al temporal
	// sitúese el puntero de origen al final de la partida,
	// tanto si ha sido sustituida como si no
	// (el de destino sigue en su lugar correcto)
	fseek( fg, currentGame.secondInsertionPoint, SEEK_SET );
/*
	// (es demasiado eficaz; muerde en la primera línea siguiente)
	// saltarse las posibles líneas en blanco,
	// pues la nueva partida ya lleva las suyas
	while ( (c = getc(fg)) == '\n' || c == '\r' )
		;	// no hagamos nada más que avanzar el puntero
*/
  // a partir de ahí,	sígase la copia hasta el final 
	FileCopy(fg, ff);

	// cierre de ambos ficheros
	c = fclose(ff);
	c = fclose(fg);

	// renombramiento del fichero original a *.bak
	// creación de la sarta
	strcpy( fichero1, currentGame.inFile );

	//	Obtener la ruta y el nombre
	// del archivo de destino, crearlo y dejarlo abierto
	// para escritura destructiva;
	// predeterminar su nombre con el del archivo base
	if ( p = strrchr( fichero1, punto ) )
	{
		p++;
		* p = NULLCHAR;
		strcat( fichero1, "bak" );	
	}

	// determinar si existe un '.bak' anterior, abriéndolo;
	// si se logra, borrarlo inmediatamente
	// para que no falle la operación siguiente
	ff = fopen(fichero1, "rb");
	if (ff != NULL)
	{
		fclose(ff);
		remove( fichero1 );
	}

	// si el fichero original está abierto, no podrá renombrarse
	if (currentGame.opened != NULL)
	{
		c = fclose(currentGame.opened);
		if ( c != 0)
		{
			// caso de fallo
			sprintf( mensaje, closeFileError, currentGame.inFile );

			MessageBox(NULL, mensaje, "WinBoard",
										MB_OK|MB_ICONEXCLAMATION);
			return FALSE;
		}
	}

	c = rename( currentGame.inFile,  fichero1 );

	if (c != 0)
	{
		// caso de fallo
		sprintf( mensaje, renameError,
								currentGame.inFile, fichero1 );
		MessageBox(NULL, mensaje, "WinBoard",
										MB_OK|MB_ICONEXCLAMATION);
		return FALSE;
	}

	// renombramiento del fichero temporal al nombre originario
	c = rename( fichero2,  currentGame.inFile );

	if ( c != 0 )
	{
		sprintf( mensaje, renameError, fichero2, currentGame.inFile );
		// caso de fallo
		MessageBox(NULL, mensaje, "WinBoard",
										MB_OK|MB_ICONEXCLAMATION);
		return FALSE;
	}

	// reapertura del fichero y suplantación del originario
	if (currentGame.opened != NULL)
	{
		// suplantar el fichero originario con el nuevo
		fi = freopen(currentGame.inFile, "rb", currentGame.opened);
		if ( fi == currentGame.opened )
		{
			// rehacer la lista de recuperación de partidas
			UpdateRecordedData( &gameList );
		}
		else
		{
			currentGame.opened = NULL;
			// invalídense los punteros
			// de LoadGame(), por lo menos
			lastLoadGameFP = NULL;
			lastLoadGameNumber = 0;
			lastLoadGameUseList = FALSE;
			lastLoadGameTitle[0] = NULLCHAR;
		}
	}

	return TRUE;
}


// Kernighan-Ritchie, El lenguaje de programación C: 179.
// Copia el contenido del fichero previamente abierto 'origen'
// al fichero 'destino', también previamente abierto.
// Ambos ficheros continuan abiertos tras la operación.
// Tanto la lectura como la escritura se realizan
// a la altura en que se encuentren los indicadores de
// desplazamiento dentro de los respectivos ficheros
// en el momento de invocarse la función,
// aunque los autores no mencionan este decisivo aspecto,
// ni preven comprobaciones del resultado
void
FileCopy( FILE * origen, FILE * destino )
{
	int c;

   while ( (c = getc(origen)) != EOF )
		putc(c, destino);

}

// Copia 'limit' bytes del fichero 'origen'
// al fichero 'destino' desde y hacia las ubicaciones
// en que se encuentren al empezar dichos ficheros
// (salvo que 'origen' no sea tan largo,
// en cuyo caso la ejecución acaba con él)
// Devuelve el número de bytes transferidos
unsigned long int
BoundedFileCopy( FILE * origen, FILE * destino,
									unsigned long int limit )
{
	unsigned long int i = 0L;
	int c, j;

   while ( (i < limit) && (((c = getc(origen)) != EOF)) )
	{
		putc(c, destino);
		i++;
	}
	// si hay signos de nueva línea al final,
	// transferirlos también (pues 'yylex()'
	// es poco claro en este punto), pero sin
	// incluirlos en la cuenta
	// (la expresión es correcta; cfr. Kernighan-Ritchie: 46, 58)
//	while ( (c = getc(origen)) == '\n' || c == '\r' )
//			putc(c, destino);
	// limitarlo a dos pares o a 4 líneas, como máximo
	for ( j = 0; j < 4; j++ )
	{
		c = getc(origen);
		if ( c == '\n' || c == '\r' )
			putc(c, destino);
	}

	return i;
}

