#include <io.h>
#include <dos.h>
#include <dir.h>
#include <direct.h>
#include <ctype.h>
#include <stdio.h>

#include <string.h>
#include <alloc.h>
#include <conio.h>
#include <stdlib.h>
#include <graphics.h>


#include "..\..\libs\make_bot\make_bot.h"
#include "frec.h"

extern CFG_FREC cfgFREC;
////////////////////////////////////////////////////////////////////////////
/***************************************************************************\
| Critical Disk Error handling routines (C) 1995 Jason Speight.             |
|	void interrupt critical_error_handler(__CPPARGS) is the interrupt which   |
|	captures disk io errors. (int 0x24, if you're interested!) Such errors    |
|	are : Disk not inserted in drive, seek error reading from a drive, general|
|	disk failure etc. The only things the interrupt does is :                 |
|		Suppress the dos ABORT,RETRY,FAIL,IGNORE statement                      |
|		Sets a variable erroroccurred to the dos error statement. (!=0)         |
|																																						|
|	StartCEH() and StopCEH() start and stop the error handler. YOU MUST       |
|	STOPCEH BEFORE THE EXIT OF THE PROGRAM. or else when you get a disk       |
|	error, the int 24 issued bu DOS points to the middle of nowhere! *HANG*   |
|																																						|
|	diskerror() is my routine to display a disk IO error. It also sets the    |
|	global variable erroroccurred to 0 for future use. This procedure also    |
|	needs access to "SCRNHNDL.H" and "BOXES.H"                                |
|																																						|
|	BTW, anybody know how to trap the message "PLEASE INSERT DISK FOR DRIVE x"|
\***************************************************************************/

void interrupt critical_error_handler(.../*__CPPARGS*/);	// interrupt prototype
void interrupt (*old_int24)(.../*__CPPARGS*/);			// interrupt function pointer
void startceh();
void stopceh();

int erroroccurred=0;

////////////////////////////////////////////////////////////////////////////

typedef struct {
 char files[13]   ;  //200 files, 12 byte filename (+1 for terminator!)
 long filesize    ; //Try as static.. free up that ram, bud.  (Use HUGE mem model)
 unsigned char attrs       ;
} SFile;

SFile *S_File;

void FileDownRow(void);
void FileUpRow(void)  ;
void PrintWholeScreen_Files(void);
void PrintSelectRow( char Hide_Show );

unsigned char FileRow = 0; int FileCurrTopRow = 0;
unsigned int maxfiles=0;
unsigned int rasterscan(char *fm);
char Archivo[13];
void PrintVisor(void);

char Optar( char *texto1, char *texto2, char *texto3 );

int InputCadenaG(char *s, int numalp, int lmax, int cc, int cf, int left, int up, int right, int down);

char file_browser( char *comodin_name, char *texto1, char Cargar_Salvar );

