//
//       Manejo de informacion a "disco"
//
#include "H\General.H"
#include "H\Disco.h"
#include "H\Credito.h"
#include "H\Efectivo.h"
#include "H\Gastos.h"
#include "H\Inst.h"
#include "H\Prog.h"
#include "H\Bancos.h"


static DmOpenRef    ApArc=0;
static UInt32       TotReg=0;
static UInt16       IDMax=0;
static MemPtr       ApRM,ApMM;
static MemHandle    HRM,HMM;
static ID           IDAct;

typedef struct DTMOV {
	Int16    TMov;       // Total de movimientos
    Int32    UltID;      // Ultimo ID
	Char     Mov[1];     // Movimientos
} TMOV;	

//   ****    Desplegar errores en disco

void ErrorBD (UInt16 Fun, UInt16 NumLet, Err Error)
{
	Char DescNumErr[maxStrIToALen];
	Char DescFun[3];
	Char DescLetErr[50];
	SysStringByIndex(9000,Fun-1,DescFun,3);
    SysStringByIndex(9000,NumLet+14,DescLetErr,50);
    StrIToA(DescNumErr, Error);
    FrmCustomAlert(9000, DescFun, DescLetErr, DescNumErr);
}

//   ****    Sacar aputandor registro mayor y movimiento mayor

MemPtr  SacarApRM() {
	    return ApRM;
}
MemPtr  SacarApMM() {
	    return ApMM;
}

//   ****    Sacar tipo de registro de *ApRM*

UInt8   SacarTpApRM() { 
INF  *  inf;
        inf=ApRM; 
        return inf->TReg; 
}

//   ****    Sacar longitud de registros

Int16 SacarLonReg(Int16 tr,Int16 nr) {
	Int16 lon = 0;
	switch (tr) {
		case 1:
	   	   lon=sizeof(CRE);
		   break;
		case 2:
	   	   lon=sizeof(EFE);
		   break;
		case 3:
	   	   lon=sizeof(GA);
		   break;
		case 4:
	   	   lon=sizeof(IN);
		   break;
		case 5:
	   	   lon=sizeof(GA);
		   break;
		case 6:
	   	   lon=sizeof(PROG);
		   break;
		case 7:
	   	   lon=sizeof(REGBA);
		   break;
		default:
           ErrorBD(nr,7,0);
		   break;
	}
	return lon;
}

//    ****    Sacar longitud de movimientos

Int16 SacarLonMov(Int16 tr,Int16 nr) {
	Int16 lon = 0;
	switch (tr) {
		case 1:
		   lon=sizeof(MOVC);
		   break;
		case 2:
		   lon=sizeof(MOVEF);
		   break;
		case 3:
		   lon=sizeof(MOVGA);
		   break;
		case 4:
	   	   lon=sizeof(MOVIN);
		   break;
		case 5:
	   	   lon=sizeof(MOVGA);
		   break;
		case 6:
	   	   lon=0;
		   break;
		case 7:
	   	   lon=sizeof(MOVBA);
		   break;
		default:
           ErrorBD(nr,7,0);
		   break;
	}
	return lon;
}

//   ****    Sacar longitud maxima 1=reg 2=mov

Int16   SacarLonMax (Int16 Op) {
Int16   i,LM,lon;
        LM=0;
        for (i=0;i<NumTipoReg;i++) {
        	if(Op==1) {
        		lon=SacarLonReg(i+1,0);	
                if(lon>LM) LM=lon;
        	} else {
        		lon=SacarLonMov(i+1,0);	
                if(lon>LM) LM=lon;
        	}
        }
        return LM;
}	

//   ****    Sacar total de registros

Int16 SacarTotReg() {
	  return TotReg;
}

//   ****    Validar numero de registro

Boolean  ValNReg (Int16 NReg, Int16 nr){
      if(NReg >= 0 && NReg < TotReg) return true;
      ErrorBD(nr,5,0);
      return false;
}

	
//   ****    Inicio: Abrir archivos y sacar total de registros

