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

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

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

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

Numerics::Numerics(int _NoEditErase)
{
  CurrentLocation=0;
  NoEditErase=_NoEditErase;
  EditOverriden=0;
  AllowedNegative=0;
}

Numerics::~Numerics()
{
  if (Value)
    delete Value;
}

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

static int InsertMode=0;

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

  MouseHide();
  if (strlen(Mask)!=strlen(Value))
    Blaze->CharacterRepeater(X+strlen(Value),Y,strlen(Mask)-strlen(Value),
      Colors.NumHiLite,' ');
  (*Blaze) (X,Y) << Colors.NumHiLite << Numerics::Value;
  MouseShow();

  if (CurrentLocation>=strlen(Mask))
    CurrentLocation=strlen(Mask)-1;

  Blaze->WindowGotoXY(X+CurrentLocation,Y);
}

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

void Numerics::Show()
{
  Blaze->BigCursor();

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

  MouseHide();
  TrimTrailingZeros();
  MaskShow(Mask,Value,*Blaze);
  TrimTrailingZeros();
  EditOverriden=0;
  CurrentLocation=strlen(Value);
  MouseShow();
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
//
// EventValidation()
//
// Validates the number that was input by the user
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

int Numerics::EventValidation(int Event)
{
  if (!AllowedAfterDecimal && !AllowedBeforeDecimal)
    return Event;

  // ---------------------------------------------------------------
  // determine current amount of numbers in string
  // ---------------------------------------------------------------

  long ActualBeforeDecimal=0;

  long ActualAfterDecimal=0;

  if (AllowedBeforeDecimal)
  {
    if (strchr(Value,'.'))
      ActualBeforeDecimal=(strchr(Value,'.')-Value)-
        ((strchr(Value,'-'))?1:0);
    else
      ActualBeforeDecimal=strlen(Value)-((strchr(Value,'-'))?1:0);
  }

  if (AllowedAfterDecimal)
  {
    if (strchr(Value,'.'))
      ActualAfterDecimal=(((Value+strlen(Value))-1)-strchr(Value,'.'));
  }

  // ---------------------------------------------------------------
  // process 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;
      return CompleteEvent;

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

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

    case kbRight:
      EditOverriden++;
      if (CurrentLocation==strlen(Value))
        return CompleteEvent;
      CurrentLocation++;
      return CompleteEvent;

    case '.':
      if (AllowedAfterDecimal)
      {
        if (NoEditErase && !EditOverriden)
        {
          EditOverriden++;
          *(Value+1)=0;
          CurrentLocation=0;
          ActualBeforeDecimal=0;
          ActualAfterDecimal=0;
        }

        if (strchr(Value,'.'))
          return CompleteEvent;

        if (!InsertMode)
        {
          if (!*(Value+CurrentLocation))
          {
            *(Value+CurrentLocation++)='.';
            *(Value+CurrentLocation)=0;
            return CompleteEvent;
          }
          else
          {
            if ((strlen(Value)-1)-CurrentLocation<=AllowedAfterDecimal)
            {
              *(Value+CurrentLocation++)='.';
              *(Value+CurrentLocation)=0;
              return CompleteEvent;
            }
          }
        }
        else
        {
          if (!*(Value+CurrentLocation))
          {
            *(Value+CurrentLocation++)='.';
            *(Value+CurrentLocation)=0;
            return CompleteEvent;
          }
          else
          {
            int ModifiedAfter=strlen(Value)-CurrentLocation;
            int ModifiedBefore=CurrentLocation-((*Value=='-')?1:0);
            if (ModifiedAfter<=AllowedAfterDecimal &&
              ModifiedBefore<=AllowedBeforeDecimal)
            {
              movmem((Value+CurrentLocation),(Value+CurrentLocation+1),
                strlen(Value)-CurrentLocation);
              *(Value+CurrentLocation)='.';
              CurrentLocation++;
            }
          }
        }
      }
      return CompleteEvent;

    case kbBackSpace:
      EditOverriden++;

      if (!CurrentLocation)
        return CompleteEvent;

      if (!*(Value+CurrentLocation))
      {
        *(Value+(--CurrentLocation))=0;
      }
      else if (CurrentLocation==strlen(Mask)-1)
      {
        *(Value+CurrentLocation)=0;
      }
      else
      {
        if (*((Value+CurrentLocation)-1)=='.' &&
          ActualBeforeDecimal+ActualAfterDecimal>AllowedBeforeDecimal)
          return CompleteEvent;

        movmem((Value+CurrentLocation),(Value+CurrentLocation-1),
          (strlen(Value)-CurrentLocation)+1);

        CurrentLocation--;
      }

      return CompleteEvent;

    case kbDel:
      EditOverriden++;

      if (!*(Value+CurrentLocation))
        return CompleteEvent;

      if (*(Value+CurrentLocation)=='-' || *(Value+CurrentLocation)>='0')
      {
        movmem((Value+CurrentLocation+1),(Value+CurrentLocation),
          (strlen(Value)-CurrentLocation)+1);
      }
      else
      {
        if (ActualBeforeDecimal+ActualAfterDecimal<=AllowedBeforeDecimal)
        {
          movmem((Value+CurrentLocation+1),(Value+CurrentLocation),
            (strlen(Value)-CurrentLocation)+1);
        }
      }

      return CompleteEvent;

    case '-':
      if (AllowedNegative && NoEditErase && !EditOverriden)
      {
        EditOverriden++;
        *(Value+1)=0;
        CurrentLocation=0;
        ActualBeforeDecimal=0;
        ActualAfterDecimal=0;
      }

      if (AllowedNegative && !CurrentLocation && *Value!='-')
      {
        if (InsertMode)
        {
          movmem((Value+CurrentLocation),(Value+CurrentLocation+1),
            (strlen(Value)-CurrentLocation)+1);
          CurrentLocation++;
          *Value='-';
        }
        else
        {
          if (*Value=='.' && ActualAfterDecimal>=AllowedBeforeDecimal)
            return CompleteEvent;

          *Value='-';
          CurrentLocation++;
        }
        return CompleteEvent;
      }

    default:
      if (!AllowedBeforeDecimal && !AllowedAfterDecimal)
        return CompleteEvent;

      if (Event>='0' && Event<='9')
      {
        if (!strchr(Value,'.') && !AllowedBeforeDecimal)
          return CompleteEvent;

        if (NoEditErase && !EditOverriden)
        {
          EditOverriden++;
          *Value=0;
          CurrentLocation=0;
          ActualBeforeDecimal=0;
          ActualAfterDecimal=0;
        }

        if (!InsertMode)
        {

NoInsert:

          // ---------------------------------------------------------------
          // typing over a number
          // ---------------------------------------------------------------

          if (*(Value+CurrentLocation)>='0' && *(Value+CurrentLocation)<='9')
          {
            *(Value+CurrentLocation++)=Event;
            return CompleteEvent;
          }

          // ---------------------------------------------------------------
          // typing at end of number - checks to make sure before and after
          // decimal places are not too many to fit in the mask
          // ---------------------------------------------------------------

          if (!*(Value+CurrentLocation))
          {
            if ((!strchr(Value,'.') && ActualBeforeDecimal<AllowedBeforeDecimal)
             || (strchr(Value,'.') && ActualAfterDecimal<AllowedAfterDecimal))
            {
              *(Value+CurrentLocation++)=Event;
              *(Value+CurrentLocation)=0;
            }
            return CompleteEvent;
          }

          // ---------------------------------------------------------------
          // typing over a negative sign
          // ---------------------------------------------------------------

          if (*(Value+CurrentLocation)=='-')
          {
            if ((!ActualBeforeDecimal && AllowedBeforeDecimal)
              || (ActualBeforeDecimal && ActualBeforeDecimal<AllowedBeforeDecimal))
            {
              *(Value+CurrentLocation++)=Event;
            }
            return CompleteEvent;
          }

          // ---------------------------------------------------------------
          // typing over a decimal point
          // ---------------------------------------------------------------

          if (*(Value+CurrentLocation)=='.')
          {
            if (ActualBeforeDecimal+ActualAfterDecimal<AllowedBeforeDecimal)
            {
              *(Value+CurrentLocation++)=Event;
            }
            return CompleteEvent;
          }
        }
        else
        {
          if ((!CurrentLocation && !*Value) || !*(Value+CurrentLocation))
            goto NoInsert;

          if (*(Value+CurrentLocation)=='-')
            return CompleteEvent;

          // ---------------------------------------------------------------
          // insertion prior to decimal
          // ---------------------------------------------------------------

          if (strchr(Value,'.') && (Value+CurrentLocation)<=strchr(Value,'.'))
          {
            if (ActualBeforeDecimal<AllowedBeforeDecimal)
            {
              movmem((Value+CurrentLocation),(Value+CurrentLocation+1),
                (strlen(Value)-CurrentLocation)+1);
              *(Value+CurrentLocation)=Event;
              CurrentLocation++;
            }
            return CompleteEvent;
          }

          // ---------------------------------------------------------------
          // insertion after to decimal
          // ---------------------------------------------------------------

          if (strchr(Value,'.') && (Value+CurrentLocation)>strchr(Value,'.'))
          {
            if (ActualAfterDecimal<AllowedAfterDecimal)
            {
              movmem((Value+CurrentLocation),(Value+CurrentLocation+1),
                (strlen(Value)-CurrentLocation)+1);
              *(Value+CurrentLocation)=Event;
              CurrentLocation++;
            }
            return CompleteEvent;
          }

          // ---------------------------------------------------------------
          // insertion without a decimal
          // ---------------------------------------------------------------

          if (ActualBeforeDecimal<AllowedBeforeDecimal)
          {
            movmem((Value+CurrentLocation),(Value+CurrentLocation+1),
              (strlen(Value)-CurrentLocation)+1);
            *(Value+CurrentLocation)=Event;
            CurrentLocation++;
            return CompleteEvent;
          }
        }
      }
      break;
  }

  return Event;
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
//
// TrimTrailingZeros()
//
// Slice off 0's at end of number (i.e. before: 10.5000 after: 10.5)
// Removes decimal place if it isn't needed
// Removes dead zeros (i.e. before: -0000 after: NULL)
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

void Numerics::TrimTrailingZeros()
{
  if (!*Value)
    return;

  // scan entire number and see if any NON-ZERO numbers appear -- if none
  // appear, just turn the # into a zero

  if (!*(Value+strcspn(Value,"123456789")))
  {
    *Value=0;
    return;
  }

  // if all else fails ...

  if (strchr(Value,'.'))
  {
    char *Current=(Value+strlen(Value)-1);

    do
    {
      if (*Current=='0')
        *Current=0;
      else if (*Current=='.')
      { // if nada behind decimal, knock off decimal
        *Current=0;
        break;
      }
      else
        break;

      Current--;
    }
    while (Current>=Value);
  }

  if (*Value && !strchr(Value,'.'))
  {
    char *AltValue=Value;
    int Counter=0;

    do
    {
      if (*AltValue>'0' && *AltValue<='9')
        Counter++;
    } while(*++AltValue);

    if (!Counter)
    {
      *Value=0;
      CurrentLocation=0;
    }
  }

  if (strchr(Value,' '))     // get rid of white space at END of string
    *(strchr(Value,' '))=0;  // only occurs on floating point based numbers
}