char file_browser( char *comodin_name, char *texto1, char Cargar_Salvar ){

 int ok = 0, inst = 0;
 struct textsettingstype textinfo;
 char oldpath[229]=" -- NONE -- ";				//internal. do not change
 unsigned char olddrive=255;					//impossible drive name
 char olddisk, key;

 startceh();

 FileRow = FileCurrTopRow = 0;

 olddrive = getdisk();
 getcwd( oldpath, 229 );

       void *C_Texto;

C_Texto    = malloc( JD_imagesize(240, 140, 400, 340) );
S_File     = (SFile *)malloc( sizeof(SFile) * 201 );

if( C_Texto == NULL || S_File == NULL )  {
 closegraph();
 cprintf("\n\rSALIENDO");
 cprintf("\n\rImposible encontrar %ldKbytes en el Heap", ( JD_imagesize(240, 140, 400, 340) + sizeof(SFile)*201 ) );
 return 0;
}

rasterscan( comodin_name );

gettextsettings(&textinfo);

getimage( 240, 140, 400, 340, C_Texto);


  Imprime_Estaticos( 10, "FREC.IMG");     // Imprime botones estaticos 'Seccion 20'



settextstyle( SMALL_FONT, HORIZ_DIR, 4);

setcolor( 1 );
outtextxy( 250+( ( 141 - textwidth(texto1) ) / 2 ), 150, texto1 );

PrintWholeScreen_Files();
PrintSelectRow( 1 );


while(!ok){				  // Bucle infinito

 switch( Comprueba_Secuencia( 4, NULL ) ) {     // Iniciamos comprobacion de 2¦ sec

       case  0:				  // No se pulso ningun BOTON
					  // Pero el raton fue presionado en
					  // algun sitio...
	       break;
       case -2:				  // Hay una tecla normal en BUFFER
	       switch( key = getch() ) {  // La utilizamos
		// ESC   ( CANCELAR )
		case 27:
			inst = 0;
			ok   = 1;
			break;
		case 13:
			switch( S_File[FileRow + FileCurrTopRow].attrs )
			{
			 // Si directorio: cambiamos simplemente
			 case FA_DIREC:
				chdir( S_File[FileRow + FileCurrTopRow].files );
				FileRow = FileCurrTopRow = 0;
				rasterscan( comodin_name );
				PrintWholeScreen_Files();
				PrintSelectRow( 1 );
			    break;
			 // Si unidad comprobamos que podemos cambiar y como directorio...
			 case 255:
				 erroroccurred=0;
				 olddisk=getdisk();
				 setdisk( (S_File[FileRow + FileCurrTopRow].files[0] - 'A') );
				 if (erroroccurred) {
					setdisk(olddisk);
				 } else {
				  FileRow = FileCurrTopRow = 0;
				  rasterscan( comodin_name );
				  PrintWholeScreen_Files();
				  PrintSelectRow( 1 );
				 }
			    break;
			 default:
			 if ( strcmp(Archivo, S_File[FileRow+FileCurrTopRow].files) == 0 )
			  {
			       if ( Cargar_Salvar == 0 ) {
				if ( access(Archivo, 0) != 0) break;
				 sprintf( comodin_name, "%c:\\", getdisk() + 'A' );
				 getcurdir(0,comodin_name+3);
				 strcat(comodin_name, "\\");
				 strcat(comodin_name, Archivo);
				 inst = 1;
				 ok   = 1;
			       }
			  }
			  strcpy(Archivo, S_File[FileRow+FileCurrTopRow].files);
			  PrintVisor();
			    break;
			}

			break;
		default:
			strcpy( Archivo, "\0" );
			ungetch(key);
			InputCadenaG(Archivo, 0, 12, 0, cfgFREC.F_Texto, 252, 171, 373, 178);
			if (Cargar_Salvar == 0)
			{
			 // Comprobamos que existe el fichero
			 if ( access(Archivo, 0) != 0)
			   strcpy( Archivo, "\0" );
			}
			 PrintVisor();
			break;
	       }
	       break;
       case -1:				  // Hay una tecla especial en BUFFER
	       getch();			  // La eliminamos
	       break;
       // Boton Aceptar
       case  2:
	       if ( Cargar_Salvar == 0 ) {
		if ( access(Archivo, 0) != 0) break;
		 sprintf( comodin_name, "%c:\\", getdisk() + 'A' );
		 getcurdir(0,comodin_name+3);
		 strcat(comodin_name, "\\");
		 strcat(comodin_name, Archivo);
		 inst = 1;
		 ok   = 1;
	       } else {
		if ( access(Archivo, 0) == 0)
		 if ( Optar( "Fichero Existe", "¨ Reemplazarlo ?","" ) == 0 ) break;
		  sprintf( comodin_name, "%c:\\", getdisk() + 'A' );
		  getcurdir(0,comodin_name+3);
		  strcat(comodin_name, "\\");
		  strcat(comodin_name, Archivo);
		  inst = 1;
		  ok   = 1;
	       }
	       break;
       // Boton Cancelar
       case  1:
	       inst = 0;
	       ok   = 1;
	       break;
       // Boton Subir
       case  3:
	       FileUpRow();
	       break;
       // Boton Bajar
       case  4:
	       FileDownRow();
	       break;
       default:
	       while( kbhit() ) getch();  // Limpiamos posibles teclas en BUFFER
	       break;
 }

}

putimage( 240, 140, C_Texto, COPY_PUT);

free ( C_Texto    );
free ( S_File     );

settextstyle(textinfo.font, textinfo.direction, textinfo.charsize );
settextjustify(textinfo.horiz, textinfo.vert);

 setdisk(olddrive);
 chdir(oldpath);


stopceh();

return inst;

}



