//
// The Fusion Library Interface for DOS
// Version 1.06c
// Copyright (C) 1990, 1991, 1992
// Software Dimensions
//
// DialogClass
// DiaMulti - MLEE (Multi Line Edit Element, pronouced Millie)
//

#include "fli.h"
#include "elements.h"
#include "colors.h"

#ifdef __BCPLUSPLUS__
#pragma hdrstop
#endif

#include <alloc.h>
#include <ctype.h>
#include <string.h>
#include <dos.h>
#include <mem.h>

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
//
// DiaMulti()
//
// Constructor
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

DiaMulti::DiaMulti(int _X,int _Y,int _Width,int _Height,char *Storage)
{
  X=_X;
  Y=_Y;
  Width=_Width;
  Height=_Height;

  CurX=0;
  CurY=0;
  Relative=0;

  MaxWidth=Width*Height;

  String=Storage;
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
//
// Triangulate()
//
// Locates the start and end of a particular line.  This will feed the
// Start and End variable members of the DiaMulti class.
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

void DiaMulti::Triangulate(int Line)
{
  Start=0;
  End=0;

  int OutputY=0;
  int EndOfLastLine=0;

  if (!strlen(String))
    return;
  else
  {
    char *String=DiaMulti::String;

    int StrWidth=strlen(String);

    do
    {
      if (Width>StrWidth)
      {
        if (Line==OutputY)
        {
          Start=EndOfLastLine;
          End=EndOfLastLine+strlen(String+EndOfLastLine);
          break;
        }

        OutputY++;
        StrWidth=-1;

        break;
      }
      else
      {
        int i;

        if (*(String+EndOfLastLine+Width-1)!=' ')
        {
          for (i=EndOfLastLine+Width-1;i>=EndOfLastLine;i--)
            if (*(String+i)==' ')
              break;

          if (i<EndOfLastLine || *(String+i)!=' ')
            i=EndOfLastLine+Width-1;
        }
        else
          i=EndOfLastLine+Width-1;

        if (EndOfLastLine+Width-1>strlen(String))
          i=EndOfLastLine+(strlen(String)-EndOfLastLine)-1;

        if (OutputY==Height-1 && *(String+i+1))
        {
          for (;i<EndOfLastLine+Width;i++)
            if (!*(String+i))
              break;
          if (*(String+i))
            *(String+i)=0;
          if (Relative>EndOfLastLine+Width-1)
            Relative=EndOfLastLine+Width-1;
        }

        if (Line==OutputY)
        {
          Start=EndOfLastLine;
          End=i;
          break;
        }

        StrWidth-=((i-EndOfLastLine)+1);
        EndOfLastLine=i+1;
        OutputY++;
      }
    }
    while (StrWidth>=0 && OutputY<Height);
  }
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
//
// Display()
//
// Display MLEE - accepts variable colors
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

void DiaMulti::Display(int Color)
{
  CurX=0;
  CurY=0;

  MouseHide();

  (*Blaze) << Color;

  for (int i=0;i<Height;i++)
  {
    Triangulate(i);

    if (!Start && !End)
      Blaze->CharacterRepeater(X,Y+i,Width,Color,' ');
    else
    {
      for (int j=Start;j<End;j++)
        (*Blaze) (X+(j-Start),Y+i) << *(String+j);
      if (End-Start<Width)
        for (j;j<End+(Width-(End-Start));j++)
          (*Blaze) (X+(j-Start),Y+i) << ' ';
      if (Relative>=Start && Relative<=End)
      {
        CurY=i;
        CurX=Relative-Start;
      }
    }
  }

  if (!CurX && !CurY && Relative)
  {
    for (i=Height-1;i>=0;i--)
    {
      Triangulate(i);
      if (End)
      {
        CurY=i;
        CurX=End-Start;
        break;
      }
    }
  }

  Blaze->WindowGotoXY(X+CurX,Y+CurY);

  MouseShow();
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
//
// Show()
//
// Show the character element
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

static int InsertMode=0;

void DiaMulti::Show()
{
  Blaze->BigCursor(0);

  if (Relative>strlen(String))
    Relative=strlen(String);

  Display((Available()==CompleteEvent)?Colors.CharNormal:Colors.DiaDeadLocator);
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
//
// HighLight()
//
// Highlight the character element
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

void DiaMulti::HighLight()
{
  Blaze->BigCursor(InsertMode);

  if (Relative>strlen(String))
    Relative=strlen(String);

  Display(Colors.CharHiLite);
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
//
// EventHandler()
//
// Handles the events
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

int DiaMulti::EventHandler(int Event)
{
  switch(Event)
  {
    case kbBackSpace:
      if (!Relative)
        return CompleteEvent;

      Relative--;

    case kbDel:
      if (Event!=kbBackSpace && !*(String+Relative))
        return CompleteEvent;

      if (Relative<strlen(String)-1)
        movmem(String+Relative+1,String+Relative,strlen(String)-Relative);
      else
        *(String+Relative)=0;

      HighLight();

      return CompleteEvent;

    case kbLeft:
      if (Relative)
      {
        Relative--;
        HighLight();
      }

      return CompleteEvent;

    case kbRight:
      if (Relative<strlen(String))
      {
        Relative++;
        HighLight();
      }

      return CompleteEvent;

    case kbUp:
      if (CurY)
      {
        Triangulate(CurY);
        int Calc=Relative-Start;
        Triangulate(CurY-1);
        int NewPos=Start+Calc;
        if (NewPos>=Start && NewPos<=End)
        {
          Relative=NewPos;
          HighLight();
        }
      }

      return CompleteEvent;

    case kbDown:
      if (CurY!=Height-1)
      {
        Triangulate(CurY);
        int Calc=Relative-Start;
        Triangulate(CurY+1);

        if (!Start && !End)
          return CompleteEvent;

        int NewPos=Start+Calc;
        if (NewPos>=Start && NewPos<=End)
        {
          Relative=NewPos;
          HighLight();
        }
      }

      return CompleteEvent;

    case kbHome:
      Relative=0;
      HighLight();

      return CompleteEvent;

    case kbEnd:
      Relative=strlen(String);
      HighLight();

      return CompleteEvent;

    case kbCtrlLeftArrow:
      if (Relative)
      {
        int SpareRelative=Relative;

        if (*(String+SpareRelative)!=' ')
        {
          if (SpareRelative && *(String+SpareRelative-1)==' ')
          {
            SpareRelative--;
            while (SpareRelative && *(String+SpareRelative)==' ')
              SpareRelative--;
          }
          while (SpareRelative && *(String+SpareRelative)!=' ')
            SpareRelative--;
          if (SpareRelative)
            SpareRelative++;
          Relative=SpareRelative;
        }
        else
        {
          while (SpareRelative && *(String+SpareRelative)==' ')
            SpareRelative--;
          while (SpareRelative && *(String+SpareRelative)!=' ')
            SpareRelative--;
          if (SpareRelative)
            SpareRelative++;
          Relative=SpareRelative;
        }

        HighLight();
      }

      return CompleteEvent;

    case kbCtrlRightArrow:
      if (*(String+Relative))
      {
        int SpareRelative=Relative;

        if (*(String+SpareRelative)!=' ')
        {
          if (*(String+SpareRelative) && *(String+SpareRelative+1)==' ')
          {
            SpareRelative++;
            while (*(String+SpareRelative) && *(String+SpareRelative)==' ')
              SpareRelative++;
          }
          while (*(String+SpareRelative) && *(String+SpareRelative)!=' ')
            SpareRelative++;
          if (*(String+SpareRelative))
            SpareRelative++;
          Relative=SpareRelative;
        }
        else
        {
          while (*(String+SpareRelative) && *(String+SpareRelative)==' ')
            SpareRelative++;
          while (*(String+SpareRelative) && *(String+SpareRelative)!=' ')
            SpareRelative++;
          if (SpareRelative)
            SpareRelative++;
          Relative=SpareRelative;
        }

        HighLight();
      }

      return CompleteEvent;

    case kbCtrlY:
      if (strlen(String))
      {
        Triangulate(CurY);
        movmem((String+End),(String+Start),strlen(String)-End+1);
        if (Relative>strlen(String)-1)
          Relative=strlen(String)-1;
        else
        {
          Triangulate(CurY);
          Relative=Start;
        }

        HighLight();
      }

      return CompleteEvent;

    case kbCtrlT:
      if (*(String+Relative))
      {
        int SpareRelative=Relative;

        while (SpareRelative && *(String+SpareRelative)!=' ')
          SpareRelative--;

        if (!SpareRelative)
          SpareRelative--;

        Relative=SpareRelative+1;

        int End=SpareRelative+1;
        while (*(String+End) && *(String+End)!=' ')
          End++;

        if (*(String+End))
          End++;

        movmem((String+End),(String+SpareRelative+1),strlen(String)-End+1);

        HighLight();
      }

      return CompleteEvent;

    case kbIns:
      InsertMode=(InsertMode)?0:1;
      Blaze->BigCursor(InsertMode);
      return CompleteEvent;

    case ValidatedMousedEvent:
      if (MouseEvent&MouseDoubleClick)
        return ClickEvent;
      if (MouseEvent&MouseLeftButtonRelease)
      {
        MouseVertical-=Y;
        MouseHorizontal-=X;

        Triangulate(MouseVertical);

        if (!Start && !End)
          return CompleteEvent;

        if ((MouseHorizontal<End-Start) ||
          (!*(String+End-Start) && MouseHorizontal==End-Start))
        {
          Relative=Start+MouseHorizontal;
          HighLight();
        }
      }

      return CompleteEvent;

    default:
      if (Event>=' ' && Event<='~')
      {
        if (!*(String+Relative))
        {
          *(String+Relative++)=Event;
          *(String+Relative)=0;
          HighLight();
          return CompleteEvent;
        }

        if (!InsertMode)
        {
          *(String+Relative++)=Event;
          HighLight();
          return CompleteEvent;
        }
        else
        {
          movmem((String+Relative),(String+Relative+1),
            strlen(String)-Relative+1);
          *(String+Relative++)=Event;
          HighLight();
          return CompleteEvent;
        }
      }
  }
  return Event;
}