void InicioBD()
{
    Err       Error      = errNone;
    UInt16    CardNo     = 0;
    Char      FinNom[32] = "Sistema-Finanzas";
    UInt32    Creador    = 'PFM1';
    UInt32    Tipo       = 'SFSF';
    UInt16    Modo       = dmModeReadWrite;
    LocalID   DBID;
	Int16     i,Lon;
    MemHandle HReg;
    UInt8     *ApReg;    
    UInt8     TReg;
    UInt16    IDMaxR;
    
//  Sacar apuntador de registro mayor y movimiento mayor

     HRM = MemHandleNew(SacarLonMax(1));
     if (HRM==0) ErrorBD(1,16,0);
     ApRM=MemHandleLock(HRM);
     HMM = MemHandleNew(SacarLonMax(2));
     if (HMM==0) ErrorBD(1,16,0);
     ApMM=MemHandleLock(HMM);
    
//  Abrir, si da error, crear.    
    
    ApArc = DmOpenDatabaseByTypeCreator(Tipo, Creador, Modo);
    if (ApArc==0) {
        Error = DmCreateDatabase(CardNo, FinNom, Creador, Tipo, false);
        if (Error!=errNone) {
            ErrorBD(1,1,Error);
            return;
        }
        ApArc = DmOpenDatabaseByTypeCreator(Tipo, Creador, Modo);
        if (ApArc==0) {
   	        Error = DmGetLastErr();
            ErrorBD(1,2,Error);
            return;
        }
        TotReg = 0;
        IDMax=0;
        return;
    }
    
//   Sacar total de registros    
    
    Error=DmOpenDatabaseInfo(ApArc, &DBID, NULL, NULL, &CardNo, NULL);
    if (Error==errNone) Error=DmDatabaseSize(CardNo, DBID, &TotReg, NULL, NULL);
    if (Error!=errNone )  {
        ErrorBD(1,3, Error);
        ApArc=0;
        TotReg=0;
        return;
    }
    
//  Sacar ID maximo    

    for (i=0;i<TotReg;i++) {
        HReg=DmQueryRecord(ApArc, i);
        if (HReg == NULL ) {
           Error = DmGetLastErr();
           if(Error == dmErrRecordArchived || 
              Error == dmErrRecordDeleted  )continue;
           ErrorBD(1,8, Error);
           return;
        }
        ApReg = MemHandleLock(HReg);
        MemMove (&TReg,ApReg,1);
        Lon=SacarLonReg(TReg,1);
        ApReg=ApReg+Lon;
        MemMove (&IDMaxR,ApReg,2);
        MemHandleUnlock(HReg);
        if(Lon==0) continue;
        if(IDMaxR > IDMax) IDMax=IDMaxR;
    }
    return;
}

//   ****    Fin:  Cerrar archivos

void FinBD()
{
    Err Error = DmCloseDatabase(ApArc);
    if (Error!=errNone) {
        ErrorBD(2,4, Error);
    }
    ApArc=0;
    MemHandleUnlock(HRM);   
    MemHandleFree(HRM);
    MemHandleUnlock(HMM);   
    MemHandleFree(HMM);
}

//   ****    Leer registro
//           Si esta borrado se regresa tipo de registro en cero

Boolean LeerReg (INF *ApInf, UInt16 NReg) {
    Err         Error;
    MemHandle   HReg;
    INF         *ApReg;
    Int32       Lon;
    UInt8       *ApID;
    
//  Leer un registro, revisa borrado    

    if(!ValNReg(NReg,3)) return false;
    HReg=DmQueryRecord(ApArc, NReg);
    if (HReg == NULL ) {
        Error = DmGetLastErr();
        if(Error == dmErrRecordArchived || 
           Error == dmErrRecordDeleted  ){
              ApInf->TReg = 0; 
              return true;
        }
        ErrorBD(3,8, Error);
        return false;
    }
    
//  Pasar la informacion    
    
    ApReg = MemHandleLock(HReg);
    Lon = SacarLonReg((Int16)ApReg->TReg,3);
    if( Lon > 0 ) {
    	MemMove (ApInf,ApReg,Lon);
    	ApID=(UInt8*)ApReg+Lon;
    	MemMove (&IDAct.r,ApID,2);
    	IDAct.m=0;
    }
    MemHandleUnlock(HReg);
    if (Lon == 0) return false;
    return true;
}

