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

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

#ifdef __BCPLUSPLUS__
#pragma hdrstop
#endif

#include <string.h>
#include <bios.h>
#include <alloc.h>
#include <mem.h>

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
//
// FLICMP() -> statically/locally used by ShiftManager
//
// Compares two far strings -- returns 1 if alike or 0 if not alike
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

static int FLICMP(char far *chka,char far *chkb,int size)
{
  do
  {
    if (*chka++!=*chkb++)
      return 0;
  }
  while (--size);
  return 1;
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
//
// FLICPY() -> statically/locally used by ShiftManager
//
// Copies one string into another
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

static void FLICPY(char far *from,char far *to,int size)
{
  do *to++=*from++; while (--size);
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
//
// ShiftManager()
//
// Constructor
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

int ShiftManager::LastShift=500;
int ShiftManager::KeyLast=500;

ShiftManager::ShiftManager()
{
  LastShift=500;
  KeyLast=500;

  Keys=0;
  Alt=0;
  Ctrl=0;
  Normal=0;

  NumAltKeys=0;
  NumCtrlKeys=0;
  NumNormKeys=0;
  NumKeyTies=0;

  Item=0;
  PromptWidth=0;
  XOffset=0;
  OnLastShift=500;

  SnapShot=0;
  InAWindow=0;
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
//
// ~ShiftManager()
//
// Destructor
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

ShiftManager::~ShiftManager()
{
  if (NumAltKeys)
    free(Alt);

  if (NumCtrlKeys)
    free(Ctrl);

  if (NumNormKeys)
    free(Normal);

  if (NumKeyTies)
    free(Keys);

  if (SnapShot)
    delete SnapShot;
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
//
// RefreshPromptLine()
//
// Refreshes the prompt line after a shift state change
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

int ShiftManager::RefreshPromptLine()
{
  int BoldHelp=Colors.PromptLineBold;
  int Help=Colors.PromptLineNormal;

  BlazeClass Blaze;

  MouseLocate();

  if (((bioskey(2)&8 && !NumAltKeys) ||
    (bioskey(2)&4 && !NumCtrlKeys) ||
    !NumNormKeys) && InAWindow)
    return 0;

  if (bioskey(2)!=LastShift || (SnapShot && !FLICMP(
      ((char far *)Blaze.WhatOutput()+((Blaze.WhatWidth()*2)*(Blaze.WhatHeight()-1))),
      SnapShot,30) && MouseVertical!=Blaze.WhatHeight()-1))
  {
    LastShift=bioskey(2);

    if ((SnapShot && FLICMP(
      ((char far *)Blaze.WhatOutput()+((Blaze.WhatWidth()*2)*(Blaze.WhatHeight()-1))),
      SnapShot,30)) || !SnapShot)
    {
      if (bioskey(2)&8 && KeyLast==1) // Alt
        return 1;
      else if (bioskey(2)&4 && KeyLast==2) // Ctrl
        return 1;
      else if (!bioskey(2)&8 && !bioskey(2)&4 && !KeyLast) // Non Shifted
        return 1;
    }

    int NumOptions;
    _PromptLine *Keyer;

    if (bioskey(2)&8)
    {
      KeyLast=1;
      NumOptions=NumAltKeys;
      Keyer=Alt;
    }
    else if (bioskey(2)&4)
    {
      KeyLast=2;
      NumOptions=NumCtrlKeys;
      Keyer=Ctrl;
    }
    else
    {
      KeyLast=0;
      NumOptions=NumNormKeys;
      Keyer=Normal;
    }

    MouseHide();

    Blaze.CharacterRepeater(0,Blaze.WhatHeight()-1,Blaze.WhatWidth(),Help,0);
    Blaze (1,Blaze.WhatHeight()-1);
    !Blaze;
    +Blaze;

    if (!NumOptions)
    {
      MouseShow();
      return 0;
    }

    Item=0;
    OnLastShift=0;

    for (register int i=0,Width=0;i<NumOptions;i++)
    {
      if ((Keyer+i)->Key && (Keyer+i)->Info &&
        *(Keyer+i)->Key && *(Keyer+i)->Info)
      {
        Width+=(strlen((Keyer+i)->Key)+strlen((Keyer+i)->Info)+1);
        if (Width>=Blaze.WhatWidth()-1)
          break;
        Blaze << BoldHelp
          << (Keyer+i)->Key
          << ' '
          << Help
          << (Keyer+i)->Info;

        Width++;
        if (Width>=Blaze.WhatWidth()-1)
          break;
        Blaze << ' ';
      }
    }

    if (!SnapShot)
      SnapShot=new char[32];

    FLICPY(((char far *)Blaze.WhatOutput()+
        ((Blaze.WhatWidth()*2)*(Blaze.WhatHeight()-1))),
      SnapShot,30);

    MouseShow();
  }

  return 1;
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
//
// CheckPromptLine()
//
// See if mouse is touching the prompt line
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

int ShiftManager::CheckPromptLine()
{
  if (LastShift==500 ||
     (KeyLast==1 && !NumAltKeys) ||
     (KeyLast==2 && !NumCtrlKeys) ||
     (KeyLast==0 && !NumNormKeys))
    return 0;

  if (!bioskey(2)&8 && KeyLast==1)
    return 0;
  else if (!bioskey(2)&4 && KeyLast==2)
    return 0;
  else if ((bioskey(2)&8 || bioskey(2)&4) && !KeyLast)
    return 0;

  BlazeClass Blaze;

  if (MouseEvent&MouseMoved)
  {
    if (OnLastShift==KeyLast)
    {
      MouseHide();
      Blaze.ChangeBackground(XOffset,Blaze.WhatHeight()-1,PromptWidth,1,Colors.PromptLineNormal);
      MouseShow();
    }

    if (MouseVertical<Blaze.WhatHeight()-1)
    {
      Item=0;
      return 1;
    }

    int NumOptions;
    _PromptLine *Keyer;

    if (KeyLast==1)
    {
      NumOptions=NumAltKeys;
      Keyer=Alt;
    }
    else if (KeyLast==2)
    {
      NumOptions=NumCtrlKeys;
      Keyer=Ctrl;
    }
    else
    {
      NumOptions=NumNormKeys;
      Keyer=Normal;
    }

    for (register int i=0,Width=0,SaveWidth=0;i<NumOptions;i++)
    {
      if ((Keyer+i)->Key && (Keyer+i)->Info &&
        *(Keyer+i)->Key && *(Keyer+i)->Info)
      {
        SaveWidth=Width;
        Width+=(strlen((Keyer+i)->Key)+strlen((Keyer+i)->Info)+1);
        if (Width>=Blaze.WhatWidth()-1)
          break;
        if (MouseHorizontal>=SaveWidth && MouseHorizontal<=Width+1)
        {
          XOffset=SaveWidth;
          PromptWidth=Width-SaveWidth+2;
          Item=i+1;
          MouseHide();
          Blaze.ChangeBackground(XOffset,Blaze.WhatHeight()-1,PromptWidth,1,Colors.MenuHiLite);
          MouseShow();
          OnLastShift=KeyLast;
          return 1;
        }
        Width++;
        if (Width>=Blaze.WhatWidth()-1)
          break;
      }
    }

    OnLastShift=KeyLast;
    XOffset=0;
    Width=0;
    Item=0;
  }
  else if (MouseEvent&MouseLeftButtonRelease)
  {
    if (OnLastShift==KeyLast && Item && MouseVertical==Blaze.WhatHeight()-1)
    {
      _PromptLine *Keyer;

      if (KeyLast==1)
        Keyer=Alt;
      else if (KeyLast==2)
        Keyer=Ctrl;
      else
        Keyer=Normal;
      return (InAWindow)?
        (Keyer+Item-1)->Event:EventHandler((Keyer+Item-1)->Event);
    }
  }

  return 1;
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
//
// DefineKey()
//
// Places a key and event onto the global keyboard event queue
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

void ShiftManager::DefineKey(int HotKey,int Event)
{
  if (HotKey && Event)
  {
    Keys=(_HotKeys*)realloc(Keys,++NumKeyTies*sizeof(_HotKeys));
    (Keys+NumKeyTies-1)->Tie=HotKey;
    (Keys+NumKeyTies-1)->Event=Event;
  }
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
//
// DefineAltKey()
//
// Defines an ALT key combination
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

void ShiftManager::DefineAltKey(char *Key,char *Description,int Event,
  int HotKey)
{
  Alt=(_PromptLine*)realloc(Alt,++NumAltKeys*sizeof(_PromptLine));
  (Alt+NumAltKeys-1)->Key=Key;
  (Alt+NumAltKeys-1)->Info=Description;
  (Alt+NumAltKeys-1)->Event=Event;
  DefineKey(HotKey,Event);
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
//
// DefineCtrlKey()
//
// Defines an CTRL key combination
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

void ShiftManager::DefineCtrlKey(char *Key,char *Description,int Event,
  int HotKey)
{
  Ctrl=(_PromptLine*)realloc(Ctrl,++NumCtrlKeys*sizeof(_PromptLine));
  (Ctrl+NumCtrlKeys-1)->Key=Key;
  (Ctrl+NumCtrlKeys-1)->Info=Description;
  (Ctrl+NumCtrlKeys-1)->Event=Event;
  DefineKey(HotKey,Event);
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
//
// DefineNormKey()
//
// Defines an normal (non-shifted) key combination
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

void ShiftManager::DefineNormKey(char *Key,char *Description,int Event,
  int HotKey)
{
  Normal=(_PromptLine*)realloc(Normal,++NumNormKeys*sizeof(_PromptLine));
  (Normal+NumNormKeys-1)->Key=Key;
  (Normal+NumNormKeys-1)->Info=Description;
  (Normal+NumNormKeys-1)->Event=Event;
  DefineKey(HotKey,Event);
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
//
// CheckEvent()
//
// Check all events and see if the passed event matches
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

int ShiftManager::CheckEvent(int Event)
{
  if (NumKeyTies)
  {
    for (register int i=0;i<NumKeyTies;i++)
    {
      if ((Keys+i)->Tie==Event && (Keys+i)->Event)
        return (Keys+i)->Event;
    }
  }
  return 0;
}
