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

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

#include <stdio.h>
#include <alloc.h>
#include <mem.h>
#include <string.h>
#include <io.h>

#include "open.h"
#include "saveas.h"
#include "yesno.h"

//-------------------------------------------------------------------------
//
// This is the event handler for the dialog window
// The global event handler is in GLOBAL.CPP
//
// Other definitions for the dialog window class are farther down
// in this file.
//
//-------------------------------------------------------------------------

int DialogWindow::EventHandler(int Event)
{
  switch(Event)
  {
    case winOpen:
      OpenDialog &Open=*new OpenDialog("*.DDS");
      char *File=Open.OpenFile();
      char Storage[100];

      if (File)
        strcpy(FileName,File);
      else
        strcpy(FileName,"");

      delete &Open;

      if (FileName[0])
        LoadFile(FileName);
      return RefreshEvent;

    case winSave:

      int SaveAsed=0;

ReRequestSave:

      if (!FileName[0])
      {
        SaveAs &Dialog=*new SaveAs("Save File As");
        int Load=Dialog.UseDialog();
        if (Load==FileSaveAs || Load==kbCr)
        {
          if (Dialog.FileName[0])
            strcpy(FileName,Dialog.FileName);
        }
        else
        {
          delete &Dialog;
          return CompleteEvent;
        }
        delete &Dialog;
        SaveAsed=1;
      }

      if (!strstr(FileName,".DDS"))
      {
        char Test[100];
        strcpy(Test,FileName);
        strcat(Test,".DDS");
        if (!access(Test,0))
        {
          YesNo &Query=*new YesNo();
          Query + "A file by that name already exists!"
                + ""
                + "Are you sure you want to save over it?";
          Query.Title("Warning");
          int Response=Query.UseYesNo();
          delete &Query;
          if (!Response && !SaveAsed)
            return CompleteEvent;
          else if (!Response && SaveAsed)
          {
            FileName[0]=0;
            goto ReRequestSave;
          }
        }
        SaveFile(Test);
      }
      else
      {
        if (!access(FileName,0))
        {
          YesNo &Query=*new YesNo();
          Query + "A file by that name already exists!"
                + ""
                + "Are you sure you want to save over it?";
          Query.Title("Warning");
          int Response=Query.UseYesNo();
          delete &Query;
          if (!Response && !SaveAsed)
            return CompleteEvent;
          else if (!Response && SaveAsed)
          {
            FileName[0]=0;
            goto ReRequestSave;
          }
        }
        SaveFile(FileName);
      }

      return CompleteEvent;

    case winSaveAs:

ReRequestSaveAs:

      if (strchr(FileName,'.'))
        *(strchr(FileName,'.'))=0;

      SaveAs &Dialog=*new SaveAs("Save File As");
      strcpy(Dialog.FileName,FileName);
      int Load=Dialog.UseDialog();
      if (Load==FileSaveAs || Load==kbCr)
      {
        if (Dialog.FileName[0])
          strcpy(FileName,Dialog.FileName);
      }
      else
      {
        delete &Dialog;
        return CompleteEvent;
      }
      delete &Dialog;

      if (FileName[0])
      {
        if (!strstr(FileName,".DDS"))
        {
          char Test[100];
          strcpy(Test,FileName);
          strcat(Test,".DDS");
          if (!access(Test,0))
          {
            YesNo &Query=*new YesNo();
            Query + "A file by that name already exists!"
                  + ""
                  + "Are you sure you want to save over it?";
            Query.Title("Warning");
            int Response=Query.UseYesNo();
            delete &Query;
            if (!Response)
              goto ReRequestSaveAs;
          }
          SaveFile(Test);
        }
        else
        {
          if (!access(FileName,0))
          {
            YesNo &Query=*new YesNo();
            Query + "A file by that name already exists!"
                  + ""
                  + "Are you sure you want to save over it?";
            Query.Title("Warning");
            int Response=Query.UseYesNo();
            delete &Query;
            if (!Response)
              goto ReRequestSaveAs;
          }
          SaveFile(FileName);
        }
      }

      return CompleteEvent;

    case winGenCPP:

ReRequest:

      char Loader[50];

      SaveAs &Dia=*new SaveAs("Generate Into");
      strcpy(Dia.FileName,"");
      Load=Dia.UseDialog();
      if (Load==FileSaveAs || Load==kbCr)
      {
        if (Dia.FileName[0])
          strcpy(Loader,Dia.FileName);
      }
      else
      {
        delete &Dia;
        return CompleteEvent;
      }
      delete &Dia;

      if (Loader[0])
      {
        if (!strstr(Loader,".CPP"))
        {
          char Test[100];
          strcpy(Test,Loader);
          strcat(Test,".CPP");
          if (!access(Test,0))
          {
            YesNo &Query=*new YesNo();
            Query + "That file exists!"
                  + ""
                  + "Are you sure you want to save over it?";
            Query.Title("Warning");
            int Response=Query.UseYesNo();
            delete &Query;
            if (!Response)
              goto ReRequest;
          }
          Generate(Test);
        }
        else
        {
          if (!access(Loader,0))
          {
            YesNo &Query=*new YesNo();
            Query + "That file exists!"
                  + ""
                  + "Are you sure you want to save over it?";
            Query.Title("Warning");
            int Response=Query.UseYesNo();
            delete &Query;
            if (!Response)
              goto ReRequest;
          }
          Generate(Loader);
        }
      }
      return CompleteEvent;

    case winNew:
      if (NumberPieces)
      {
        YesNo &Query=*new YesNo();
        Query + "There is stuff on this dialog!"
              + ""
              + "Are you sure you want to clear it?";
        Query.Title("Warning");
        int Response=Query.UseYesNo();
        delete &Query;
        if (!Response)
          return CompleteEvent;
      }

      RemoveTheMenus();

      if (NumberPieces)
      {
        for (int i=0;i<NumberPieces;i++)
          delete Pieces[i];
        free(Pieces);
        Pieces=0;
        NumberPieces=0;
        CursorX=0;
        CursorY=0;
        Insert=0;
        FileName[0]=0;
        X=0;
        Y=1;
        Width=Blaze.WhatWidth();
        Height=Blaze.WhatHeight()-2;
        strcpy(DerivedClass,"DiaDerived");
        if (Title)
        {
          delete Title;
          Title=0;
        }
        CurrentColor=Colors.DiaInterior;
      }

      for (int y=0;y<60;y++)
        for (int x=0;x<sizeof(Interior[0]);x+=2)
        {
          *(Interior[y]+x)=0;
          *(Interior[y]+x+1)=WinInterior;
        }

      return RefreshEvent;

    case layoutTest:
      TestDialog();
      return CompleteEvent;

    case layoutSpecs:
      LayOut();
      return RefreshEvent;

    case layoutEditMode:
      RemoveTheMenus();
      VirtualizedInterior();
      return CompleteEvent;

    case drawColor:
      ChangeColor();
      return CompleteEvent;

    case drawBox:
      PlaceObject(PieceHandler::Box);
      return CompleteEvent;

    case drawFillBox:
      PlaceObject(PieceHandler::FilledBox);
      return CompleteEvent;

    case drawHLine:
			PlaceObject(PieceHandler::HorizontalLine);
      return CompleteEvent;

    case drawVLine:
      PlaceObject(PieceHandler::VerticalLine);
      return CompleteEvent;

    case drawShadow:
      PlaceObject(PieceHandler::Shadow);
      return CompleteEvent;

    case drawErase:
      PlaceObject(PieceHandler::EraseArea);
      return CompleteEvent;

    case drawTrans:
      PlaceObject(PieceHandler::ColorizeArea);
      return CompleteEvent;

    case elementChar:
      PlaceElement(PieceHandler::Character);
      return CompleteEvent;

    case elementInt:
      PlaceElement(PieceHandler::Integer);
      return CompleteEvent;

    case elementLong:
      PlaceElement(PieceHandler::Long);
      return CompleteEvent;

    case elementFloat:
      PlaceElement(PieceHandler::Float);
      return CompleteEvent;

    case elementDouble:
      PlaceElement(PieceHandler::Double);
      return CompleteEvent;

    case elementBcd:
      PlaceElement(PieceHandler::Bcd);
      return CompleteEvent;

    case elementCheck:
      PlaceElement(PieceHandler::Check);
      return CompleteEvent;

    case elementPush:
      PlaceElement(PieceHandler::Push);
      return CompleteEvent;

    case elementHeading:
      PlaceElement(PieceHandler::GroupHeading);
      return CompleteEvent;

    case elementHRadio:
      PlaceElement(PieceHandler::HRadio);
      return CompleteEvent;

    case elementVRadio:
      PlaceElement(PieceHandler::VRadio);
      return CompleteEvent;

    case elementPickGeneric:
      PlaceElement(PieceHandler::PickGeneric);
      return CompleteEvent;

    case manipMove:
      MoveObject();
      return CompleteEvent;

    case manipSize:
      SizeObject();
      return CompleteEvent;

    case manipForward:
      BringFront();
			return CompleteEvent;

    case manipBack:
      PushBack();
      return CompleteEvent;

    case manipCopy:
      CopyObject();
      return CompleteEvent;

    case manipObjectColor:
      ColorObject();
      return CompleteEvent;

    case manipDeletePiece:
      DeleteObject();
      return CompleteEvent;

    case manipTextColor:
      ColorText();
      return CompleteEvent;

    case manipMoveText:
      MoveText();
      return CompleteEvent;

    case manipCopyText:
      CopyText();
      return CompleteEvent;

    case manipToStart:
      ManipToStart();
      return CompleteEvent;

    case manipToEnd:
      ManipToEnd();
      return CompleteEvent;

    case manipEarlier:
      ManipEarlier();
      return CompleteEvent;

    case manipLater:
      ManipLater();
      return CompleteEvent;


    case kbRight:
      if (CursorX<=Blaze.WhatWinWidth()-1)
      {
        CursorX++;
        Cursor();
      }
      return CompleteEvent;

    case kbLeft:
      if (CursorX)
      {
				CursorX--;
        Cursor();
      }
      return CompleteEvent;

    case kbDown:
      if (CursorY<=Blaze.WhatWinHeight()-1)
      {
        CursorY++;
        Cursor();
      }
      return CompleteEvent;

    case kbUp:
      if (CursorY)
      {
        CursorY--;
        Cursor();
      }
      return CompleteEvent;

    case kbHome:
      CursorX=0;
      Cursor();
      return CompleteEvent;

    case kbEnd:
      CursorX=Blaze.WhatWinWidth()-1;
      Cursor();
      return CompleteEvent;

    case kbPgUp:
      CursorY=0;
			Cursor();
      return CompleteEvent;

    case kbPgDn:
      CursorY=Blaze.WhatWinHeight()-1;
      Cursor();
      return CompleteEvent;

    case kbCr:
      CursorX=0;
      if (CursorY<=Blaze.WhatWinHeight()-1)
      {
        CursorY++;
        Cursor();
      }
      return CompleteEvent;

    case kbIns:
      Insert=(Insert)?0:1;
      {
        BlazeClass Blaze;

        Blaze (X+Width-5,Y+Height-1) << WinTitle << ((Insert)?"Ins":"Ovr");
      }
      return CompleteEvent;

    case ValidatedMousedEvent:
      if (MouseEvent&MouseLeftButtonRelease || MouseButtonStatus&LeftButton)
      {
        CursorX=MouseHorizontal;
        CursorY=MouseVertical;
        Cursor();
      }
      if (MouseEvent&MouseLeftButtonPress)
        MoveObject(1);
      return CompleteEvent;

    case kbDel:
			memmove((Interior[CursorY]+(CursorX*2)),(Interior[CursorY]+(CursorX*2)+2),
        sizeof(Interior[0])-(CursorX*2));
      VirtualizedInterior();
      return CompleteEvent;

    case kbBackSpace:
      if (!Insert)
      {
        if (!CursorX)
          return CompleteEvent;
        CursorX--;
        *(Interior[CursorY]+(CursorX*2))=0;
        *(Interior[CursorY]+(CursorX*2)+1)=CurrentColor;
        VirtualizedInterior();
        return CompleteEvent;
      }
      else
      {
        if (!CursorX)
          return CompleteEvent;
        CursorX--;
        memmove((Interior[CursorY]+(CursorX*2)),(Interior[CursorY]+(CursorX*2)+2),
          sizeof(Interior[0])-(CursorX*2));
        VirtualizedInterior();
        return CompleteEvent;
      }

    case drawPlop:
			int Plopped=PlopCharacter();

			if (Plopped)
			{
				Event=Plopped;
				RemoveTheMenus();
				goto PlopChar;
			}

			return CompleteEvent;

	 	default:
			if (Event>=' ' && Event<='~')
			{

PlopChar:

				if (!Insert)
				{
          *(Interior[CursorY]+(CursorX*2))=Event;
          *(Interior[CursorY]+(CursorX*2)+1)=CurrentColor;
          if (CursorX<=Blaze.WhatWinWidth()-1)
          {
            CursorX++;
            Cursor();
          }
          VirtualizedInterior();
          return CompleteEvent;
        }
        else
        {
          memmove((Interior[CursorY]+(CursorX*2)+2),(Interior[CursorY]+(CursorX*2)),
            sizeof(Interior[0])-(CursorX*2));

          *(Interior[CursorY]+(CursorX*2))=Event;
          *(Interior[CursorY]+(CursorX*2)+1)=CurrentColor;
          if (CursorX<=Blaze.WhatWinWidth()-1)
					{
            CursorX++;
            Cursor();
          }
          VirtualizedInterior();
          return CompleteEvent;
        }
			}
	}
	return Event;
}