//   ****    Modificar registro 

Boolean ModReg (INF *ApInf, UInt16 NReg) {
    Err         Error;
    MemHandle   HReg;
    INF         *ApReg;
    Int32       Lon;
    Char        TRO;
    UInt8       *ApID;
    
//   Leer un registro    

    if(!ValNReg(NReg,4)) return false;
    HReg = DmGetRecord(ApArc, NReg);
    if (HReg == NULL) {
        Error = DmGetLastErr();
        ErrorBD(4,9, Error);
        return false;
    } 
    
//  Revisa mismo tipo    
    
    ApReg = MemHandleLock(HReg);
    MemMove (&TRO,ApReg,1);
    if (TRO != ApInf->TReg) {
        ErrorBD(4,18, 0);
  	    MemHandleUnlock(HReg);
  	    return false;
    }
    
//  Modificarlo y unlock    
    
    Lon = SacarLonReg((Int16)ApInf->TReg,4);
    if( Lon > 0 ){
    	 Error = DmWrite(ApReg, 0, ApInf, Lon);
     	 ApID=(UInt8*)ApReg+Lon;
    	 MemMove (&IDAct.r,ApID,2);
    	 IDAct.m=0;
    }
    MemHandleUnlock(HReg);
    if (Lon == 0) return false;
    if (Error!=errNone) {
        ErrorBD(4,10, Error);
        return false;
    }
    Error = DmReleaseRecord(ApArc, NReg, true);
    if (Error!=errNone) {
        ErrorBD(4,11, Error);
        return false;
    }
    return true;
}

//   ****    Insertar un nuevo registro

Boolean InsReg (INF *ApInf) {
    Err         Error;
    MemHandle   HReg;
    INF        *ApReg;
    UInt16     NReg = dmMaxRecordIndex;
    Int32      Lon;

    Lon = SacarLonReg((Int16)ApInf->TReg,5);
    if (Lon == 0) return false;
    HReg = DmNewRecord(ApArc, &NReg, Lon+8);
    if (HReg == 0) {
        Error = DmGetLastErr();
        ErrorBD(5,12,Error);
        return false;
    }
    ApReg = MemHandleLock(HReg);
    Error=DmWrite(ApReg, 0, ApInf, Lon);
    IDMax++;
    IDAct.r=IDMax;
    IDAct.m=0;
    if (Error==errNone) Error = DmWrite(ApReg,Lon,&IDMax,2);
    if (Error==errNone) Error = DmSet(ApReg,Lon+2,6,0);
    MemHandleUnlock(HReg);
    if (Error!=errNone) {
        ErrorBD(5,10,Error);
        return false;
    }
    Error = DmReleaseRecord(ApArc, NReg, true);
    if (Error!=errNone) {
        ErrorBD(5,11, Error);
        return false;
    }
    TotReg++;
    return true;
}

//  ****    Borrar un registro ind = true  borrarlo totalmente
//                                 = false marcar borrado para proxima syc

Boolean BorReg (UInt16 NReg, Boolean Ind) {
	Err         Error;
	
    if(!ValNReg(NReg,6)) return false;
    if(Ind) {
        Error = DmRemoveRecord(ApArc,NReg);
        if (Error!=errNone) {
            ErrorBD(6,13,Error);
            return false;
        }
        TotReg--;
    } else {
    	Error = DmArchiveRecord(ApArc,NReg);
        if (Error!=errNone) {
            ErrorBD(6,14,Error);
            return false;
        }
    }
    return true;
}

//   ****    Total de Movimientos

Boolean TotMov (UInt16 NReg, Int16 *ApTMov) {
    Err         Error;
    MemHandle   HReg;
    INF         *ApReg;
    UInt8       *ApNM;
    Int32       Lon;

    if(!(ValNReg(NReg,7))) return false;
    HReg=DmQueryRecord(ApArc, NReg);
    if (HReg == NULL ) {
        Error = DmGetLastErr();
        ErrorBD(7,8, Error);
        return false;
    }
    ApReg = MemHandleLock(HReg);
    Lon = SacarLonReg((Int16)ApReg->TReg,7);
    if (Lon > 0) {
    	ApNM = (UInt8*)ApReg + Lon + 2;
    	MemMove (ApTMov,ApNM,2);
    } 
    MemHandleUnlock(HReg);
    if (Lon == 0) return false;
    return true;
}

