//
// 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 <stdio.h>
#include <io.h>

#include "open.h"

#pragma warn -inl

const FileSelected=10000;
const FileFromPath=10001;

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

OpenDialog::OpenDialog(char *_Mask) : DialogClass(51,14,"Open a File")
{

  Path=new PathStorage();
  File=new FileStorage(_Mask);

  strcpy(Value,Path->Path);
  strcat(Value,File->Mask);

  FilePathed=new FilePath(6,1,*Path,*File,Value);
  Element(FilePathed);
  Help("Enter the search path and file name (masks permitted)");
  HotKey(1,1,"~Name",kbAltN);
  FusionHelp(10103);

  FileLister=new FileList(1,4,*File);

  Element(FileLister);
  Help("Select the file to load");
  HotKey(1,3,"~File",kbAltF);
  Available(File->Count);
  FusionHelp(10106);

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

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

  Element(new DiaPushButton(39,5," Open ",ChDirOkayButton,0,1));
  Help("Accept the current drive and directory");

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

  Prompt2 *Prompter=new Prompt2(*Path,*File,*FileLister);
  Element(Prompter);
  FileLister->Prompt=Prompter;

}

OpenDialog::~OpenDialog()
{
  delete Path;
  delete File;
}

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

int OpenDialog::EventHandler(int Event)
{
  switch(Event)
  {
    case kbCr:
    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 kbEsc:
    case ChDirCancelButton:
    case CloseEvent:
    case OutsideEvent:
      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;

    case FileSelected:
    case FileFromPath:
      return StopEvent;
  }

  return CompleteEvent;
}

char *OpenDialog::OpenFile()
{

  int Returned=UseDialog();

  if (Returned==ChDirOkayButton || Returned==FileSelected)
  {
    strcpy(FileCompute,(File->DirEntries+FileLister->Item)->ff_name);
    return FileCompute;
  }

  if (Returned==FileFromPath)
  {
    strcpy(FileCompute,FilePathed->Value);
    return FileCompute;
  }

  return 0;
}

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

int FileList::CurrentItem=0;

FileList::FileList(int X,int Y,FileStorage &_File) :
  File(_File),
  DiaStructPickList(X,Y,12,5,CurrentItem,_File.Count,sizeof(ffblk),
  &_File.DirEntries->ff_name)
{
  CurrentItem=0;
}

int FileList::EventHandler(int Event)
{
  if (Event==kbCr)
    return FileSelected;

  int Hold=Item;

  int EventStore=DiaStructPickList::EventHandler(Event);

  if (EventStore==StopEvent)
    return FileSelected;

  if (Hold!=Item)
    Prompt->Show();

  return Event;
}

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

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

FileStorage::FileStorage(char *_Mask)
{

  Count=0;
  strcpy(Mask,_Mask);

  DirEntries=new ffblk[MaxEntries];

  Refresh();

}

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