//-------------------------------------------------------------------------
//
// This is a nifty function that virtualizes the interior of the DDS
// window so flicker doesn't happen when it is updated.  This function
// is necessary since each time a new character is placed into the window
// it must be updated "flicker free".
//
//-------------------------------------------------------------------------

void DialogWindow::VirtualizedInterior()
{
  int X, Y, Width, Height;

  Blaze.WindowInformation(X,Y,Width,Height);
  char *VirtualizedScreen=new char[(Blaze.WhatWidth()*2)*Blaze.WhatHeight()];
  Blaze.UseMemory(VirtualizedScreen);

  ShowInterior();

  MouseHide();
  Blaze.UseVideo();
  Blaze.BlockCopyVirtualToVisual(X,Y,Width,Height,VirtualizedScreen);
  delete VirtualizedScreen;
  MouseShow();
}

//-------------------------------------------------------------------------
//
// This displays the interior of the dialog window -- all objects and
// elements are drawn in the exact order in which they will be drawn
// on the generated dialog
//
//-------------------------------------------------------------------------

void DialogWindow::ShowInterior()
{
  MouseHide();

  int X, Y, Width, Height;

  Blaze.WindowInformation(X,Y,Width,Height);

  Blaze.EraseArea(0,0,Width,Height,WinInterior);

  int Object=1;
  char ZPos[10];

	// Blaze Drawing Tools

  if (NumberPieces)
  {
    for (int i=0;i<NumberPieces;i++)
    {
      PieceHandler &Piece=*Pieces[i];
      if (Piece.LayOut<PieceHandler::__DUMMY__)
      {
        Piece.DrawFigure();
        if (ZPositioning)
        {
          sprintf(ZPos,"O%d",Object++);
          Blaze (Piece.X,Piece.Y) << Piece.Color << ZPos;
        }
      }
    }
  }

  // Blaze Text

  for (int y=0;y<Height;y++)
  {
    char *OutPut=Interior[y];
    for (int x=0;x<Width;x++,OutPut+=2)
    {
      if (*OutPut)
        Blaze (x,y) << (int)*(OutPut+1) << *OutPut;
    }
  }

  // Elements

  if (NumberPieces)
  {
    Object=1;

    for (int i=0;i<NumberPieces;i++)
    {
      PieceHandler &Piece=*Pieces[i];
      if (Piece.LayOut>PieceHandler::__DUMMY__ && Piece.LayOut<PieceHandler::__DUMMY2__)
      {
        Piece.DrawFigure();
        if (ZPositioning)
        {
          sprintf(ZPos,"E%d",Object++);
          Blaze (Piece.X,Piece.Y) << Piece.Color << ZPos;

          if (Piece.Prompter && *Piece.Prompter)
            Blaze (Piece.PromptX,Piece.PromptY) << Colors.DiaLocator << ZPos;
        }
      }
    }
  }

  // Group headings

  if (NumberPieces)
  {
    for (int i=0;i<NumberPieces;i++)
    {
      PieceHandler &Piece=*Pieces[i];
      if (Piece.LayOut>PieceHandler::__DUMMY2__)
        Piece.DrawFigure();
    }
  }

  MouseShow();
}