Int16 SacarTotMov(UInt16 NReg) {
	Int16 TMov;
	if(TotMov(NReg,&TMov)) return TMov; else return 0;
}

//   ****    Leer movimientos

Boolean LeerMov (MOV *ApMov, UInt16 NReg, Int16 NMov, Boolean * IndB) {
    Err         Error;
    MemHandle   HReg;
    INF         *ApReg;
    UInt8       *ApNM;
    UInt8       IndMov;
    Int32       Lon,LonM;
    Int16       TMov;
    Boolean     Cont = true;
    
//  Leer registro y sacar longitudes 

    if(!(ValNReg(NReg,8))) return false;
    HReg=DmQueryRecord(ApArc, NReg);
    if (HReg == NULL ) {
        Error = DmGetLastErr();
        ErrorBD(8,8, Error);
        return false;
    }
    ApReg = MemHandleLock(HReg);
    Lon = SacarLonReg((Int16)ApReg->TReg,8);
    if (Lon == 0) Cont = false;
  	LonM = SacarLonMov((Int16)ApReg->TReg,8);
    if (LonM == 0) Cont = false;
    
//  Total de movimientos, indicador de borrado y mover        
    
    if (Cont) {
    	ApNM = (UInt8*)ApReg + Lon;
    	MemMove (&IDAct.r,ApNM,2);
  	    ApNM+=2;
    	MemMove (&TMov,ApNM,2);
        if(NMov >= 0 && NMov < TMov) {
        	ApNM+= (LonM+4) * NMov + 6;
   	    	MemMove (&IndMov,ApNM,1);    	
   	    	MemMove (&IDAct.m,ApNM,4);
    	    ApNM+=4;
        	MemMove(ApMov,ApNM,LonM);
        } else {
        ErrorBD(8,6,0);
        Cont = false;
        }
    } 
    MemHandleUnlock(HReg);
    (*IndB)=false;
    if((IndMov & 02) != 0) (*IndB)=true;
    return Cont;
}

//   ****    Modificar movimiento 

Boolean ModMov (MOV *ApMov, UInt16 NReg, Int16 NMov) {
    Err         Error;
    MemHandle   HReg;
    INF         *ApReg;
    UInt8       *ApNM;
    Int32       Lon,LonM;
    Int16       TMov;
    UInt8       IndMov=01;
    Boolean     Cont = true;

//  Preparar para sacar total de movimientos

    if(!ValNReg(NReg,9)) return false;
    HReg = DmGetRecord(ApArc, NReg);
    if (HReg == NULL) {
        Error = DmGetLastErr();
        ErrorBD(9,9, Error);
        return false;
    } 
    ApReg = MemHandleLock(HReg);
    Lon = SacarLonReg((Int16)ApReg->TReg,9);
    if (Lon == 0) Cont = false;
  	LonM = SacarLonMov((Int16)ApReg->TReg,9);
    if (LonM == 0) Cont = false;
    
//  Sacar total y copiar el movimiento    
    
    if (Cont) {
    	ApNM = (UInt8*)ApReg + Lon;
    	MemMove (&IDAct.r,ApNM,2);
  	    ApNM+=2;
    	MemMove (&TMov,ApNM,2);
        if(NMov >= 0 && NMov < TMov) {
      	    Error = DmWrite(ApReg, Lon + (LonM+4) * NMov + 12, ApMov, LonM);
      	    if (Error==errNone) Error = DmWrite(ApReg, Lon + (LonM+4) * NMov + 8, &IndMov,1);
            if (Error!=errNone) {
                ErrorBD(9,10, Error);
                Cont = false;
            }
        	ApNM+= (LonM+4) * NMov + 6;
   	    	MemMove (&IDAct.m,ApNM,4);
        } else {
        ErrorBD(9,6,0);
        Cont = false;
        }
    } 
    MemHandleUnlock(HReg);
    Error = DmReleaseRecord(ApArc, NReg, true);
    if (Error!=errNone) {
        ErrorBD(9,11, Error);
        Cont = false;
    }
    return Cont;
}

