//
// The Fusion Library Interface for DOS
// Version 1.06c
// Copyright (C) 1990, 1991, 1992
// Software Dimensions
//
// DialogClass
// DiaChar
//

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

#ifdef __BCPLUSPLUS__
#pragma hdrstop
#if defined(__SMALL__) || defined(__TINY__) || defined(__MEDIUM__)
#pragma option -Od
#endif
#endif

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

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
//
// MaskSet define
//
// Defines the characters available in the masking set
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

#define MaskSet "xXaALlUu0123456789#"

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
//
// DiaChar()
//
// Constructor
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

DiaChar::DiaChar(int _X,int _Y,char *_Mask,char *_Value,int _VisualWidth,
  char MaskCharacter,int MaskWidth,int _NoEditErase)
{
  X=_X;
  Y=_Y;
  Mask=_Mask;
  Value=_Value;
  if (!MaskWidth)
    Width=strlen(Mask);
  Height=1;
  AtLeft=0;
  NoEditErase=_NoEditErase;
  EditOverriden=0;

  VisualWidth=_VisualWidth;

  if (MaskCharacter)
  {
    Mask=new char[MaskWidth+1];
    memset(Mask,MaskCharacter,MaskWidth);
    *(Mask+MaskWidth)=0;
    QuickMasked=1;
    Width=MaskWidth;
  }
  else
    QuickMasked=0;

  if (_VisualWidth && strlen(Mask)<_VisualWidth)
    VisualWidth=0;
  else if (_VisualWidth)
    Width=VisualWidth;

  if (!strlen(Mask))
    AssembleMask=NULL;
  else
  {
    AssembleMask=new char[strlen(Mask)+1];

    char *SaveAssembleMask=AssembleMask;
    char *SaveMask=Mask;

    while (*Mask)
    {
      if (strchr(MaskSet,*Mask))
        *AssembleMask++=*Mask++;
      else
        Mask++;
    }

    *AssembleMask=0;

    AssembleMask=SaveAssembleMask;
    Mask=SaveMask;

    if (!strlen(AssembleMask))
    {
      delete AssembleMask;
      AssembleMask=NULL;
    }
  }

  TotalMaskWidth=strlen(AssembleMask);

  if (!*Value)
    CurrentLocation=0;
  else
  {
    char *AssembleCount=AssembleMask;
    int Position=0;

    while (*AssembleCount)
    {
      #pragma warn -lin
      #pragma warn -lvc

      if (!MaskCheck(*AssembleCount,*_Value))
      {
        *_Value=0;
        break;
      }
      else
      {
        Position++;
        AssembleCount++;
        _Value++;
      }

      #pragma warn .lin
      #pragma warn .lvc
    }

    CurrentLocation=Position;

    if (CurrentLocation==TotalMaskWidth)
      CurrentLocation--;
  }

  if (VisualWidth && CurrentLocation>=VisualWidth)
    CurrentLocation=0;

  if (VisualWidth)
    X++;

  DialogElement::Width=Width;
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
//
// ~DiaChar()
//
// Destructor
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

DiaChar::~DiaChar()
{
  if (AssembleMask)
    delete AssembleMask;
  if (QuickMasked)
    delete Mask;
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
//
// GetPhysical()
//
// Gets the physical display location
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

int DiaChar::GetPhysical()
{
  int Locate=0, Logical=0;

  char *Mask=DiaChar::Mask;

  while (*Mask)
  {
    if (strchr(MaskSet,*Mask++))
    {
      if (Logical==CurrentLocation)
        break;
      Logical++;
    }
    Locate++;
  }

  return Locate;
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
//
// ScrollUpdate()
//
// Updates a scrolling characer element
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

void DiaChar::ScrollUpdate(int Color)
{
  if (!VisualWidth)
    return;

  int Physical=GetPhysical();

  if (AtLeft>Physical)
    AtLeft=Physical;

  if ((AtLeft+VisualWidth)<=Physical)
    AtLeft=(Physical-VisualWidth)+1;

  (*Blaze) (X-1,Y) << Color << (char)((AtLeft)?'\x11':' ');

  (*Blaze) (X+VisualWidth,Y) << Color <<
    (char)((AtLeft+VisualWidth!=strlen(Mask))?'\x10':' ');
}

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

static int InsertMode=0;

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

  if (CurrentLocation>strlen(Value))
  {
    CurrentLocation=strlen(Value);
    if (VisualWidth)
    {
      AtLeft=0;
      CurrentLocation=0;
    }
  }

  EditOverriden=0;

  if (NoEditErase)
    CurrentLocation=strlen(Value);

  MouseHide();

  ScrollUpdate(Colors.CharNormal);

  (*Blaze) (X,Y);
  (*Blaze) <<
    ((Available()==CompleteEvent)?Colors.CharNormal:Colors.DiaDeadLocator);

  if (VisualWidth)
    MaskShow(Mask,Value,*Blaze,AtLeft,VisualWidth);
  else
    MaskShow(Mask,Value,*Blaze);

  MouseShow();
}

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

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

  if (CurrentLocation>strlen(Value))
  {
    CurrentLocation=strlen(Value);
    if (VisualWidth)
    {
      AtLeft=0;
      CurrentLocation=0;
    }
  }

  MouseHide();

  ScrollUpdate(Colors.CharHiLite);

  (*Blaze) (X,Y);
  (*Blaze) << Colors.CharHiLite;

  if (VisualWidth)
    MaskShow(Mask,Value,*Blaze,AtLeft,VisualWidth);
  else
    MaskShow(Mask,Value,*Blaze);

  MouseShow();

  Blaze->VisibleCursor();

  char *Mask=DiaChar::Mask;
  int Count=CurrentLocation+1;
  int Position=-1;

  while (*Mask)
  {
    if (strchr(MaskSet,*Mask++))
    {
      Count--;
      Position++;
      if (!Count)
        break;
    }
    else
      Position++;
  }

  if (!VisualWidth)
    Blaze->WindowGotoXY(X+Position,Y);
  else
    Blaze->WindowGotoXY(X+(Position-AtLeft),Y);
}

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

int DiaChar::EventHandler(int Event)
{
  switch(Event)
  {
    case ValidatedMousedEvent:
      if (MouseEvent&MouseDoubleClick)
        return ClickEvent;
      return Event;

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

    case kbHome:
      EditOverriden++;
      CurrentLocation=0;
      AtLeft=0;
      HighLight();
      return CompleteEvent;

    case kbEnd:
      EditOverriden++;
      CurrentLocation=strlen(Value);
      HighLight();
      return CompleteEvent;

    case kbLeft:
      EditOverriden++;
      if (CurrentLocation)
        CurrentLocation--;
      HighLight();
      return CompleteEvent;

    case kbRight:
      EditOverriden++;
      if ((strlen(Value)==strlen(AssembleMask) && CurrentLocation!=strlen(Value)-1)
        || (strlen(Value)<strlen(AssembleMask) && CurrentLocation!=strlen(Value)))
        CurrentLocation++;
      HighLight();
      return CompleteEvent;

    case kbDel:
    case kbBackSpace:

      EditOverriden++;

      if (CurrentLocation==TotalMaskWidth-1 && *(Value+CurrentLocation))
      {
        *(Value+CurrentLocation)=0;
        HighLight();
        break;
      }

      if (Event==kbBackSpace)
      {
        if (CurrentLocation)
          CurrentLocation--;
        else
          return CompleteEvent;
      }

      char &DelMask = *(Value+CurrentLocation);

      #pragma warn -lin
      #pragma warn -lvc

      for (int i=CurrentLocation+1;i<strlen(Value);i++)
        if (MaskCheck(*(AssembleMask+i-1),*(Value+i),1)!=1)
          return CompleteEvent;

      #pragma warn .lin
      #pragma warn .lvc

      for (i=CurrentLocation+1;i<=strlen(Value);i++)
        *(Value+i-1)=*(Value+i);

      if (CurrentLocation && strchr("Ll",*(AssembleMask+CurrentLocation)) &&
        *(Value+CurrentLocation-1)!=' ')
          DelMask+=(isupper(DelMask))?32:0;

      if (CurrentLocation && strchr("LlUu",*(AssembleMask+CurrentLocation+1)) &&
        *(Value+CurrentLocation-1)==' ')
          DelMask-=(islower(DelMask))?32:0;

      if (!CurrentLocation && strchr("UuLlXA",*(AssembleMask+CurrentLocation)))
        DelMask-=(islower(DelMask))?32:0;

      HighLight();

      return CompleteEvent;

    default:
      if ((NoEditErase && !EditOverriden && MaskCheck(*AssembleMask,Event,0)
         && Event<128)
         ||
         (MaskCheck(*(AssembleMask+CurrentLocation),Event,0) && Event<128))
      {
        if (NoEditErase && !EditOverriden && MaskCheck(*AssembleMask,Event,0))
        {
          CurrentLocation=0;
          *Value=0;
        }

        EditOverriden++;

        if (InsertMode && strlen(Value))
        {
          if (CurrentLocation==TotalMaskWidth-1 || TotalMaskWidth==1)
          {
            *(Value+CurrentLocation)=Event;
            *(Value+CurrentLocation+1)=0;
            HighLight();
            return CompleteEvent;
          }

          if (strlen(Value)==TotalMaskWidth) // cannot insert
            return CompleteEvent;

          #pragma warn -lin
          #pragma warn -lvc

          for (i=CurrentLocation;i<strlen(Value)-1;i++)
            if (MaskCheck(*(AssembleMask+i+1),*(Value+i),1)!=1)
              return CompleteEvent;

          #pragma warn .lin
          #pragma warn .lvc

          for (i=strlen(Value)+1;i>CurrentLocation;i--)
            *(Value+i)=*(Value+i-1);
        }

        if (strchr("UuLl",*(AssembleMask+CurrentLocation)))
        {
          if (!CurrentLocation || (CurrentLocation && *(Value+CurrentLocation-1)==' '))
            Event-=(islower(Event))?32:0;
          else if (strchr("Ll",*(AssembleMask+CurrentLocation)))
            Event+=(isupper(Event))?32:0;
        }

        if (!*(Value+CurrentLocation))
          *(Value+CurrentLocation+1)=0;

        *(Value+CurrentLocation)=Event;

        if (strchr("Ll",*(AssembleMask+CurrentLocation+1)) &&
          *(Value+CurrentLocation)!=' ')
        {
          char &EntryMask = *(Value+CurrentLocation+1);

          EntryMask+=(isupper(EntryMask))?32:0;
        }
        else if (strchr("UuLl",*(AssembleMask+CurrentLocation+1)) &&
          *(Value+CurrentLocation)==' ')
        {
          char &EntryMask = *(Value+CurrentLocation+1);

          EntryMask-=(islower(EntryMask))?32:0;
        }

        CurrentLocation=(CurrentLocation==TotalMaskWidth-1)?
          CurrentLocation:(++CurrentLocation);

        HighLight();

        return CompleteEvent;
      }
  }
  return Event;
}
