/* $Revision Header *** Header built automatically - do not edit! ***********
 *
 *	(C) Copyright 1993 by Amit Fridman
 *
 *	Name .....: Data.c
 *	Created ..: Tuesday 14-Dec-93 11:40:39
 *	Revision .: 5
 *
 *	Date        Author                 Comment
 *	=========   ====================   ====================
 *	13-May-94   Amit Fridman           v1.05 Preliminary release
 *	15-Apr-94   Amit Fridman           v1.04 Beta version complete
 *	24-Mar-94   Amit Fridman           v1.03 Added Keys
 *	24-Feb-94   Amit Fridman           v1.02
 *	07-Jan-94   Amit Fridman           v1.01
 *	14-Dec-93   Amit Fridman           Created this file!
 *
 * $Revision Header ********************************************************/
#define REVISION	5

/* Floppy Base data handling routines */

#include "FBase.h"
#include "Protos.h"

static BOOL    _ReadFloppy(struct List *RList,RECORD *Record,UWORD *Depth);
static void    _DeleteBelow(RECORD *Record);
static RECORD *_DupFloppy(struct List *RList,RECORD *Src,RECORD *Parent);

extern char *CY_Labels[];

struct List  FloppyList;
STRPTR       KeyList[MAXKEYS];
STRPTR       KeyListCopy[MAXKEYS];

static ULONG RecID;
static int   KeyScan;

void myStartup()
{
   NewList(&FloppyList);
   InitDiskNames();
   SetSaveName();
   ResetKeys();
}

void myCleanup()
{
   int i;

   FreeKeys();
   for (i=0; i<32; i++)
      if (CY_Labels[i])
         FreeMem(CY_Labels[i],strlen(CY_Labels[i])+1);
   FreeAllFloppies(&FloppyList);
}

BOOL ReadDirectory(char *BaseName,struct List *RList,RECORD *Parent,RECORD **Top,UWORD Depth)
{
   RECORD               *TopRecord = NULL;
   RECORD               *Record;
   STRPTR                String;
   struct FileInfoBlock *fib;
   BPTR                  lock;
   BOOL                  error;

   fib=(struct FileInfoBlock *)AllocDosObject(DOS_FIB,NULL);
   lock=Lock((STRPTR)BaseName,ACCESS_READ);
   if (!lock) return(NULL);
   if (Examine(lock,fib)==0) return(FALSE);
   if (fib->fib_EntryType<0) return(FALSE);
   error=FALSE;
   while (!error) {
      error=(ExNext(lock,fib)==0);
      if (!error) {
         Record=AllocMem(sizeof(RECORD),MEMF_CLEAR);
         if (!Record)
            return(FALSE);
         Record->Parent=Parent;
         Record->Size=fib->fib_Size;
         Record->Depth=Depth;
         if (fib->fib_EntryType>0)
            Record->Flags|=RECORD_DIRECTORY;
         String=AllocMem(strlen(fib->fib_FileName)+1,MEMF_CLEAR);
         if (!String) return(FALSE);
         strcpy(String,fib->fib_FileName);
         Record->FName=String;
         if (strlen(fib->fib_Comment)>0) {
            String=AllocMem(strlen(fib->fib_Comment)+1,MEMF_CLEAR);
            if (!String) return(FALSE);
            strcpy(String,fib->fib_Comment);
            Record->FRem=String;
         }
         Record->Unique=RecID++;
         Record->Keys=0L;
         if (AddRecordInPlace(RList,(struct Node *)Record,(struct Node *)Parent))
            TopRecord=Record;
      }
   }
   UnLock(lock);
   FreeDosObject(DOS_FIB,(APTR)fib);
   *Top=TopRecord;
   return(TRUE);
}

