#include "includes.h"
 
 Parameter *FileIO_Parm;
 
/**************************************|****************************************
Routine   : SaveTrans
Input  par: Transformation *T (pointer to trans)
            char *file        (filename)
            int dx            (delta x)
            int dy            (delta y)
Output par: none
Function  : Saves transformation plus all its sub-transformation.
***************************************|***************************************/
 
 void SaveTrans3D(Transformation *T,char *file, int delta)
  {
   unsigned char out[]="dummy",temp,main=TRUE;
   unsigned int i,j,k;
   
   if (T->Sub!=NULL) main=FALSE; /* check subblock configuration */
   
   out[0]=main;
   IOBitArray(FILE_APPEND,file,FileIO_Parm->SBits,out); /* par/subs */
   
   if (main) /* should we save the transformation ? */
    {
     switch(T->Type)
      {
       case EDGEBLOCK : 
       out[0]=0x00;  /* Type bit = 00 b */
       IOBitArray(FILE_APPEND,file,1,out);
       out[0]=(unsigned char)(T->Domain->x/delta);
       IOBitArray(FILE_APPEND,file,FileIO_Parm->XBits,out);
       out[0]=(unsigned char)(T->Domain->y/delta);
       IOBitArray(FILE_APPEND,file,FileIO_Parm->YBits,out);
       out[0]=(unsigned char)(T->Domain->z/delta);
       IOBitArray(FILE_APPEND,file,FileIO_Parm->ZBits,out);
       out[0]=MakeRange(T->Alpha,FileIO_Parm);
       IOBitArray(FILE_APPEND,file,FileIO_Parm->ABits,out);
       
       if (T->Deltag<0) 
        {
         temp=-T->Deltag;
         out[0]=1;
        }
       else 
        {
         temp=T->Deltag;
         out[0]=0;
        }
       IOBitArray(FILE_APPEND,file,1,out); /* save sign */
       out[0]=temp;
       IOBitArray(FILE_APPEND,file,FileIO_Parm->DBits,out);
       
       out[0]=(unsigned char)(T->tn);
       IOBitArray(FILE_APPEND,file,FileIO_Parm->TBits,out);
       break;
       
       case SHADEBLOCK :
       out[0]=0x01;  /* Type bit = 10 b */
       IOBitArray(FILE_APPEND,file,1,out);
       out[0]=(unsigned char)(T->g0);
       IOBitArray(FILE_APPEND,file,FileIO_Parm->GBits,out);
       break;
       
       default : ErrorHandler(OUT_OF_RANGE,"Unknown block type in SaveFC");
       break;
      }
    }
   else
   for(i=0;i<2;i++)
   for(j=0;j<2;j++)
   for(k=0;k<2;k++) SaveTrans3D(T->Sub[i][j][k],file,delta);
   
  }
 
