//
// The Fusion Library Interface for DOS
// Version 1.02
// Copyright (C) 1990, 1991
// Software Dimensions
//
// Dialog Development System
//

#include "fliwin.h"
#include "elements.h"
#include "colors.h"
#include "dds.h"

#include <dos.h>
#include <time.h>
#include <stddef.h>
#include <string.h>
#include <alloc.h>

#include "chgdir.h"

#pragma warn -inl

//-------------------------------------------------------------------------
//
// Powers up the PathStorage class
//
//-------------------------------------------------------------------------

PathStorage::PathStorage()
{

  DirEntries=0;

  Drives=0;
  Revert=0;
  Path=0;

  CurrentDisk=0;
  DriveCount=0;
  SaveDisk=0;
  Count=0;

  Path=new char[45];
  Revert=new char[45];
  DirEntries=new ffblk[MaxEntries];
  getcwd(Revert,40);
  Refresh();

  SaveDisk=getdisk();
  for (int Disk=0;Disk<26;Disk++)
  {
    setdisk(Disk);
    if (Disk==getdisk())
    {
      Drives=(char(*)[2])realloc(Drives,sizeof(Drives[0])*++DriveCount);
      *(Drives[DriveCount-1]+0)='A'+Disk;
      *(Drives[DriveCount-1]+1)=0;
      if (Disk==SaveDisk)
        CurrentDisk=DriveCount-1;
    }
  }

  setdisk(SaveDisk);
}

//-------------------------------------------------------------------------
//
// Refresh the directories when our location switched
//
//-------------------------------------------------------------------------

void PathStorage::Refresh()
{
  getcwd(Path,40);
  if (*(Path+strlen(Path)-1)!='\\')
    strcat(Path,"\\");
  strcat(Path,"*.*");

  ffblk DummyStorage;

  int Done=findfirst(Path,&DummyStorage,FA_DIREC);
  Count=0;

  while (!Done)
  {
    if (DummyStorage.ff_attrib&FA_DIREC)
      DirEntries[(++Count)-1]=DummyStorage;
    if (Count==MaxEntries-1)
    {
      InfoBox &NotAvailable = *new InfoBox;
      NotAvailable
            + "Internal drive storage buffer is exhausted."
            + ""
            + "Directory listing may be missing some directories.";
      NotAvailable.Title("Exhausted");
      NotAvailable.UseInfoBox();
      delete &NotAvailable;
      break;
    }
    Done=findnext(&DummyStorage);
  }

  *(strchr(Path,'*'))=0;
}

//-------------------------------------------------------------------------
//
// Destructor that frees up the directory information
//
//-------------------------------------------------------------------------

PathStorage::~PathStorage()
{
  if (Path)
  {
    delete Path;
    delete DirEntries;
    delete Revert;
    delete Drives;
  }
  Revert=0;
  DirEntries=0;
  Path=0;
  DriveCount=0;
  Drives=0;
}

//-------------------------------------------------------------------------
//
// Construct the class that will contain the ChDir event handler
// Destruct class upon exit
//
//-------------------------------------------------------------------------

ChDirDialog::ChDirDialog() : DialogClass(49,13,"Change Directory")
{
  Path=new PathStorage();

  Element(new ChDirPath(6,1,*Path));
  Help("Enter the search path");
  HotKey(1,1,"~Path",kbAltP);
  FusionHelp(10103);

  Element(new ChDirList(1,4,*Path));
  Help("Select the directory to traverse to");
  HotKey(1,3,"~Directory",kbAltD);
  Available(Path->Count);
  FusionHelp(10104);

  Element(new DirList(17,4,*Path));
  Help("Select the drive to jump to");
  HotKey(17,3,"D~rive",kbAltR);
  FusionHelp(10105);

  Element(new DiaPushButton(32,4,"   Okay   ",ChDirOkayButton,0,1));
  Help("Accept the current drive and directory");

  Element(new DiaPushButton(32,6,"  ~Cancel  ",ChDirCancelButton,kbAltC));
  Help("Cancel and do not change the drive and directory");

  Element(new DiaPushButton(32,8,"R~evert ...",ChDirRevertButton,kbAltE));
  Help("Revert to the original drive and directory");

  Element(new Prompt(*Path));
}

ChDirDialog::~ChDirDialog()
{
  delete Path;
}

//-------------------------------------------------------------------------
//
// Event handler for the ChDir dialog
//
//-------------------------------------------------------------------------

int ChDirDialog::EventHandler(int Event)
{
  switch(Event)
  {
    case kbEsc:
    case kbCr:
    case CloseEvent:
    case OutsideEvent:
    case ChDirOkayButton:
      return StopEvent;

    case ChDirRevertButton:
      setdisk(Path->SaveDisk);
      for (int i=0;i<Path->DriveCount;i++)
        if (*Path->Drives[i]=='A'+Path->SaveDisk)
          Path->CurrentDisk=i;
      strcpy(Path->Path,Path->Revert);
      chdir(Path->Path);
      Path->Refresh();
      return RefreshEvent;

    case ChDirCancelButton:
      setdisk(Path->SaveDisk);
      for (i=0;i<Path->DriveCount;i++)
        if (*Path->Drives[i]=='A'+Path->SaveDisk)
          Path->CurrentDisk=i;
      strcpy(Path->Path,Path->Revert);
      chdir(Path->Path);
      return StopEvent;
  }

  return CompleteEvent;
}