BOOL ReadFloppy(char *FloppyName,FLOPPY **pFloppy)
{
   FLOPPY               *Floppy;
   RECORD               *Record;
   struct FileInfoBlock *fib;
   BPTR                  lock;
   UWORD                 Depth;

   fib=(struct FileInfoBlock *)AllocDosObject(DOS_FIB,NULL);
   lock=Lock((STRPTR)FloppyName,ACCESS_READ);
   if (!lock) return(FALSE);
   if (Examine(lock,fib)==0) return(FALSE);
   UnLock(lock);
   Floppy=AllocMem(sizeof(FLOPPY),MEMF_CLEAR);
   if (!Floppy) return(FALSE);
   NewList(&Floppy->Records);
   Record=AllocMem(sizeof(RECORD),MEMF_CLEAR);
   if (!Record) {
      FreeMem(Floppy,sizeof(FLOPPY));
      return(FALSE);
   }
   Record->FName=AllocMem(strlen(fib->fib_FileName)+1,MEMF_CLEAR);
   if (!Record->FName) {
      FreeRecord(Record,FALSE);
      return(FALSE);
   }
   strcpy((char *)Record->FName,fib->fib_FileName);
   Record->Flags=RECORD_DIRECTORY|RECORD_ROOT;
   RecID=1;
   Record->Unique=RecID++;
   Record->Keys=0L;
   Floppy->HeadRecord=Record;
   AddTail(&Floppy->Records,(struct Node *)Record);
   FreeDosObject(DOS_FIB,(APTR)fib);
   Depth=0;
   if (!_ReadFloppy(&Floppy->Records,Record,&Depth)) {
      FreeFloppy(Floppy,FALSE);
      return(FALSE);
   }
   *pFloppy=Floppy;
   return(TRUE);
}

static BOOL _ReadFloppy(struct List *RList,RECORD *Record,UWORD *Depth)
{
   RECORD *Sub;
   char    BFName[108];

   while (Record) {
      if (Record->Flags & RECORD_DIRECTORY) {
         (*Depth)++;
         if (!ReadDirectory(BuildName(Record,BFName),RList,Record,&Sub,*Depth))
            return(FALSE);
         Record->Sub=Sub;
         if (!_ReadFloppy(RList,Sub,Depth))
            return(FALSE);
      }
      Record=Record->Next;
   }
   (*Depth)--;
   return(TRUE);
}

void FreeAllFloppies(struct List *FList)
{
   while (FList->lh_Head->ln_Succ)
      FreeFloppy((FLOPPY *)FList->lh_Head,TRUE);
}

void FreeFloppy(FLOPPY *Floppy,BOOL remove)
{
   struct List *RList;

   RList=&(Floppy->Records);
   while (RList->lh_Head->ln_Succ)
      FreeRecord((RECORD *)RList->lh_Head,TRUE);
   if (remove) Remove((struct Node *)Floppy);
   FreeMem(Floppy,sizeof(FLOPPY));
}

void FreeRecord(RECORD *Record,BOOL remove)
{
   if (Record->FName)
      FreeMem(Record->FName,strlen(Record->FName)+1);
   if (Record->FRem)
      FreeMem(Record->FRem,strlen(Record->FRem)+1);
   if (remove) Remove((struct Node *)Record);
   FreeMem(Record,sizeof(RECORD));
}

void DeleteBelow(RECORD *Record,BOOL DeleteHead)
{
   _DeleteBelow(Record->Sub);
   if (DeleteHead)
      DeleteRecord(Record);
}

static void _DeleteBelow(RECORD *Record)
{
   RECORD *Rec;

   while (Record) {
      _DeleteBelow(Record->Sub);
      Rec=Record->Next;
      DeleteRecord(Record);
      Record=Rec;
   }
}

void DeleteRecord(RECORD *Record)
{
   RECORD *PrevR,*NextR;

   NextR=Record->Next;
   PrevR=Record->Parent->Sub;
   if (PrevR==Record)
      Record->Parent->Sub=NextR;
   else {
      while (PrevR->Next!=Record)
         PrevR=PrevR->Next;
      PrevR->Next=NextR;
   }
   FreeRecord(Record,TRUE);
}