void FileStorage::Refresh()
{
  int Done;

  ffblk DummyStorage;

  if (Mask)
    Done=findfirst(Mask,&DummyStorage,0);
  else
    Done=findfirst("*.*",&DummyStorage,0);

  Count=0;

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

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

FileStorage::~FileStorage()
{
  if (DirEntries)
    delete DirEntries;
}

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

FilePath::FilePath(int X,int Y,PathStorage &_Path,FileStorage &_File,char *Merge) :
  Path(_Path),
  File(_File),
  DiaChar(X,Y,0,Merge,0,'X',42,1)
{
  Reset=1;
  ComparePathStorage=new char[65];
  strcpy(ComparePathStorage,Path.Path);
  strcat(ComparePathStorage,File.Mask);
  strcpy(GetMask,File.Mask);
}

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

int FilePath::Departure()
{
  strcpy(Value,Path.Path);
  strcat(Value,File.Mask);

  return RefreshEvent;
}

int FilePath::EventHandler(int Event)
{
  if (Event==kbCr)
  {
    if (strcmp(Value,ComparePathStorage))
    {
      Reset=1;

      char Drive[MAXDRIVE];
      char Dir[MAXDIR];
      char File[MAXFILE];
      char Ext[MAXEXT];

      // See if changing directory

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

      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;
          }
        }
      }

      if (Flags&DIRECTORY || Flags&FILENAME)
      {
        char Value[MAXPATH];

        if (Flags&WILDCARDS && Flags&DIRECTORY)
        {
          strcpy(Value,Dir);
          if (Value[strlen(Value)-1]=='\\' && strlen(Value)!=1)
            Value[strlen(Value)-1]=0;
        }
        else if (Flags&DIRECTORY)
          strcpy(Value,FilePath::Value);
//        else if (Flags&FILENAME)
  //        strcpy(Value.FilePath::File);  // <<--- bug fixed 11/18
        else
          strcpy(Value,".");

        if (chdir(Value) || (!Value[1] && Value[0]=='.'))
        {
          if (!(Flags&WILDCARDS))
          {
            if (!access(FilePath::Value,0))
              return FileFromPath;

            fnsplit(GetMask,Drive,Dir,File,Ext);

            char WildFile[80];
            strcpy(WildFile,FilePath::Value);
            strcat(WildFile,Ext);

            if (!access(WildFile,0))
            {
              strcpy(FilePath::Value,WildFile);
              return FileFromPath;
            }
          }
          else if (!(Flags&DIRECTORY))
            goto WildCheck;

          if (strlen(Value)!=2)
          {

DirError:

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

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

WildCheck:

      if (Flags&WILDCARDS)
      {
        char JoinWildCards[15];

        JoinWildCards[0]=0;

        if (File[0])
          strcat(JoinWildCards,File);

        if (Ext[0])
          strcat(JoinWildCards,Ext);

        strcpy(FilePath::File.Mask,JoinWildCards);
      }

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

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

int ChDirList2::CurrentItem=0;

ChDirList2::ChDirList2(int X,int Y,PathStorage &_Path,FileStorage &_File,
  FilePath &_PathEntry) :
  Path(_Path),
  File(_File),
  PathEntry(_PathEntry),
  DiaStructPickList(X,Y,12,5,CurrentItem,_Path.Count,sizeof(ffblk),
  &_Path.DirEntries->ff_name)
{
  CurrentItem=0;
}

int ChDirList2::EventHandler(int Event)
{
  if (Event==kbCr || Event==' ')
  {
    chdir((Path.DirEntries+CurrentItem)->ff_name);
    Item=0;
    ItemAtTopOfList=0;
    Path.Refresh();
    File.Refresh();
    ItemCount=Path.Count;
    strcpy(PathEntry.Value,Path.Path);
    strcat(PathEntry.Value,File.Mask);
    return RefreshEvent;
  }
  else
  {
    int EventStore=DiaStructPickList::EventHandler(Event);
    if (EventStore==StopEvent)
    {
      chdir((Path.DirEntries+CurrentItem)->ff_name);
      Item=0;
      ItemAtTopOfList=0;
      Path.Refresh();
      File.Refresh();
      ItemCount=Path.Count;
      strcpy(PathEntry.Value,Path.Path);
      strcat(PathEntry.Value,File.Mask);
      return RefreshEvent;
    }
    return EventStore;
  }
}

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

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

DirList2::DirList2(int X,int Y,PathStorage &_Path,FileStorage &_File,
  FilePath &_PathEntry) :
  Path(_Path),
  File(_File),
  PathEntry(_PathEntry),
  DiaStructPickList(X,Y,2,5,_Path.CurrentDisk,_Path.DriveCount,2,_Path.Drives)
{
}

int DirList2::EventHandler(int Event)
{
  if (Event==kbCr || Event==' ')
  {
    setdisk(*Path.Drives[Path.CurrentDisk]-'A');
    Path.Refresh();
    File.Refresh();
    strcpy(PathEntry.Value,Path.Path);
    strcat(PathEntry.Value,File.Mask);
    return RefreshEvent;
  }
  else
  {
    int EventStore=DiaStructPickList::EventHandler(Event);
    if (EventStore==StopEvent)
    {
      setdisk(*Path.Drives[Path.CurrentDisk]-'A');
      Path.Refresh();
      File.Refresh();
      strcpy(PathEntry.Value,Path.Path);
      strcat(PathEntry.Value,File.Mask);
      return RefreshEvent;
    }
    return EventStore;
  }
}

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

Prompt2::Prompt2(PathStorage &_Path,FileStorage &_File,FileList &_List) :
  Path(_Path),
  File(_File),
  List(_List)
{
}

void Prompt2::Show()
{
  MouseHide();

  Blaze->EraseArea(0,Blaze->WhatWinHeight()-2,Blaze->WhatWinWidth(),2,bCyan);
  (*Blaze) (1,Blaze->WhatWinHeight()-1) << bCyan << Path.Path;

  if (File.Count)
  {
    char *Months[] =
    {
      "Jan","Feb","Mar","Apr","May","Jun",
      "Jul","Aug","Sep","Oct","Nov","Dec"
    };

    union
    {
      int Date;
      struct
      {
        unsigned Day : 5;
        unsigned Month : 4;
        unsigned Year : 7;
      } Bits;
    } Date;

    union
    {
      int Time;
      struct
      {
        unsigned Seconds : 5;
        unsigned Minutes : 6;
        unsigned Hours : 5;
      } Bits;
    } Time;

    char FileInfo[51];

    Date.Date=(File.DirEntries+List.Item)->ff_fdate;
    Time.Time=(File.DirEntries+List.Item)->ff_ftime;

    sprintf(FileInfo,"%-12s       %7ld  %3s %2d, %4d  %02d:%02d",
      (File.DirEntries+List.Item)->ff_name,
      (File.DirEntries+List.Item)->ff_fsize,
      Months[Date.Bits.Month-1],Date.Bits.Day,Date.Bits.Year+1980,
      Time.Bits.Hours,Time.Bits.Minutes);

    (*Blaze) (1,Blaze->WhatWinHeight()-2) << bCyan << FileInfo;
  }

  MouseShow();
}

void Prompt2::HighLight()
{
}

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

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