//   ****    Borrar movimiento  Ind = true  Borrarlo totalmente
//                                  = false Poner indicador de borrado

Boolean BorMov (UInt16 NReg, Int16 NMov, Boolean Ind) {
    Err         Error;
    MemHandle   HReg,HMov;
    INF         *ApReg;
    UInt8       *ApNM;
    TMOV        *ApTM;
    Int32       Lon,LonM,LonT;
    Int16       TMov,Op,ai,af;
    Boolean     Cont = true;
    UInt8       IndMov;

    Op=1;
    while(Cont && Op < 8) {
    	switch (Op) {

//   Preparar para copiar los movimientos actuales a memoria    		
    		
    		case 1:
                if(!ValNReg(NReg,10)) return false;
                HReg=DmQueryRecord(ApArc, NReg);
                if (HReg == NULL ) {
                    Error = DmGetLastErr();
                    ErrorBD(10,8, Error);
                    return false;
                }
                ApReg = MemHandleLock(HReg);
                Lon = SacarLonReg((Int16)ApReg->TReg,10);
                if (Lon == 0) Cont = false;
                break;
            case 2:    
            	LonM = SacarLonMov((Int16)ApReg->TReg,10);
                if (LonM == 0) Cont = false;
                break;
            case 3:
    	        ApNM = (UInt8*)ApReg + Lon + 2;
    	        MemMove (&TMov,ApNM,2);
                if(NMov >= 0 && NMov < TMov) break;
                ErrorBD(10,6,0);
                Cont = false;
                break;
                
//    Caso de solo marcar

           case 4:                
                if(Ind) break;
                ApNM+=NMov*(LonM+4)+6;
               	MemMove(&IndMov,ApNM,1);
              	IndMov+=02;
           	    Error = DmWrite(ApReg, Lon+NMov*(LonM+4)+8, &IndMov, 1);
                if (Error!=errNone) {
                    ErrorBD(10,10, Error);
                    Cont = false;
                    break;
                }
               	Op=7;
               	break;
                
//    Caso de quitar, copiar a memoria y reajustar            
                
            case 5:       
                LonT = TMov*(LonM+4)+6;
    	        HMov = MemHandleNew(LonT);
    	        if( HMov == 0 ) {
                   ErrorBD(10,16,0);
                   Cont = false;
                   }
                break;
            case 6:
                ApTM = MemHandleLock(HMov);
                MemMove(ApTM,ApNM,LonT);
                ApTM->TMov--;
                ai = NMov * (LonM+4);
                af = ai + LonM + 4;
                while (af < (LonT-6) ) {
                    ApTM->Mov[ai]=ApTM->Mov[af];
                 	ai++;
                 	af++;
                }
                LonT-=LonM+4;
                MemHandleUnlock(HReg);
                HReg=DmResizeRecord(ApArc, NReg,Lon+2+LonT);
                if (HReg == NULL ) {
                        Error = DmGetLastErr();
                        ErrorBD(10,15, Error);
                        Cont = false;
                        }
                break;
                
//      Regresar al registro los movimientos                
                
            case 7:      
                ApReg = MemHandleLock(HReg);
           	    Error = DmWrite(ApReg, Lon + 2, ApTM, LonT);
                if (Error!=errNone) {
                    ErrorBD(10,10, Error);
                    Cont = false;
                }
                break;
    	}
    	if(Cont)Op++;
    }
    
//   Terminar, quitar lock
    
    if (Op != 6 ) MemHandleUnlock(HReg);
    if (Op >= 6 && Ind ) {
    	MemHandleUnlock(HMov);
    	MemHandleFree(HMov);
    }
    Error = DmReleaseRecord(ApArc, NReg, true);
    if (Error!=errNone) {
        ErrorBD(10,11, Error);
        Cont = false;
    }
    return Cont;
}

//   ****    Insertar movimiento

