/*
	MACHACA.C
	=========

	Uso:  machaca fichero tambloque nbloques nficheros [ventana]

fichero = ruta del fichero de pruebas
tambloque = tamaño de bloque físico
nbloques = número de bloques físicos
nficheros = máximo número de ficheros
ventana = tamaño de la ventana para evaluar la localidad de las referencias
	  a bloques físicos

	  Parámetros que probará José Miguel:
	  machaca fichero 500 1000 100 10
	  machaca fichero 500 1000 100 100

*/

#include "errores.h"
#include "sfbasico.h"
#include "sffisico.h"

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int SALIR_SI_ERROR = 0;

#define HECHO printf("hecho\n");

/* Funciones locales */

void prueba_lectura(WORD maxfich);
void prueba_escritura(WORD* maxfich);

int  crea_fichero(int nfich);
void lee_fichero(int nfich);
void escribe_fichero(int nfich);

WORD tam_fichero (int nf);
const char* nombre_fichero(int nf);

int lee_bloque (IFB ifb,int nf,int nb);
int escribe_bloque (IFB ifb,int nf,int nb);
void mensaje (const char* m,...);

#include <signal.h>

int contador=0;

void muestra()
{
  printf("contador=%d\n",contador);
  signal(SIGINT,muestra);
}


/**** MàDULO PRINCIPAL ****/


main (int argc,char* argv[])
{
  WORD tamblfis = atoi(argv[2]);
  DWORD numblfis = atol(argv[3]);
  WORD maxfich = atoi(argv[4]);
  char* args[3];
  int ventana = atoi(argv[5]);
  if (ventana==0) ventana=25;

  /* Crea el disco y lo formatea */
  printf("fabrico disco...");fflush(stdout);
  FabricaDisco(argv[1],tamblfis,numblfis);
  if (HAY_ERROR)
  {
    mensaje("no se pudo crear el disco");
    exit(1);
  }
  else HECHO

  printf("formateo el disco..."); fflush(stdout);
  args[0]=argv[4];
  args[1]="3";
  args[2]=0;
  FormateaSFB(argv[1],args);
  if (HAY_ERROR)
  {
    mensaje("no se pudo formatear el disco");
    exit(1);
  }
  else HECHO

  /* Monta el SF y crea varios ficheros */
  MontaSFB(argv[1],ventana);
  printf("pruebas de creación y escritura...");fflush(stdout);
  prueba_escritura(&maxfich);
  HECHO
  printf("pruebas de lectura...");fflush(stdout);
  prueba_lectura(maxfich);
  HECHO
  DesmontaSFB();

  /* Vuelve a montar el SF y hace una prueba de lectura */
  MontaSFB(argv[1],ventana);
  printf("repito pruebas de lectura...");fflush(stdout);
  prueba_lectura(maxfich);
  HECHO

  /* borra alg£n fichero y vuelve a hacer la prueba */
  printf("prueba de borrado selectivo...");fflush(stdout);
  {
    int nf = 13;
    IFB ifb = BuscaFB(nombre_fichero(nf));
    DestruyeFB(ifb);
    ifb = BuscaFB(nombre_fichero(nf));
    if (!HAY_ERROR && ifb!=NINGUN_IFB)
    {
      mensaje("Se permitió acceder al fichero borrado %d",nf);
    }
    crea_fichero(nf);
  }
  HECHO

  printf("comprobación de integridad tras el borrado...");fflush(stdout);
  prueba_lectura(maxfich);
  HECHO

  /* realiza lecturas aleatorias */
  signal(SIGINT,muestra);
  printf("acceso aleatorio al disco...");fflush(stdout);
  {
    for (contador=0;contador<1000;contador++)
    {
       lee_fichero(((unsigned)rand())%maxfich);
    }
  }
  HECHO
  DesmontaSFB();

  return 0;
} /* main */



/* Prueba de creaci¢n y escrituras en ficheros */


void prueba_escritura(WORD* maxf)
{
  int k;
  int maximo=*maxf;
  for (k=0;k<*maxf;k++)
  {
    int ok = crea_fichero(k);
    if (!ok) { maximo=k; break; }
  }

  /* Crea los restantes ficheros de longitud cero */
  for (k=maximo;k<*maxf;k++)
  {
    IFB ifb = CreaFB(nombre_fichero(k),0);
    if (HAY_ERROR || ifb==NINGUN_IFB)
    {
      mensaje("no se pudo crear el fichero %s",nombre_fichero(k));
      *maxf = maximo;
      return;
    }
  }
  *maxf = maximo;

  /* intenta escribir un fichero de m s */
  {
    IFB nf = CreaFB(nombre_fichero(*maxf+1),0);
    if (!HAY_ERROR && nf!=NINGUN_IFB)
    {
      mensaje("se permiti¢ crear un fichero de m s");
    }
  }
}



/* Prueba de lecturas de ficheros */


int crea_fichero (int k)
{
    IFB ifb;
    if (EspacioLibre()<TamBloqueDatos()*tam_fichero(k)) return 0;
    ifb = CreaFB(nombre_fichero(k),tam_fichero(k));
    if (HAY_ERROR || ifb==NINGUN_IFB)
    {
      mensaje("no se pudo crear el fichero %d",k);
      return;
    }
    escribe_fichero(k);
    return 1;
}


void prueba_lectura(WORD maxf)
{
  int k;
  for (k=0;k<maxf;k++)
  {
    lee_fichero(k);
  }
}