/**************************************|****************************************
Routine   : SaveFC
Input  par: Transformation ***T (pointer to 2D array of Transformation pointers)
            char *file          (filename)
            LimboHeader TheHead (header structure with current header info)
Output par: none
Function  : Saves all transformation in T[][] to file. Saves FC-header + FC-Code
***************************************|***************************************/
 
 void SaveFC3D(Transformation ****T, char *file, LimboHeader *Head)
  {
   int i,j,k,x,y,z,delta,B,nsquare;
   unsigned char out[]="dummy";
   char savefile[99];
   FILE *headfile;
   
   strcpy(savefile,FCCODE);
   strcat(savefile,file);
   strcat(savefile,".lmb");
   
   vprintf(stderr,"\nSaving fractal code...\n   File:'%s'",savefile);
   
   HeadInfo3D(T,Head);
   
   FileIO_Parm=GimmeAParameter();
   FileIO_Parm->XBits=Head->XBits;
   FileIO_Parm->YBits=Head->YBits;
   FileIO_Parm->ZBits=Head->ZBits;
   FileIO_Parm->SBits=Head->SBits;
   FileIO_Parm->ABits=Head->ABits;
   FileIO_Parm->AMax =Head->AMax/100.0;
   FileIO_Parm->AMin =Head->AMin/100.0;
   FileIO_Parm->DBits=Head->DBits;
   FileIO_Parm->GBits=Head->GBits;
   FileIO_Parm->TBits=Head->TBits;
   
   x=Head->MSBx*256+Head->LSBx;
   y=Head->MSBy*256+Head->LSBy;
   z=Head->MSBz*256+Head->LSBz;
   delta=Head->Delta;
   B=Head->B;
   nsquare=Head->NSquare;
   
   if ((headfile=fopen(savefile,"wb")) == NULL) 
   ErrorHandler(UNABLE_TO_OPEN,"SaveFC could not open file");
   fprintf(headfile,"LIMBO:%s\n",LIMBOVERSION);
   fwrite((void *)Head,sizeof(LimboHeader),1,headfile);
   if (fclose(headfile)) ErrorHandler(UNABLE_TO_CLOSE,"SaveFC could not close file");
   
   IOBitArray(FILE_OPENAPPEND,savefile,0,out); /* open for FCCode */
   for (i=0;i<x/(B<<nsquare);i++)  
   for (j=0;j<y/(B<<nsquare);j++)
   for (k=0;k<z/(B<<nsquare);k++)
   SaveTrans3D(T[i][j][k],savefile,delta);  /* save transformations */
   
   out[0]='X';
   IOBitArray(FILE_APPEND,file,8,out); /* end */
   IOBitArray(FILE_CLOSE,savefile,0,out);
  }
 
/**************************************|****************************************
Routine   : LoadTrans
Input  par: char *file (filename)
            int B      (B-blocksize)
            int D      (D-blocksize)
            int dx     (delta x)
            int dy     (delta y)
Output par: Transformation * (pointer to transformation loaded)
Function  : Loads transformation from file. Loads main transformation plus 
            recursive load of all sub-blocks.
***************************************|***************************************/
 
 Transformation *LoadTrans3D(char *file, int B, int D, int delta)
  {
   Transformation *T;
   unsigned char in[99],sign,main=TRUE;
   int type;
   
   T=GimmeATransformation();    /*dynamic allocation of tranformation */
   T->Type=NOBLOCK;
   T->D=D;
   T->BlockSize=B;
   
   if (FileIO_Parm->SBits) 
    {
     IOBitArray(FILE_READ,file,FileIO_Parm->SBits,in); /* parent/sub bit */
     main=in[0]; /* remember subblock */ 
    }
   
   if (main) /* read trans ? if this is a main */               
    {
     T->Domain=GimmeAPoolNode();
     
     IOBitArray(FILE_READ,file,1,in);
     if (in[0]==0x00)      type=EDGEBLOCK;
     else if (in[0]==0x01) type=SHADEBLOCK;
     else ErrorHandler(OUT_OF_RANGE,"Unknown block type in LoadFC");
     
     switch(type)
      {
       case EDGEBLOCK :
       T->Type=EDGEBLOCK;
       T->D=D;
       T->BlockSize=B;
       IOBitArray(FILE_READ,file,FileIO_Parm->XBits,in);
       T->Domain->x=in[0]*delta;
       IOBitArray(FILE_READ,file,FileIO_Parm->YBits,in);
       T->Domain->y=in[0]*delta;
       IOBitArray(FILE_READ,file,FileIO_Parm->ZBits,in);
       T->Domain->z=in[0]*delta;
       IOBitArray(FILE_READ,file,FileIO_Parm->ABits,in);
       T->Alpha=MakeFloat(in[0],FileIO_Parm);
       
       IOBitArray(FILE_READ,file,1,in);
       sign=in[0];
       IOBitArray(FILE_READ,file,FileIO_Parm->DBits,in);
       if (sign==0) T->Deltag=in[0];
       else T->Deltag = -in[0];
       
       IOBitArray(FILE_READ,file,FileIO_Parm->TBits,in);
       T->tn=in[0];
       break;
       
       case SHADEBLOCK :
       T->Type=SHADEBLOCK;
       T->D=D;
       T->BlockSize=B;
       IOBitArray(FILE_READ,file,FileIO_Parm->GBits,in);
       T->g0=(int)in[0];
       break;
       
       default : ErrorHandler(OUT_OF_RANGE,"Unknown block type in LoadFC");
       break;
      }
    }
   else /* load subblock configuration */
    {
     int i,j,k;
     T->Sub=GimmeATransArray3D(2,2,2);
     
     for(i=0;i<2;i++) 
     for(j=0;j<2;j++) 
     for(k=0;k<2;k++) T->Sub[i][j][k]=LoadTrans3D(file,B>>1,D>>1,delta);
    }
   
   return T;
  }
 
