/*

File: paedia.c
Author: Neil Cafferkey
Copyright (C) 2000 Neil Cafferkey

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA.

*/

#include "viewer.h"
#include <exec/memory.h>
#include <dos/dos.h>
#include <dos/dostags.h>
#include <stdio.h>
#include <string.h>

#include "paedia_protos.h"
#include "general_protos.h"
#include "deflated_sequence_protos.h"
#include "article_protos.h"
#include "index_protos.h"
#include <proto/exec.h>
#include <proto/dos.h>


#define BLOCK_SIZE 512
#define MAX_LINK_FILE_NAME_LENGTH 20

const TEXT main_file_name[]="info_dat/wb.dat";
/*const TEXT link_file_name[]="links";*/
const TEXT master_file_name[]="info_dat/master.ndx";
const TEXT index_file_name[]="info_dat/ssubject.ndx";
const TEXT orig_link_file_name[]="info_dat/rom_link.dat";


static VOID GetBlocks(BPTR file,ULONG start_block,ULONG block_count,
   UBYTE *buffer);
static MediaLink GetPaediaLink(Paedia paedia,ULONG link_no);



/* Function: ConvertLinkFile
 * =========================
 * Converts the original link file into a new file with a non-textual
 * format.
 */

BOOL ConvertLinkFile(TEXT *old_file_name,TEXT *new_file_name)
{
   FILE *old_file;
   ULONG line_count=0,i;
   char ch;
   MediaLink media_links,p;
   BPTR new_file;
   BOOL success=TRUE;

   /* Convert "rom link" text file into an array in memory */

   if(old_file=fopen(old_file_name,"rb"))
   {

      /* Count the lines in the text file and allocate enough memory to
       * hold its converted  contents. */

      for(ch=0;!feof(old_file);ch=getc(old_file))
         if(ch=='\n')
            line_count++;

      line_count;

      media_links=(MediaLink)AllocMem(sizeof(MediaLink_imp)
         *line_count,MEMF_CLEAR);

      /* Fill array of media links */

      if(media_links)
      {
         rewind(old_file);
         p=media_links;
         for(i=0;i<line_count;i++)
         {
            fscanf(old_file,"%lu|%*[^|]|%*[^|]|%*[^|]|%*[^|]|%lu|%hu",
               &(p->link_no),&(p->start_block),&(p->block_count));
            getc(old_file);
            p++;
         }

         /* Write converted links into a new file */

         if(new_file=Open(new_file_name,MODE_NEWFILE))
         {
            if(Write(new_file,media_links,line_count
               *sizeof(MediaLink_imp))==-1)
               success=FALSE;
            Close(new_file);
         }

         FreeMem(media_links,sizeof(MediaLink_imp)*line_count);
      }

      fclose(old_file);
   }
   else
   {
   success=FALSE;
   }

   return success;
}



/* Function: CreatePaedia
 * ======================
 * Creates a Paedia.
 */