/* funciones b sicas de escritura y lectura en un fichero */


void escribe_fichero (int nf)
{
  int k;
  WORD maxbl;
  IFB ifb = BuscaFB(nombre_fichero(nf));
  if (HAY_ERROR || ifb==NINGUN_IFB)
  {
    mensaje("no se pudo acceder al fichero %d",nf);
  }
  maxbl = LongitudFB(ifb);
  if (HAY_ERROR)
    mensaje("problemas al leer la longitud del fichero %d",nf);
  if (maxbl!=tam_fichero(nf))
  {
    mensaje("longitud del fichero: %d bloques. Se esperaban %d bloque(s)",
	    maxbl,tam_fichero(nf));
    return;
  }

  /* bucle de escritura de los bloques */
  for (k=0;k<maxbl;k++)
  {
    escribe_bloque(ifb,nf,k);
  }

  /* intenta escribir un bloque incorrecto */
  {
    char* bufer = (char*)malloc(TamBloqueDatos());
    for (k=1;k<10;k++)
    {
      EscribeBloqueFB(ifb,maxbl+k,bufer);
      if (!HAY_ERROR)
      {
	mensaje("Se ha permitido escribir fuera de los l¡mites del fichero %d",nf);
	break;
      }
    }
    free(bufer);
  }

} /* escribe_fichero() */



void lee_fichero (int nf)
{
  int k;
  WORD maxbl;
  IFB ifb = BuscaFB(nombre_fichero(nf));
  if (HAY_ERROR || ifb==NINGUN_IFB)
  {
    mensaje("no se pudo acceder al fichero %d",nf);
    return;
  }
  maxbl = LongitudFB(ifb);
  if (HAY_ERROR)
    mensaje("problemas al leer la longitud del fichero %d",nf);
  if (maxbl!=tam_fichero(nf))
  {
    mensaje("longitud del fichero: %d bloques. Se esperaban %d bloque(s)",
	    maxbl,tam_fichero(nf));
    return;
  }

  /* comprueba la integridad de los bloques existentes */
  for (k=0;k<maxbl;k++)
  {
    lee_bloque(ifb,nf,k);
  }

  /* intenta leer un bloque incorrecto */
  {
    char* bufer = (char*)malloc(TamBloqueDatos());
    for (k=1;k<10;k++)
    {
      LeeBloqueFB(ifb,maxbl+k,bufer);
      if (!HAY_ERROR)
      {
	mensaje("Se ha permitido leer fuera de los l¡mites del fichero %d",nf);
	break;
      }
    }
    free(bufer);
  }

} /* lee_fichero() */


/* Da un nombre de fichero a partir de un n£mero */


const char* nombre_fichero (int nf)
{
 static char c [6];
 sprintf(c,"%04u",nf);
 return c;
}


/* Calcula un tama¤o variado de fichero */


WORD tam_fichero (int nf)
{
  return (nf&1)*10 + (nf%3==0)*5 + ((nf/4)&7)*30;
}


/* Escribe un bloque al azar */


int escribe_bloque (IFB ifb,int nf,int nb)
{
  int k;
  char patron[11];
  WORD tb;
  char* bufer;

  tb = TamBloqueDatos();
  if (tb==0) mensaje("tama¤o de bloque de datos incorrecto (%u)", tb);
  bufer = (char*)malloc(tb);
  if (!bufer)
  { mensaje("imposible ubicar memoria"); return 0; }

  sprintf(patron,"%04u.%04u#",nf,nb);
  for (k=0;k<tb-10;k+=10)
  {
    memcpy(bufer+k,patron,10);
  }

  EscribeBloqueFB(ifb,nb,bufer);
  if (HAY_ERROR)
  {
    mensaje("mala escritura del bloque %u del fichero %u",nb,nf);
  }
  free(bufer);
  return 1;
}

/* Lee un bloque al azar */


int lee_bloque (IFB ifb,int nf,int nb)
{
  int k;
  char* bufer;
  WORD tb = TamBloqueDatos();
  if (tb==0) mensaje("tama¤o de bloque de datos incorrecto (%u)",tb);
  bufer = (char*)malloc(tb);
  if (!bufer)
  { mensaje("imposible ubicar memoria"); return 0; }

  LeeBloqueFB(ifb,nb,bufer);
  if (HAY_ERROR)
  {
    mensaje("no se pudo leer el bloque %u del fichero %u",nb,nf);
    free(bufer);
    return 0;
  }

  for (k=0;k<tb-10;k+=10)
  {
    char num[5];
    num[4]=0;
    strncpy(num,bufer+k,4);
    if (atoi(num)!=nf)
    {
      mensaje("fichero %d - bloque %d incorrecto",nf,nb);
      break;
    }
    strncpy(num,bufer+k+5,4);
    if (atoi(num)!=nb)
    {
      mensaje("fichero %d - bloque %d incorrecto",nf,nb);
      break;
    }
    if ( bufer[k+4]!='.' || bufer[k+9]!='#' )
    {
      mensaje("fichero %d - bloque %d incorrecto",nf,nb);
      break;
    }
  }

  free(bufer);
  return 1;
}



void mensaje (const char* m,...)
{
  va_list args;
  va_start(args,m);
  fputs("ERROR: ",stderr);
  vfprintf(stderr,m,args);
  fputs("\n",stderr);
  if (SALIR_SI_ERROR) exit(1);
}