FLOPPY *DupFloppy(FLOPPY *Floppy)
{
   FLOPPY *Dup;
   RECORD *Rec;

   Dup=AllocMem(sizeof(FLOPPY),MEMF_CLEAR);
   if (!Dup) return((FLOPPY *)-1);
   NewList(&Dup->Records);
   Rec=_DupFloppy(&Dup->Records,Floppy->HeadRecord,NULL);
   Dup->HeadRecord=Rec;
   return(Dup);
}

static RECORD *_DupFloppy(struct List *RList,RECORD *Src,RECORD *Parent)
{
   RECORD *TopRecord = NULL;
   RECORD *Record,*Sub,*Rec;

   while (Src) {
      Record=DupRecord(Src);
      if (TopRecord) {
         for (Rec=TopRecord; Rec->Next; Rec=Rec->Next);
         Rec->Next=Record;
      } else
         TopRecord=Record;
      Record->Parent=Parent;
      Record->Next=NULL;
      Record->Sub=NULL;
      AddTail(RList,(struct Node *)Record);
      if (Src->Sub) {
         Sub=_DupFloppy(RList,Src->Sub,Record);
         Record->Sub=Sub;
      }
      Src=Src->Next;
   }
   return(TopRecord);
}

RECORD *DupRecord(RECORD *Src)
{
   RECORD *Record;

   Record=AllocMem(sizeof(RECORD),MEMF_CLEAR);
   *Record=*Src;
   if (Src->FName) {
      Record->FName=AllocMem(strlen((char *)Src->FName)+1,MEMF_CLEAR);
      strcpy((char *)Record->FName,(char *)Src->FName);
   }
   if (Src->FRem) {
      Record->FRem=AllocMem(strlen((char *)Src->FRem)+1,MEMF_CLEAR);
      strcpy((char *)Record->FRem,(char *)Src->FRem);
   }
   return(Record);
}

BOOL FindMatch(struct List *SList,STRPTR Pattern,BOOL NoCase,
               BOOL DoDirs,LONGBITS KeyMask,BOOL KeyAnd)
{
   FLOPPY *SFloppy;
   RECORD *SRecord;
   char    token[132];
   BOOL    NameMatch,Success;
   BOOL    Found = FALSE;

   if (NoCase)
      ParsePatternNoCase(Pattern,(STRPTR)token,sizeof(token)-1);
   else
      ParsePattern(Pattern,(STRPTR)token,sizeof(token)-1);
   SFloppy=(FLOPPY *)SList->lh_Head;
   while (((struct Node *)SFloppy)->ln_Succ) {
      SRecord=(RECORD *)SFloppy->Records.lh_Head;
      while (((struct Node *)SRecord)->ln_Succ) {
         if ((!(SRecord->Flags & RECORD_DIRECTORY)) || (DoDirs)) {
            if (NoCase)
               NameMatch=MatchPatternNoCase((STRPTR)token,(STRPTR)SRecord->FName);
            else
               NameMatch=MatchPattern((STRPTR)token,(STRPTR)SRecord->FName);
            if (NameMatch) {
               if (!KeyMask)
                  Success=TRUE;
               else
                  if (KeyAnd)
                     Success=((KeyMask & SRecord->Keys)==KeyMask);
                  else
                     Success=((KeyMask & SRecord->Keys)!=NULL);
               if (Success) {
                  Found=TRUE;
                  AddMatchToList(SRecord);
               }
            }
         }
         SRecord=(RECORD *)(((struct Node *)SRecord)->ln_Succ);
      }
      SFloppy=(FLOPPY *)(((struct Node *)SFloppy)->ln_Succ);
   }
   return(Found);
}

void AddFloppyInPlace(struct List *fList,struct Node *fNode)
{
   RECORD      *Record;
   struct Node *Node;
   STRPTR       String;

   Record=((FLOPPY *)fNode)->HeadRecord;
   if (!Record) {
      AddHead(fList,fNode);
      return;
   }
   String=Record->FName;
   Node=fList->lh_Head;
   while (Node->ln_Succ) {
      Record=((FLOPPY *)Node)->HeadRecord;
      if (Record) {
         if (stricmp((char *)String,(char *)Record->FName)<0) {
            Insert(fList,fNode,Node->ln_Pred);
            return;
         }
      }
      Node=Node->ln_Succ;
   }
   AddTail(fList,fNode);
}