//-------------------------------------------------------------------------
//
// ChDirPath element that permits typing of a path
//
//-------------------------------------------------------------------------

ChDirPath::ChDirPath(int X,int Y,PathStorage &_Path) :
  Path(_Path),
  DiaChar(X,Y,0,_Path.Path,0,'X',40,1)
{
  ComparePathStorage=new char[50];
  strcpy(ComparePathStorage,Path.Path);
}

ChDirPath::~ChDirPath()
{
  delete ComparePathStorage;
}

int ChDirPath::EventHandler(int Event)
{
  if (Event==kbCr)
  {
    if (strcmp(Path.Path,ComparePathStorage))
    {
      char Drive[MAXDRIVE];
      char Dir[MAXDIR];
      char File[MAXFILE];
      char Ext[MAXEXT];

      int Flags=fnsplit(Path.Path,Drive,Dir,File,Ext);

      if (Flags&FILENAME || Flags&DIRECTORY)
      {
        if (chdir(Path.Path))
        {
          if (strlen(Path.Path)!=2)
          {

DirError:

            InfoBox &NotAvailable = *new InfoBox;
            NotAvailable
                  + "Sorry, either you entered in an incorrect"
                  + "directory or the directory could not be"
                  + "found.  Please try again.";
            NotAvailable.Title("Not Found");
            NotAvailable.UseInfoBox();
            delete &NotAvailable;
            HighLight();
            return CompleteEvent;
          }

          if (strlen(Path.Path)==2 && Path.Path[1]!=':')
            goto DirError;
        }
      }

      if (Flags&DRIVE)
      {
        setdisk(Drive[0]-'A');

        for (int i=0;i<Path.DriveCount;i++)
        {
          if (*(Path.Drives[i]+0)==Drive[0])
          {
            Path.CurrentDisk=i;
            break;
          }
        }
      }

      Path.Refresh();
      CurrentLocation=0;
      strcpy(ComparePathStorage,Path.Path);
      return RefreshEvent;
    }
    return CompleteEvent;
  }
  else if (Event==' ')
    return CompleteEvent;
  else
    return DiaChar::EventHandler(Event);
}

//-------------------------------------------------------------------------
//
// Element that lists the available directories
//
//-------------------------------------------------------------------------

int ChDirList::CurrentItem=0;

ChDirList::ChDirList(int X,int Y,PathStorage &_Path) :
  Path(_Path),
  DiaStructPickList(X,Y,12,5,CurrentItem,_Path.Count,sizeof(ffblk),
  &_Path.DirEntries->ff_name)
{
}

int ChDirList::EventHandler(int Event)
{
  if (Event==kbCr || Event==' ')
  {
    chdir((Path.DirEntries+CurrentItem)->ff_name);
    Item=0;
    ItemAtTopOfList=0;
    Path.Refresh();
    ItemCount=Path.Count;
    return RefreshEvent;
  }
  else
  {
    int EventStore=DiaStructPickList::EventHandler(Event);
    if (EventStore==StopEvent)
    {
      chdir((Path.DirEntries+CurrentItem)->ff_name);
      Item=0;
      ItemAtTopOfList=0;
      Path.Refresh();
      ItemCount=Path.Count;
      return RefreshEvent;
    }
    return EventStore;
  }
}

void ChDirList::Show()
{
  if (!Path.Count)
  {
    Item=0;
    ItemAtTopOfList=0;
    ItemCount=0;
  }
  DiaStructPickList::Show();
}

//-------------------------------------------------------------------------
//
// DirList dialog that controls the display of the drives
//
//-------------------------------------------------------------------------

DirList::DirList(int X,int Y,PathStorage &_Path) :
  Path(_Path),
  DiaStructPickList(X,Y,2,5,_Path.CurrentDisk,_Path.DriveCount,2,_Path.Drives)
{
}

int DirList::EventHandler(int Event)
{
  if (Event==kbCr || Event==' ')
  {
    setdisk(*Path.Drives[Path.CurrentDisk]-'A');
    Path.Refresh();
    return RefreshEvent;
  }
  else
  {
    int EventStore=DiaStructPickList::EventHandler(Event);
    if (EventStore==StopEvent)
    {
      setdisk(*Path.Drives[Path.CurrentDisk]-'A');
      Path.Refresh();
      return RefreshEvent;
    }
    return EventStore;
  }
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
//
// Prompt class
//
// Indicates current directory and file.
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

Prompt::Prompt(PathStorage &_Path) :
  Path(_Path)
{
}

void Prompt::Show()
{
  Blaze->EraseArea(0,Blaze->WhatWinHeight()-1,Blaze->WhatWinWidth(),1,bCyan);
  (*Blaze) (1,Blaze->WhatWinHeight()-1) << bCyan << Path.Path;
}

void Prompt::HighLight()
{
}

int Prompt::Available()
{
  return FailedEvent;
}

int Prompt::EventHandler(int Event)
{
  return Event;
}