Boolean InsMov (MOV *ApMov, UInt16 NReg) {
    Err         Error;
    MemHandle   HReg;
    INF         *ApReg;
    UInt8       *ApNM;
    Int32       Lon,LonM,LonT;
    Int16       TMov;
    Int32       UltID;
    UInt8       IndMov=01;
    Boolean     Cont = true;
    
//  Sacar total de registros    

    if(!(ValNReg(NReg,11))) return false;   
    HReg=DmQueryRecord(ApArc, NReg);
    if (HReg == NULL ) {
        Error = DmGetLastErr();
        ErrorBD(11,8, Error);
        return false;
    }
    ApReg = MemHandleLock(HReg);
    Lon = SacarLonReg((Int16)ApReg->TReg,11);
    if (Lon == 0) Cont = false;
  	LonM = SacarLonMov((Int16)ApReg->TReg,11);
    if (LonM == 0) Cont = false;
    if (Cont) {
    	ApNM = (UInt8*)ApReg + Lon;
    	MemMove (&IDAct.r,ApNM,2);
  	    ApNM+=2;
    	MemMove (&TMov,ApNM,2);
    	ApNM += 2;
    	MemMove (&UltID,ApNM,4);
    }
    MemHandleUnlock(HReg);
    if(!Cont) return false;
    
//  Insertar el nuevo y cambiar total   
    
    LonT = TMov * (LonM+4);
    TMov++;
    UltID++;
    IDAct.m=UltID;
    HReg=DmResizeRecord(ApArc, NReg,Lon+8+LonT+LonM+4);
    if (HReg == NULL ) {
        Error = DmGetLastErr();
        ErrorBD(11,6, Error);
        return false;
    }  
    ApReg = MemHandleLock(HReg);
    Error = DmWrite(ApReg, Lon+8+LonT+4, ApMov, LonM);
    if (Error==errNone) Error = DmWrite(ApReg, Lon+8+LonT, &UltID,4);
    if (Error==errNone) Error = DmWrite(ApReg, Lon+8+LonT, &IndMov,1);
    if (Error==errNone) Error = DmWrite(ApReg, Lon+2, &TMov,2);
    if (Error==errNone) Error = DmWrite(ApReg, Lon+4, &UltID,4);
    if (Error!=errNone) {
        ErrorBD(11,15, Error);
        Cont = false;
    }
    MemHandleUnlock(HReg);
    Error = DmReleaseRecord(ApArc, NReg, true);
    if (Error!=errNone) {
         ErrorBD(11,11, Error);
         Cont = false;
         }
    return Cont;
}

//   ****    Leer tipo de registro, en borrado o activo<>1 regresa 0

Boolean LeerTipo (UInt16 NReg, Int16 * Tipo) {
    Err         Error;
    MemHandle   HReg;
    INF         *ApReg;    
    UInt8       TReg;
    UInt8       *ApID;

    
//  Leer er registro, revisa borrado    

    if(!ValNReg(NReg,12)) return false;
    HReg=DmQueryRecord(ApArc, NReg);
    if (HReg == NULL ) {
        Error = DmGetLastErr();
        if(Error == dmErrRecordArchived || 
           Error == dmErrRecordDeleted  ){
              (*Tipo) = 0; 
              return true;
        }
        ErrorBD(12,8, Error);
        return false;
    }
    
//  Pasar el tipo    
    
    ApReg = MemHandleLock(HReg);    
    MemMove (&TReg,ApReg,1);
    (*Tipo)=TReg;
   	ApID=(UInt8*)ApReg+SacarLonReg((Int16)TReg,12);
  	MemMove (&IDAct.r,ApID,2);
   	IDAct.m=0;
    MemHandleUnlock(HReg);
    return true;
}

//   Leer Tipo y subtipo de registro