BOOL AddRecordInPlace(struct List *rList,struct Node *rNode,struct Node *pNode)
{
   RECORD      *Record;
   struct Node *Node;
   STRPTR       String;

   String=((RECORD *)rNode)->FName;
   Node=pNode->ln_Succ;
   while (Node->ln_Succ) {
      Record=(RECORD *)Node;
      if (Record->Parent!=(RECORD *)pNode) break;
      if (stricmp((char *)String,(char *)Record->FName)<0) {
         Insert(rList,rNode,Node->ln_Pred);
         ((RECORD *)rNode)->Next=(RECORD *)Node;
         if (rNode->ln_Pred!=pNode) {
            ((RECORD *)rNode->ln_Pred)->Next=(RECORD *)rNode;
            return(FALSE);
         } else
            return(TRUE);
      }
      Node=Node->ln_Succ;
   }
   Insert(rList,rNode,Node->ln_Pred);
   ((RECORD *)rNode)->Next=NULL;
   if (rNode->ln_Pred!=pNode) {
      ((RECORD *)rNode->ln_Pred)->Next=(RECORD *)rNode;
      return(FALSE);
   } else
      return(TRUE);
}

void ResetKeys()
{
   int i;

   for (i=0; i<MAXKEYS; i++)
      KeyList[i]=NULL;
}

void FreeKeys()
{
   int i;

   ClearKeyLView();
   for (i=0; i<MAXKEYS; i++)
      if (KeyList[i]) {
         FreeMem(KeyList[i],strlen(KeyList[i])+1);
         KeyList[i]=NULL;
      }
}

void CopyFromKeys()
{
   int i;

   for (i=0; i<MAXKEYS; i++)
      if (KeyList[i]) {
         KeyListCopy[i]=AllocMem(strlen(KeyList[i])+1,MEMF_CLEAR);
         strcpy(KeyListCopy[i],KeyList[i]);
      } else
         KeyListCopy[i]=NULL;
}

void CopyToKeys()
{
   int i;

   FreeKeys();
   for (i=0; i<MAXKEYS; i++)
      if (KeyListCopy[i]) {
         KeyList[i]=AllocMem(strlen(KeyListCopy[i])+1,MEMF_CLEAR);
         strcpy(KeyList[i],KeyListCopy[i]);
      }
}

void TestKeyDelete()
{
   int i;

   for (i=0; i<MAXKEYS; i++)
      if ((!KeyList[i]) && (KeyListCopy[i]))
            RemoveKeyFromFloppies(&FloppyList,~(1<<i));
}

void FreeKeyCopy()
{
   int i;

   for (i=0; i<MAXKEYS; i++)
      if (KeyListCopy[i]) {
         FreeMem(KeyListCopy[i],strlen(KeyListCopy[i])+1);
         KeyListCopy[i]=NULL;
      }
}

STRPTR *AddKeyToList(STRPTR KName,BOOL *Full)
{
   int i,j;

   for (i=0; i<MAXKEYS; i++)
      if (KeyList[i]==NULL) {
         KeyList[i]=AllocMem(strlen(KName)+1,MEMF_CLEAR);
         strcpy(KeyList[i],KName);
         for (j=i+1,*Full=TRUE; j<MAXKEYS; j++)
            if (KeyList[j]==NULL)
               *Full=FALSE;
         return(&KeyList[i]);
      }
   return(NULL);
}

STRPTR *ChangeKeyList(STRPTR OldKey,STRPTR KName)
{
   int i;

   for (i=0; i<MAXKEYS; i++)
      if (KeyList[i]==OldKey) {
         FreeMem(OldKey,strlen(OldKey)+1);
         KeyList[i]=AllocMem(strlen(KName)+1,MEMF_CLEAR);
         strcpy(KeyList[i],KName);
         return(&KeyList[i]);
      }
   return(NULL);
}