//-------------------------------------------------------------------------
//
// This displays the cursor inside the dialog window
//
// It also display the current location and a count of elements and objects
//
//-------------------------------------------------------------------------

void DialogWindow::Cursor()
{
  Blaze.VisibleCursor();
  if (CursorY>Blaze.WhatWinHeight()-1)
    CursorY=Blaze.WhatWinHeight()-1;
  if (CursorX>Blaze.WhatWinWidth()-1)
    CursorX=Blaze.WhatWinWidth()-1;
  Blaze.WindowGotoXY(CursorX,CursorY);

  int Objects=0;
  int Elements=0;

  if (NumberPieces)
  for (int i=0;i<NumberPieces;i++)
  {
    if (Pieces[i]->LayOut<PieceHandler::__DUMMY__)
      Objects++;
    else if (Pieces[i]->LayOut<PieceHandler::__DUMMY2__)
      Elements++;
  }

  BlazeClass Blaze;
  char Locate[25];
  sprintf(Locate,"%03dO %03dE %03dX %03dY",Objects,Elements,CursorX,CursorY);
  Blaze (Blaze.WhatWidth()-31,0) << Colors.PromptLineBold << Locate;
}

//-------------------------------------------------------------------------
//
// This overrides the ShowWindow virtual function in the WindowElement
// class so we can draw a couple of extra items on the border of the dialog
// box.  These items are the current color and insert mode status indicator.
//
// This illustrates how you can mess with the outside of the window.  You
// can use this in your own programs!
//
//-------------------------------------------------------------------------