Boolean LeerTyST (UInt16 NReg, Int16 * Tipo, Int16 * SubTipo) {
    Err         Error;
    MemHandle   HReg;
    INF         *ApReg;    
    UInt8       *ApST;
    UInt8       TReg;
    UInt8       STReg;
    UInt8       *ApID;

    
//  Leer er registro, revisa borrado    

    if(!ValNReg(NReg,12)) return false;
    HReg=DmQueryRecord(ApArc, NReg);
    if (HReg == NULL ) {
        Error = DmGetLastErr();
        if(Error == dmErrRecordArchived || 
           Error == dmErrRecordDeleted  ){
              (*Tipo) = 0; 
              (*SubTipo)=0;
              return true;
        }
        ErrorBD(12,8, Error);
        return false;
    }
    
//  Pasar el tipo y el subtipo   
    
    ApReg = MemHandleLock(HReg);
    MemMove (&TReg,ApReg,1);
    (*Tipo)=TReg;
    ApST = (UInt8*)ApReg+1;
    MemMove (&STReg,ApST,1);
    (*SubTipo)=STReg;
   	ApID=(UInt8*)ApReg+SacarLonReg((Int16)TReg,12);
  	MemMove (&IDAct.r,ApID,2);
   	IDAct.m=0;
    MemHandleUnlock(HReg);
    return true;
}

//   ****  Sacar numero de registro por secuencia

Boolean    SacarNReg (Int16 Tipo, Int16 Sec, UInt16 * NReg) {
	Int16  i,TipoLec;
	
//  Buscar en todos                               	
	
	for (i=0;i<TotReg;i++) {
		if(!LeerTipo(i,&TipoLec)) return false;
		if(TipoLec!=Tipo) continue;
		if(Sec==0) {
    		(*NReg)=i;
	    	return true;
		} 
    	Sec--;
	}
    ErrorBD(13,17,Tipo);
    return false;
}

//   ****  Sacar numero de registro y movimiento por ID

Boolean    SacarNRegNMov (ID * ApID, UInt16 * NReg, Int16 * NMov, Boolean reg) {
	UInt16      nr,nm;
	Int16       IDreg;
	Int32       IDmov;
    Err         Error;
    MemHandle   HReg;
    INF         *ApReg;
    UInt8       *ApNM;
    UInt8       *ApNMX;
    UInt8       TReg;    
    Int32       Lon,LonM;
    Int16       TMov;
	
//  Buscar en todos los registros                               	
	
	for (nr=0;nr<TotReg;nr++) {
         HReg=DmQueryRecord(ApArc, nr);
         if (HReg == NULL ) {
              Error = DmGetLastErr();
              if(Error == dmErrRecordArchived || 
                 Error == dmErrRecordDeleted  )continue;
              ErrorBD(14,8, Error);
              return false;
         }
         ApReg = MemHandleLock(HReg);
         MemMove (&TReg,ApReg,1);
         Lon = SacarLonReg((Int16)TReg,14);
         ApNM = (UInt8*)ApReg + Lon;
         MemMove (&IDreg,ApNM,2);
         MemHandleUnlock(HReg);
         if(Lon==0) return false;
    	 if(ApID->r!=IDreg) continue;
   		 (*NReg)=nr;
   		 if (reg) return true;
	    
//  Buscar ahora en los movimientos 

    	 LonM = SacarLonMov((Int16)TReg,14);
  	     if(LonM==0) return false;
         ApReg = MemHandleLock(HReg);
       	 ApNM = (UInt8*)ApReg + Lon + 2;
       	 MemMove (&TMov,ApNM,2);
  	     ApNM+=6;
    	 for (nm=0;nm<TMov;nm++ ) {
        	ApNMX= ApNM + (LonM+4) * nm;    		
   	    	MemMove (&IDmov,ApNMX,4);
   	    	IDmov = IDmov & 077777777;
   	    	if(ApID->m == IDmov) {
  		   		(*NMov)=nm;
    	   		MemHandleUnlock(HReg);
  		   		return true;
   	    	} 
    	  }
          MemHandleUnlock(HReg);
          break;
	}
    ErrorBD(14,17,0);
    return false;
}

//    ****   Sacar el ID de un registro o de un registro-movimiento
//           Id.m=0 con LeerReg InsReg SacarTipo SacarTyST.
//           ID completo con LeerMov e InsMov.
//           PRECAUCION: Ciertas funciones requieren el completo.

void  SacarID (ID * ApID) {
	  ApID->r = IDAct.r;
	  ApID->m = IDAct.m & 077777777;
	  return;
}

//    ****   Leer(0), Guardar(1) o borrar(2) el registro y su 
//           movimiento con el ID. Se usa ApRM y ApMM