/**************************************|****************************************
Routine   : LoadFC
Input  par: Transformation ***T (pointer to 2D array of Transformation pointers,
                                 will be filled with the loaded transformations)
            char *file          (filename)
            int infoflag        (fractal code info for file flag. 1=info 0=noinfo)
Output par: LimboHeader Head (header structure with new file info)
Function  : Reads FC-code from file. Read FC Header. Allocates transformations.
            Reads p/c configuration plus fractal code. Stores code in allocated
            transformations. Returns header structure with file info.
****************************************|***************************************/
 
 LimboHeader *LoadFC3D(Transformation *****T, char *file)
  {
   FILE *infile;
   int i,j,k,x,y,z,delta,size,B,nsquare;
   unsigned char in[99],limbo[20];
   char loadfile[99];
   LimboHeader *Head=GimmeALimboHeader();
   
   strcpy(loadfile,FCCODE);
   strcat(loadfile,file);
   strcat(loadfile,".lmb");
   
   vprintf(stderr,"\nLoading fractal code...\n   File:'%s'",loadfile);
   
   if ((infile=fopen(loadfile,"rb")) == NULL)
   ErrorHandler(UNABLE_TO_OPEN,"LoadFC could not open file");
   fgets(limbo,LIMBOSTRINGSIZE,infile);             /* read version */
   
   if ((strncmp(limbo,"LIMBO:",5))) 
    {
     char msg[40];
     strcpy(msg,"Could not read file ");
     strcat(msg,loadfile);
     ErrorHandler(UNKNOWN_FORMAT,msg);
    }
   vprintf(stderr,"\n   Version: %s",limbo);
   fread(Head,sizeof(LimboHeader),1,infile);    /* read header */
   
   size=Head->HeadSize;
   
   FileIO_Parm=GimmeAParameter();
   FileIO_Parm->XBits=Head->XBits;
   FileIO_Parm->YBits=Head->YBits;
   FileIO_Parm->ZBits=Head->ZBits;
   FileIO_Parm->SBits=Head->SBits;
   FileIO_Parm->ABits=Head->ABits;
   FileIO_Parm->AMax =Head->AMax/100.0;
   FileIO_Parm->AMin =Head->AMin/100.0;
   FileIO_Parm->DBits=Head->DBits;
   FileIO_Parm->GBits=Head->GBits;
   FileIO_Parm->TBits=Head->TBits;
   
   x=Head->MSBx*256+Head->LSBx;
   y=Head->MSBy*256+Head->LSBy;
   z=Head->MSBz*256+Head->LSBz;
   delta=Head->Delta;
   B=Head->B;
   nsquare=Head->NSquare;
   *T=GimmeATransArray3D(x/(B<<nsquare),y/(B<<nsquare),z/(B<<nsquare));
   
   IOBitArray(FILE_OPENREAD,loadfile,0,in);
   IOBitArray(FILE_READ,loadfile,size*8-8,in);  /* skip header */
   
   for (i=0;i<x/(B<<nsquare);i++)
   for (j=0;j<y/(B<<nsquare);j++)
   for (k=0;k<z/(B<<nsquare);k++) 
   (*T)[i][j][k]=LoadTrans3D(loadfile,B<<nsquare,B<<(nsquare+1),delta);
   
   IOBitArray(FILE_READ,file,8,in); /* end */
   if (in[0]!='X') ErrorHandler(ERROR_READING,"LoadFC could not find tail in FCfile");
   IOBitArray(FILE_CLOSE,loadfile,0,in);
   
   return Head;
  }