Paedia CreatePaedia(TEXT *data_dir_name,TEXT *paedia_dir_name)
{
   Paedia paedia;
   ULONG line_count=0;
   TEXT *path_name,*index_path_name,*link_file_name,*orig_link_path;
   struct FileInfoBlock *temp_fib;
   BPTR link_file=NULL,master_file=NULL;
   BOOL success=TRUE;

   if(paedia=AllocMem(sizeof(Paedia_imp),MEMF_CLEAR))
   {

      /* Construct the full path name for main file */

      if(path_name=AllocVec(strlen(paedia_dir_name)+
         strlen(main_file_name)+2,0))
      {

         strcpy(path_name,paedia_dir_name);

         AddPart(path_name,main_file_name,strlen(paedia_dir_name)+strlen(
            main_file_name)+2);

         /* Open the main file and free its path name buffer */

         if(!(paedia->main_file=Open(path_name,MODE_OLDFILE)))
         {
            ReportError(NULL,ERROR_REPORT_FILE,path_name,0);
            success=FALSE;
         }
         FreeVec(path_name);
      }
      else
      {
         ReportError(NULL,ERROR_REPORT_MEM,NULL,0);
         success=FALSE;
      }

      /* Make a string specifying the main file size */

      if(success)
      {
         if((temp_fib=AllocDosObjectTags(DOS_FIB,TAG_END))&&
            (link_file_name=AllocVec(MAX_LINK_FILE_NAME_LENGTH+1,
            MEMF_PUBLIC)))
         {
            ExamineFH(paedia->main_file,temp_fib);
            sprintf(link_file_name,"%ld",temp_fib->fib_Size);
            FreeDosObject(DOS_FIB,temp_fib);
         }
         else
         {
            ReportError(NULL,ERROR_REPORT_MEM,NULL,0);
            success=FALSE;
         }

         /* Construct the full path name for link file */

         if(success)
         {
            if(success&&(path_name=AllocVec(strlen(data_dir_name)+
               strlen(link_file_name)+2,0)))
            {
               strcpy(path_name,data_dir_name);

               AddPart(path_name,link_file_name,strlen(data_dir_name)+
                  strlen(link_file_name)+2);

               /* Open the link file and free its path name buffer */

               if(!(link_file=Open(path_name,MODE_OLDFILE)))
               {

                  /* Create a new link file from the original textual link
                   * file */

                  if(orig_link_path=AllocVec(strlen(paedia_dir_name)+
                     strlen(orig_link_file_name)+2,0))
                  {

                     /* TODO: should let user know what's happening */

                     strcpy(orig_link_path,paedia_dir_name);
                     AddPart(orig_link_path,orig_link_file_name,
                        strlen(paedia_dir_name)+strlen(orig_link_file_name)
                        +2);
                     ConvertLinkFile(orig_link_path,path_name);
                  }
                  else
                  {
                     ReportError(NULL,ERROR_REPORT_MEM,NULL,0);
                     success=FALSE;
                  }

                  /* Retry to open the apropriate link file */

                  if(!(link_file=Open(path_name,MODE_OLDFILE)))
                  {
                     ReportError(NULL,ERROR_REPORT_FILE,path_name,0);
                     success=FALSE;
                  }
               }

               FreeVec(path_name);
            }
            else
            {
               ReportError(NULL,ERROR_REPORT_MEM,NULL,0);
               success=FALSE;
            }
         }
         FreeVec(link_file_name);
      }

      /* Copy link file into memory */

      if(link_file)
      {

         if(temp_fib=AllocDosObjectTags(DOS_FIB,TAG_END))
         {
            /* Get link file size */

            ExamineFH(link_file,temp_fib);
            paedia->link_count=temp_fib->fib_Size/sizeof(MediaLink_imp);
            FreeDosObject(DOS_FIB,temp_fib);

            /* Allocate memory for link data */

            paedia->media_links=AllocMem(sizeof(MediaLink_imp)
               *paedia->link_count,MEMF_CLEAR);

            /* Read link data into memory */

            if(paedia->media_links)
               Read(link_file,paedia->media_links,paedia->link_count
                  *sizeof(MediaLink_imp));
            else
            {
               ReportError(NULL,ERROR_REPORT_MEM,NULL,0);
               success=FALSE;
            }

         }
         else
         {
            ReportError(NULL,ERROR_REPORT_MEM,NULL,0);
            success=FALSE;
         }

         Close(link_file);
      }

      /* Construct the full path names for the index files */

      path_name=AllocVec(strlen(paedia_dir_name)+
         strlen(master_file_name)+2,0);

      index_path_name=AllocVec(strlen(paedia_dir_name)+
         strlen(index_file_name)+2,0);

      if(path_name&&index_path_name)
      {
         strcpy(path_name,paedia_dir_name);
         strcpy(index_path_name,paedia_dir_name);

         AddPart(path_name,master_file_name,strlen(paedia_dir_name)+strlen(
            master_file_name)+2);
         AddPart(index_path_name,index_file_name,strlen(paedia_dir_name)+
            strlen(index_file_name)+2);

         paedia->index=CreateIndex(path_name,index_path_name);
         if(!paedia->index)
            success=FALSE;

         FreeVec(path_name);
         FreeVec(index_path_name);
      }
      else
      {
         ReportError(NULL,ERROR_REPORT_MEM,NULL,0);
         success=FALSE;
      }

      if(!success)
      {
         KillPaedia(paedia);
         paedia=NULL;
      }

   }
   else
   {
      ReportError(NULL,ERROR_REPORT_MEM,NULL,0);
   }

   return paedia;
}



/* Function: GetPaediaItem
 * =======================
 * Extracts an article,picture etc. from a Paedia.
 */

Sequence GetPaediaItem(Paedia paedia,ULONG link_no)
{
   MediaLink link=GetPaediaLink(paedia,link_no);
   Sequence inflated=NULL;
   DeflatedSequence deflated;
   UBYTE *compressed_buffer;

   compressed_buffer=AllocMem(link->block_count*BLOCK_SIZE,MEMF_ANY);

   if(compressed_buffer)
   {
      GetBlocks(paedia->main_file,link->start_block,link->block_count,
         compressed_buffer);

      deflated=CreateSequence(link->block_count*BLOCK_SIZE,
         compressed_buffer);
      if(deflated)
      {
         inflated=InflateSequence(deflated);
         KillSequence(deflated);
      }
      FreeMem(compressed_buffer,link->block_count*BLOCK_SIZE);
   }

#ifdef TEST
   BPTR extract_file;

      if(extract_file=Open("T:extract",MODE_NEWFILE))
      {
         Write(extract_file,inflated->data,inflated->length);
         Close(extract_file);
      }
#endif

   return inflated;
}



/* Function: KillPaedia
 * ====================
 * Destroys a Paedia.
 */

VOID KillPaedia(Paedia paedia)
{

   if(paedia->index)
      KillIndex(paedia->index);

   if(paedia->main_file)
      Close(paedia->main_file);

   if(paedia->media_links)
      FreeMem(paedia->media_links,paedia->link_count*sizeof(MediaLink_imp));

   FreeMem(paedia,sizeof(Paedia_imp));

   return;
}



/* Function: GetPaediaLink
 * =======================
 * Finds a specific link in a paedia's link array.
 */

static MediaLink GetPaediaLink(Paedia paedia,ULONG link_no)
{
   MediaLink p;

   for(p=paedia->media_links;p->link_no!=link_no;p++);

   return p;
}



/* Function: GetBlocks
 * ===================
 * Reads data blocks from the main paedia file.
 */

static VOID GetBlocks(BPTR file,ULONG start_block,ULONG block_count,
   UBYTE *buffer)
{
   Seek(file,start_block*BLOCK_SIZE,OFFSET_BEGINNING);
   Read(file,buffer,block_count*BLOCK_SIZE);

   return;
}