Boolean CGB_ID(ID * ApID, Int8 op) {
UInt16 NReg;
Int16  NMov;	
Boolean IB;
      if(!SacarNRegNMov (ApID,&NReg,&NMov,((op<3)?false:true))) return false;	
      switch(op) {
	      case 0: // Cargar los dos
	         if(!LeerReg(ApRM,NReg)) return false;
	         if(!LeerMov(ApMM,NReg,NMov,&IB)) return false;
	         if(IB) return false;
		     return true;
		  case 1: // Guardar, modificar los dos
		     if(!ModReg(ApRM,NReg)) return false;
             if(!ModMov(ApMM,NReg,NMov)) return false;
   			 return true;
   	      case 2: // Borrar el movimiento, guardar cuenta
   		     if(!ModReg(ApRM,NReg)) return false;
    	     if(!BorMov(NReg,NMov,true)) return false;
			 return true;
   	      case 3: // Guardar cuenta, insertar movimiento
   		     if(!ModReg(ApRM,NReg)) return false;
    	     if(!InsMov(ApMM,NReg)) return false;
			 return true;
   	      case 4: // Solo guardar cuenta
   		     if(!ModReg(ApRM,NReg)) return false;
			 return true;
   	      case 5: // Solo leer cuenta
   		     if(!LeerReg(ApRM,NReg)) return false;
			 return true;
	  }
	  return false;
}
      
//   ****  Sacar Proxima Referencia

Boolean    SacarProxRef (UInt16 NReg, Int32 Ref, Int16 * NMov, Boolean Sup) {
	UInt16      nm;
	Int32       RefReg;
    Err         Error;
    MemHandle   HReg;
    INF         *ApReg;
    UInt8       *ApNM;
    UInt8       *ApNMX;
    UInt8       TReg;    
    Int32       Lon,LonM;
    Int16       TMov;
    
//  Preparar la busqueda  
    
	HReg=DmQueryRecord(ApArc, NReg);
    if (HReg == NULL ) {
        Error = DmGetLastErr();
        ErrorBD(14,8, Error);
        return false;
    }
    ApReg = MemHandleLock(HReg);
    MemMove (&TReg,ApReg,1);
    Lon = SacarLonReg((Int16)TReg,14);
    LonM = SacarLonMov((Int16)TReg,14);
  	if(Lon == 0 || LonM == 0) {
   		MemHandleUnlock(HReg);
       	return false;
    }
  	 ApNM = (UInt8*)ApReg + Lon + 2;
   	 MemMove (&TMov,ApNM,2);
     ApNM+=6;
     
//   Buscar de uno por uno     
     
  	 for (nm=(*NMov)+1;nm<TMov;nm++ ) {
       	ApNMX= ApNM + (LonM+4) * nm + 4;
       	if(!Sup)ApNMX+=4;     		
      	MemMove (&RefReg,ApNMX,4);
      	if(Ref == RefReg) {
  	   		(*NMov)=nm;
   	   		MemHandleUnlock(HReg);
 	   		return true;
     	} 
     }
     MemHandleUnlock(HReg);
     (*NMov)=-1;
     return true;
}

// Cargar registro (reg=true) o movimiento con ID
Boolean  LeerConID(ID *ApID, void *d, Boolean reg) {
UInt16     NReg;
Int16      NMov;
Boolean    IB;
    if(!SacarNRegNMov(ApID,&NReg,&NMov,reg)) return false;
    if (reg) { if(!LeerReg((void*)d,NReg)) return false; }
    else       if(!LeerMov((void*)d,NReg,NMov,&IB)) return false;
    return true;
}
// Guardar movimiento con ID
Boolean  GuardarConID(ID *ApID, void *d) {
UInt16     NReg;
Int16      NMov;
    if(!SacarNRegNMov (ApID,&NReg,&NMov,false)) return false;
    if(!ModMov((void*)d,NReg,NMov)) return false;
    return true;
}
// Leer tipo con ID
Boolean  LeerTipoID(ID *ApID, Int16 *Tipo) {
UInt16     NReg;
Int16      NMov;
    if(!SacarNRegNMov (ApID,&NReg,&NMov,true)) return false;
    if(!LeerTipo(NReg,Tipo)) return false;
    return true;
}