void DelKeyFromList(STRPTR KName)
{
   int i;

   for (i=0; i<MAXKEYS; i++)
      if (KeyList[i]==KName) {
         FreeMem(KName,strlen(KName)+1);
         KeyList[i]=NULL;
         return;
      }
}

void InitKeyScan()
{
   KeyScan=0;
}

STRPTR *GetNextKey(WORD *KeyNum)
{
   while (KeyScan<MAXKEYS && KeyList[KeyScan]==NULL)
      KeyScan++;
   *KeyNum=KeyScan;
   if (KeyScan==MAXKEYS)
      return(NULL);
   else
      return(&KeyList[KeyScan++]);
}

WORD KeyNumber(STRPTR Key)
{
   WORD i;

   for (i=0; i<MAXKEYS; i++)
      if (KeyList[i]==Key) {
         return(i);
      }
   return(-1);
}

STRPTR *NumberKey(WORD Num)
{
   return(&KeyList[Num]);
}

void AddKeyInPos(WORD KeyNum,STRPTR Key)
{
   KeyList[KeyNum]=AllocMem(strlen(Key)+1,MEMF_CLEAR);
   strcpy(KeyList[KeyNum],Key);
   AddKeyToLView(&KeyList[KeyNum]);
}

void RemoveKeyFromFloppies(struct List *FList,LONGBITS KeyMask)
{
   FLOPPY *Floppy;
   RECORD *Record;

   Floppy=(FLOPPY *)FList->lh_Head;
   while (((struct Node *)Floppy)->ln_Succ) {
      Record=(RECORD *)Floppy->Records.lh_Head;
      while (((struct Node *)Record)->ln_Succ) {
         Record->Keys&=KeyMask;
         Record=(RECORD *)(((struct Node *)Record)->ln_Succ);
      }
      Floppy=(FLOPPY *)(((struct Node *)Floppy)->ln_Succ);
   }
}

void KeysBelow(RECORD *Record,LONGBITS AddMask,LONGBITS RemMask)
{
   while (Record) {
      KeysBelow(Record->Sub,AddMask,RemMask);
      Record->Keys|=AddMask;
      Record->Keys&=RemMask;
      Record=Record->Next;
   }
}

void SalvageData(FLOPPY *DstF,FLOPPY *SrcF,LONG Type)
{
   RECORD *SrcR,*DstR;
   RECORD *SrcR2;
   char    SrcN[108],DstN[108];
   BOOL    Found;

   DstR=(RECORD *)DstF->Records.lh_Head;
   while (((struct Node *)DstR)->ln_Succ) {
      BuildName(DstR,DstN);
      Found=FALSE;
      SrcR=(RECORD *)SrcF->Records.lh_Head;
      SrcR2=NULL;
      while ((!Found) && (((struct Node *)SrcR)->ln_Succ)) {
         BuildName(SrcR,SrcN);
         if (strcmp(DstN,SrcN)==0) {
            Found=TRUE;
            break;
         }
         if (Type>1)
            if (strcmp(DstR->FName,SrcR->FName)==0)
               SrcR2=SrcR;
         SrcR=(RECORD *)(((struct Node *)SrcR)->ln_Succ);
      }
      if ((!Found) && (SrcR2)) {
         SrcR=SrcR2;
         Found=TRUE;
      }
      if (Found) {
         if (SrcR->FRem) {
            if (DstR->FRem)
               FreeMem(DstR->FRem,strlen(DstR->FRem)+1);
            DstR->FRem=AllocMem(strlen(SrcR->FRem)+1,MEMF_CLEAR);
            strcpy(DstR->FRem,SrcR->FRem);
         }
         DstR->Keys=SrcR->Keys;
      }
      DstR=(RECORD *)(((struct Node *)DstR)->ln_Succ);
   }
}