void DialogWindow::ShowWindow()
{
  WindowElement::ShowWindow();

  BlazeClass InsBlaze;
  InsBlaze.UseMemory(Blaze.WhatOutput());

  InsBlaze (X+Width-5,Y+Height-1) << WinTitle << ((Insert)?"Ins":"Ovr");
  InsBlaze (X+2,Y+Height-1) << CurrentColor << "Color";
}

//-------------------------------------------------------------------------
//
// This is the constructor for the Dialog Window
//
//-------------------------------------------------------------------------

DialogWindow::DialogWindow(char *LoadIt)
{
  if (!LoadIt)
    FileName[0]=0;
  else
    strcpy(FileName,LoadIt);

  ZoomIcon=0;

  CursorX=0;
  CursorY=0;

  Interior=0;
  Insert=0;

  strcpy(DerivedClass,"DiaDerived");

  CurrentColor=Colors.DiaInterior;

  WinInterior=Colors.DiaInterior;
  WinBorder=Colors.DiaBorder;
  WinIcons=Colors.DiaCloseIcon;
  WinTitle=Colors.DiaTitle;
  WinSizeCorner=Colors.DiaCloseIcon;

  Interior=new char[61][sizeof(Interior[0])];

  for (int y=0;y<60;y++)
    for (int x=0;x<sizeof(Interior[0]);x+=2)
    {
      *(Interior[y]+x)=0;
      *(Interior[y]+x+1)=WinInterior;
    }

  Pieces=0;
  NumberPieces=0;

  if (!(!Blaze))
    !Blaze;

  if (!(+Blaze))
    +Blaze;

  if (LoadIt)
    LoadFile(FileName);
}

//-------------------------------------------------------------------------
//
// This is the destructor for the Dialog Window
//
//-------------------------------------------------------------------------

DialogWindow::~DialogWindow()
{
  delete Interior;

  if (Title)
    delete Title;

  if (Pieces)
  {
    for (int i=0;i<NumberPieces;i++)
      delete Pieces[i];
    free(Pieces);
  }
}


