// ------------------------------- //
// -------- Start of File -------- //
// ------------------------------- //
// ----------------------------------------------------------- // 
// C++ Source Code File Name: testprog.cpp 
// C++ Compiler Used: MSVC, BCC32, GCC, HPUX aCC, SOLARIS CC
// Produced By: glNET Software
// File Creation Date: 01/25/2000
// Date Last Modified: 05/25/2001
// Copyright (c) 2001 glNET Software
// ----------------------------------------------------------- // 
// ------------- Program Description and Details ------------- // 
// ----------------------------------------------------------- // 
/*
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
 
This library 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
Lesser General Public License for more details.

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

This is a test program for the DiskFileB class.
*/
// ----------------------------------------------------------- // 
#include <iostream.h>
#include <iomanip.h>
#include <string.h>
#include <stdio.h>
#include "dfileb.h"

#ifdef __MSVC_DEBUG__
#include "leaktest.h"
#endif

void PausePrg() 
{
  cout << endl;
  cout << "Press enter to continue..." << endl;
  cin.get();
}

struct fileblock {
  unsigned block_length;
};

void DirectoryTest()
{
  cout << "Testing general purpose directory functions" 
       << endl;

  const char *dirname = "testdir"; // Directory to be created
  const char *currentdir = ".";    // Current directory poisition

  // Directory immediately above the current directory position
  const char *parentdir = "..";    
  
  DiskFileB dir;
  cout << "Creating " << dirname << " directory" <<endl;
  if(dir.df_mkdir(dirname) != 0) {
    cout << dir.df_GetFileError() << endl;
    return;
  }

  if((dir.df_Exists(dirname)) && (dir.df_IsDirectory(dirname))) {
    cout << "The " << dirname << " directory was created" << endl;
  }

  cout << "Changing directory to " << dirname << " directory" <<endl;
  if(dir.df_chdir(dirname) != 0) {
    cout << dir.df_GetFileError() << endl;
    return;
  }

  char *pwd[df_MAX_DIR_LENGTH]; char drive_letter;
  if(dir.df_pwd((char *)pwd) == 0) {
    cout << "Present working directory: " << (char *)pwd << endl;
    if(dir.df_HasDriveLetter((const char *)pwd, drive_letter)) {
      cout << "DOS Drive letter = " << drive_letter << endl;
    }
  }

  cout << "Changing directory to " << parentdir << " directory" <<endl;
  if(dir.df_chdir(parentdir) != 0) {
    cout << dir.df_GetFileError() << endl;
    return;
  }

  if(dir.df_pwd((char *)pwd) == 0) {
    cout << "Present working directory: " << (char *)pwd << endl;
    if(dir.df_HasDriveLetter((const char *)pwd, drive_letter)) {
      cout << "DOS Drive letter = " << drive_letter << endl;
    }
  }

  cout << "Removing " << dirname << " directory" <<endl;
  if(dir.df_rmdir(dirname) != 0) {
    cout << dir.df_GetFileError() << endl;
    return;
  }
}

void FileTest()
{
  cout << "Testing general purpose file functions"
       << endl;

  const char *testfile1 = "testfile1.dat";
  const char *testfile2 = "testfile2.dat";
  const char *testfile3 = "testfile3.dat";
  DiskFileB dfile(testfile1, DiskFileB::df_READWRITE, DiskFileB::df_CREATE, 
		  DiskFileB::df_TRUNCATE, DiskFileB::df_SHARE);
  if(!dfile) {
    cout << "Could not open the " << testfile1 << endl;
    return;
  }

  if((dfile.df_Exists(testfile1)) && (dfile.df_IsFile(testfile1))) {
    cout << "The " << testfile1 << " file was opened with read/write access"
	 << endl;
   }
  
  const char *teststr1 = "The quick brown fox jumps over the lazy dog \
0123456789\r\n";
  
  cout << "Writing " << strlen(teststr1) << " bytes to " << testfile1 << endl;
  if(dfile.df_Write((const char *)teststr1, strlen(teststr1)) != 0) {
    cout << dfile.df_GetFileError() << endl;
    return;
  }
  
  cout << testfile1 << " is " << (int)dfile.df_FileSize(testfile1) 
       << " bytes long" << endl;
  
  char *sbuf = new char[strlen(teststr1)+1];
  cout << "Reading the file contents..." << endl;
  if(dfile.df_Read((char *)sbuf, strlen(teststr1), (df_StreamPos)0) != 0) {
    cout << dfile.df_GetFileError() << endl;
    return;
  }
  sbuf[strlen(teststr1)] = '\0';
  cout << sbuf;
  delete sbuf;
  
  dfile.df_Close();
  cout << "Renaming the " << testfile1 << " to " << testfile2 << endl;
  if(dfile.df_rename(testfile1, testfile2) != 0) {
    cout << dfile.df_GetFileError() << endl;
    return;
  }
  cout << "Copying " << testfile2 << " to " << testfile3 << endl;
  if(dfile.df_copy(testfile2, testfile3) != 0) {
    cout << dfile.df_GetFileError() << endl;
    return;
  }
  cout << "Removing " << testfile2 << " and " << testfile3 << endl;
  if(dfile.df_remove(testfile2) != 0) {
    cout << dfile.df_GetFileError() << endl;
    return;
  }
  if(dfile.df_remove(testfile3) != 0) {
    cout << dfile.df_GetFileError() << endl;
    return;
  }

  // Add routine to change file attributes/permissions here
  // ------------------------------------------------------
}