unsigned int rasterscan(char *fm) {
	struct ffblk ffblk;
	char done=0;
	unsigned int olddisk;
	maxfiles = 0;

// build a disk drive availiable list
	olddisk=getdisk();
	for (int i=1;i<27;i++) if (_chdrive(i) == 0)
	{
			sprintf( S_File[maxfiles].files, "%c:", (char)('A' + i - 1) );
			S_File[maxfiles].filesize=0;
			S_File[maxfiles].attrs=255;	// Unidad
			if (ffblk.ff_attrib & 16) S_File[maxfiles].filesize=0;
			maxfiles++;

	}
	setdisk(olddisk);

//	drivelist[2]='N'; //stop access to B drive until I sort out pahntom dive probs
//Ok, Drive B may be a phantom drive. If you try to access drive B, then
//the program looses controll. Bummer!
// needs debugging. (always ignores drive b...)
//	asm int 0x11
//	asm mov equipmentlist,ax
//	drivelist[2]='N';
//	if ((equipmentlist & 16)) drivelist[2]='Y';


	done = findfirst("*.*",&ffblk,FA_DIREC);
	while (!done) {
		if (ffblk.ff_attrib == 0x10) {
			strcpy(S_File[maxfiles].files,ffblk.ff_name);
			S_File[maxfiles].filesize=ffblk.ff_fsize;
			S_File[maxfiles].attrs=ffblk.ff_attrib;
			if (ffblk.ff_attrib & 16) S_File[maxfiles].filesize=0;
			maxfiles++;
		}
			done = findnext(&ffblk);
			if (maxfiles==200) done=!done; //stop to prevent internal crashes.
	}

	done = findfirst(fm,&ffblk,FA_DIREC);
	while (!done)	{
		if (ffblk.ff_attrib != 0x10) {
			strcpy(S_File[maxfiles].files,ffblk.ff_name);
			S_File[maxfiles].filesize=ffblk.ff_fsize;
			S_File[maxfiles].attrs=ffblk.ff_attrib;
			if (ffblk.ff_attrib & 16) S_File[maxfiles].filesize=0;
			maxfiles++;
		}
		done = findnext(&ffblk);
		if (maxfiles==200) done=!done; //stop to prevent internal crashes.
	}
	if (maxfiles==0) { //no files to browse
		strcpy(S_File[0].files," -- NONE -- ");
		S_File[0].filesize=-1;
		maxfiles=1;}
	strcpy(S_File[200].files," -- NONE -- ");
	S_File[200].filesize=-1;
	return maxfiles;
}



void PrintWholeScreen_Files(void )
{

  int OldFileRow = FileRow ;
  char Contador;

  setfillstyle( SOLID_FILL, 0 );
  bar(252, 187, 374, 327);

  PrintSelectRow ( 0 );
	for ( FileRow = 0; FileRow < 14; FileRow++ )
		if ( ( FileRow + FileCurrTopRow ) < maxfiles )
						  PrintSelectRow ( 0 );


  FileRow = OldFileRow;


}

void PrintSelectRow( char Hide_Show )
{

  char Buffer[80];
    char Buff1[80];
	char Buff2[80];

  if ( Hide_Show==0 )
  {
     setfillstyle( SOLID_FILL, 0 );
     bar(252, 188 + ( FileRow * 10 ) , 373, 187 + 10 + ( FileRow * 10 ) );
     setcolor( cfgFREC.Texto );
  } else {
     setfillstyle( SOLID_FILL, cfgFREC.F_Texto );
     bar(252, 188 + ( FileRow * 10 ) , 373, 187 + 10 + ( FileRow * 10 ) );
     setcolor(0);
  }

switch( S_File[FileRow + FileCurrTopRow].attrs )
{
 case FA_DIREC:
           sprintf(Buffer, "%-13s", S_File[FileRow+FileCurrTopRow].files );
           sprintf(Buff1 , "              < DIR >"                       );
         break;
 case 255:
           sprintf(Buffer, "%-8s", strncpy( Buff1, S_File[FileRow+FileCurrTopRow].files, 8) );
           sprintf(Buff1 , "             >DRIVER<"                                         );
        break;
 default:

           sprintf(Buffer, "%-13s",        S_File[FileRow+FileCurrTopRow].files);
//           outtextxy( 252 , 187 + ( FileRow * 10 ) , Buffer );
           sprintf(Buff1 , "             %7lu", S_File[FileRow+FileCurrTopRow].filesize );
	break;
}

  outtextxy( 252 , 187 + ( FileRow * 10 ) , Buffer );
  outtextxy( 252 , 187 + ( FileRow * 10 ) , Buff1  );

}

void FileDownRow(void)
{

 // ¨¨ Estoy en la linea fisica 000 ???
 if ( (FileRow + FileCurrTopRow) != (maxfiles - 1) ) {

    // Linea 0, Baja Con retroceso multiple
    if ( FileRow == 13 ) {
	FileCurrTopRow += 14;
	while ( (FileCurrTopRow + FileRow) > maxfiles ) FileCurrTopRow--;
	FileRow =  0;
	PrintWholeScreen_Files();
	PrintSelectRow( 1 );
    } else {
	PrintSelectRow( 0 );
	FileRow++;
	PrintSelectRow( 1 );
    }

 }
}