void RandomSeekTest()
{
  cout << "Performing random read/write test" << endl;

  const char *testfile = "testfile.dat";
  DiskFileB dfile(testfile, DiskFileB::df_READWRITE, DiskFileB::df_CREATE, 
		  DiskFileB::df_TRUNCATE, DiskFileB::df_SHARE);

  if(!dfile) {
    cout << "Could not open the " << testfile << endl;
    return;
  }
  
  if((dfile.df_Exists(testfile)) && (dfile.df_IsFile(testfile))) {
    cout << "The " << testfile << " file was opened with read/write access"
	 << endl;
  }
  
  const char *teststr = "The quick brown fox jumps over the lazy dog";

  unsigned i;
  unsigned len = strlen(teststr)+4;
  char *str = new char[len+1];
  for(i = 0; i< len; i++) str[i] = '\0';
  memmove(str, teststr, strlen(teststr));

  const unsigned blocks_to_write = 10;
  df_StreamPos pos[blocks_to_write];
  fileblock hdr;
  char sbuf[255];

  cout << "Writing " << blocks_to_write << " blocks of data..." << endl;
  for(i = 0; i < blocks_to_write; i++) {
    pos[i] = dfile.df_FilePosition();  
    sprintf(sbuf, " %u", i);
    memmove(str+strlen(teststr), sbuf, strlen(sbuf));
    str[strlen(teststr)+strlen(sbuf)] = '\0';
    hdr.block_length = sizeof(fileblock) + (strlen(str)-1);
    dfile.df_Write(&hdr,sizeof(fileblock)); 
    dfile.df_Write((char *)str, hdr.block_length);
  }

  cout << "Reading back the blocks..." << endl;
  PausePrg();

  const int max_lines = 10;
  int lines_printed = 0;
  hdr.block_length = 0;
  int ii;

  for(i = 0; i <  blocks_to_write; i++) {
    for(ii = 0; ii < (int)len; ii++) str[ii] = '\0';
    dfile.df_Read(&hdr, sizeof(fileblock), pos[i]);
    dfile.df_Read((char *)str, hdr.block_length, (pos[i]+sizeof(fileblock)));
    cout << "Block address = " << (long)pos[i] << endl;
    cout << "Block size = " << hdr.block_length << endl;
    cout << "Data = " << str << endl;
    lines_printed++;
    if(lines_printed >= max_lines) {
      PausePrg();
      lines_printed = 0;
    }
  }

  dfile.df_Rewind();
  
  cout << "Reading back the blocks in reverse order..." << endl;
  PausePrg();

  for(ii = (int)blocks_to_write-1; ii >= 0; ii--) {
    for(i = 0; i < len; i++) str[i] = '\0';
    dfile.df_Read((char *)&hdr, sizeof(fileblock), pos[ii]);
    dfile.df_Read((char *)str, hdr.block_length);
    cout << "Block address = " << (long)pos[ii] << endl;
    cout << "Block size = " << hdr.block_length << endl;
    cout << "Data = " << str << endl;
    lines_printed++;
    if(lines_printed >= max_lines) {
      PausePrg();
      lines_printed = 0;
    }
  }

  delete str;
  dfile.df_Close();

  cout << endl;
  cout << "Removing " << testfile << endl;
  if(dfile.df_remove(testfile) != 0) {
    cout << dfile.df_GetFileError() << endl;
    return;
  }
  return;
}

int main()
{
#ifdef __MSVC_DEBUG__
  InitLeakTest();
#endif

  cout << endl;
  DirectoryTest();
  PausePrg();

  FileTest();
  PausePrg();

  RandomSeekTest();

  cout << endl;
  cout << "Exiting..." << endl;
  cout << endl;
  return 0;
}
// ----------------------------------------------------------- //
// ------------------------------- //
// --------- End of File --------- //
// ------------------------------- //