void FileUpRow(void)
{

 // ¨¨ Estoy en la linea fisica 000 ???
 if ( (FileRow + FileCurrTopRow) != 0 ) {

    // Linea 0, Baja Con retroceso multiple
    if ( FileRow == 0 ) {
	FileCurrTopRow -= 14;
	if ( FileCurrTopRow < 0 ) FileCurrTopRow = 0;
	FileRow =  0;
	PrintWholeScreen_Files();
	FileRow = 13;
	PrintSelectRow( 1 );
    } else {
	PrintSelectRow( 0 );
	FileRow--;
	PrintSelectRow( 1 );
    }

 }
}



/*
void diskerror(void) {
char message[30];
	pushscreen();
	draw3dboxup(19,10,43,6);
	draw3dboxdn(21,11,39,4);
	switch (erroroccurred) {
		case 1 : strcpy(message,"Write Protected Disk"); break;
		case 2 : strcpy(message,"Drive Not Ready"); break;
		case 3 : strcpy(message,"Unknown Command"); break;
		case 4 : strcpy(message,"Data Error (CRC)"); break;
		case 5 : strcpy(message,"Bad Request Structure Length"); break;
		case 6 : strcpy(message,"Seek Error"); break;
		case 7 : strcpy(message,"Unknown Media Type"); break;
		case 8 : strcpy(message,"Sector Not Found"); break;
		case 9 : strcpy(message,"Printer Out Of Paper"); break;
		case 10: strcpy(message,"Write Fault"); break;
		case 11: strcpy(message,"Read Fault"); break;
		case 12: strcpy(message,"General Failure"); break;
		default: strcpy(message,"Unknown Error");
	}

	printcentered(12,"Error - Press any key to continue",0x74);
	printcentered(13,message,0x70);
	getch();
	popscreen();
	erroroccurred=0;
}
*/

void interrupt critical_error_handler(.../*__CPPARGS*/) {
	asm push ax               //preserve only modified register
	asm mov ax,di							//di holds error code ranging from 0 to 0x0c
//	asm inc ax
	asm mov erroroccurred,ax	//increase erroroccurred for ease of programming
	asm mov al,0x20
	asm out 0x20,al  					//send interrupt clear flag
//  asm pushf									// I think I dont need this line in....
	asm pop ax								//restore ax
}

void startceh() {
	old_int24 = _dos_getvect( 0x24 );
	_dos_setvect( 0x24, critical_error_handler);
	}

void stopceh() {
	_dos_setvect(0x24,old_int24);
	}

void PrintVisor(void)
{

     setfillstyle( SOLID_FILL, 0 );
     bar(252, 171, 373, 178);
     setcolor( cfgFREC.Texto );
     outtextxy(252, 169, strupr(Archivo) );

}



//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
int InputCadenaG(char *s, int numalp, int lmax, int cc, int cf, int left, int up, int right, int down)
{

  int  ls;                                      // longitud cadena
  char *s1;                                     // puntero a cadena inicial
  int c, ok = 0;

  s1 = s;                                       // inicio cadena
  ls = strlen ( s );                            // Longitud de actual
  s += ls;                                      // se coloca en el final

			setfillstyle(SOLID_FILL, cf);
  do{
			bar(left, up, right, down);
			setcolor(cc);
			outtextxy( left, up-2, s1 );
			if ( ls < lmax ) {
				setcolor(4);
				outtextxy( left+textwidth( s1 ), up-2, "<");
			}


	switch( c = getch() )                   // obtiene tecla
	 {
	  case  0:
	  case 13:
		  ok = 1;                       // 13 = INTRO || Especiales
		  break;
	  case  8:
		  if ( ls > 0 ) {  	 	//  8 = Back Space
		   ls--;
		   s--;
		   *s = '\0';
		  }
		  break;
	  case 27:
		  *s='\0';
		  ok = 1;
		  break;
	  default:
		  if ( !numalp && c >= 32 && c <= 254 && ls < lmax)
		  {
			*s++ = toupper(c);
			ls++;
			*s = '\0';
		  } else
		  if ( numalp && isdigit(c)  && ls < lmax) {
				*s++ = c;
				ls++;
				*s = '\0';
		  }
		  break;
	 }

  }while(!ok);

  ok = 1;
  *s = ' ';
  while( ok ) {
		if(*s==' ') { *s = '\0'; s--;
		} else { s++; ok = 0; }
  }

  *s = '\0';

  while(kbhit()) getch();              // Vacia Buffer impidiendo falsas
				       //  pulsaciones...

  return ls;
}
