#include <dos.h>
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <time.h>
#include <i86.h>

#include <tools.h>
#include <standard.h>

#include "sound.h"
#include "vdebug.h"
#include "verror.h"
#include "vectrex.h"
#include "joystick.h"


#define POLL_JOYSTICK_PER_SECOND_MAX 20
#define ADD_TO_TIMER_TICK ((UPDATES_PER_SEC+POLL_JOYSTICK_PER_SECOND_MAX-1)/POLL_JOYSTICK_PER_SECOND_MAX)

T_UWORD myGamePort=0x0201;
T_UCHAR myPresent=0;
T_LONG myMinimum[4];
T_LONG myMaximum[4];
T_LONG myTrigger[4];
T_LONG myZero[4];

T_SCHAR joy1x=0;
T_SCHAR joy2x=0;
T_SCHAR joy1y=0;
T_SCHAR joy2y=0;
T_FLOAT divider[4];

T_INT button1a=0;
T_INT button1b=0;
T_INT button2a=0;
T_INT button2b=0;

T_VOID detect(T_VOID);
T_VOID calibrate(T_VOID);

T_INT PCJoystick_init(T_VOID)
{
 static T_INT init_done=0;
 T_INT t;
 if (init_done==1)
  return T_TRUE;
 init_done=1;
 if (bGblDisplayVerbose==T_TRUE)
  t_printf(E_VERBOSE_NONE,"\nInitializing Joystick(s)");
 for (t = 0; t < 4; ++t)
 {
  myMinimum[t] = 0x000FFFFF;
  myMaximum[t] = 0;
  myTrigger[t] = 0;
  myZero[t] = 0;
  divider[t]=1;
 }
 // Determine which joysticks are present
 detect();
 // Calibrate the current position of the joystick as the "middle"
 calibrate();
 return T_TRUE;
}

T_VOID buttons(T_VOID)
{
 T_UCHAR i = ~(inp(myGamePort));
 button1a=0;
 button1b=0;
 button2a=0;
 button2b=0;
 i=(i >> 4) & 0x0F;
 if (i& 0x01)
  button1a=1;
 if (i& 0x02)
  button1b=1;
 if (i& 0x04)
  button2a=1;
 if (i& 0x08)
  button2b=1;
}

//============================================================================
// Calibrate "middle" position
//============================================================================
T_VOID calibrate(T_VOID)
{
 // Make sure a joystick is present before we continue
 if (myPresent)
 {
  T_UCHAR i;
  T_ULONG counter = 0;
  _disable();
  outp(myGamePort, 0);
  do
  {
   T_UWORD t;
   T_UWORD mask;
   i = inp(myGamePort) & 0x0F;
   for (t = 0, mask = 0x01; t < 4; ++t, mask <<= 1)
   {
    if (i & mask)
    {
     ++myZero[t];
    }
   }
  }
  while((counter++ < 0x000FFFFF) && (i & myPresent));
  _enable();

  // See if a timeout occured
  if (counter >= 0x000FFFFF)
  {
   t_printf(E_VERBOSE_NONE,"Joystick port read has timed out!\n\n");
   t_printf(E_VERBOSE_NONE,"The operation to read the joystick could not be completed.\n");
   t_printf(E_VERBOSE_NONE,"Your joystick port may not be working \n");
   t_printf(E_VERBOSE_NONE,"correctly or the joystick may have become disconnected.\n");
  }
 }
}

//============================================================================
// Determines which joysticks are presents if any
//============================================================================
T_VOID detect(T_VOID)
{
 // Reset the game port bits to 1's
 clock_t start;
 outp(myGamePort, 0);
 start = clock();

 // Wait for low on all four joystick bits
 do
 {
  myPresent = inp(myGamePort) & 0x0F;
 }
 while(((clock() - start) < (CLOCKS_PER_SEC / 2)) && myPresent);

 // Setup joystick present mask that tells which joysticks are present
 myPresent = (myPresent ^ 0x0F) & 0x0F;
 myPresent = myPresent & (((myPresent & 0x03) == 0x03) ? 0x0F : 0x0C);
 myPresent = myPresent & (((myPresent & 0x0C) == 0x0C) ? 0x0F : 0x03);

 if (bGblDisplayVerbose==T_TRUE)
 {
  if (myPresent & 0x03)
   t_printf(E_VERBOSE_NONE,"\nJoystick A found.");
  if (myPresent & 0x0C)
   t_printf(E_VERBOSE_NONE,"\nJoystick B found.");
 }

}

//============================================================================
// Answer the state of the positions
//============================================================================
T_VOID positions_analog(T_VOID)
{
 static T_INT next_timer=0;
 if (timer_tick>=next_timer)
 {
  T_UCHAR i;
  T_LONG count[4] = {0, 0, 0, 0};
  T_UWORD t;
  T_ULONG counter = 0;
  next_timer=timer_tick+ADD_TO_TIMER_TICK;
  joy1x=0;
  joy1y=0;
  joy2x=0;
  joy2y=0;
  buttons();
  _disable();
  outp(myGamePort, 0);
  do
  {
   T_UWORD mask;
   i = inp(myGamePort) & 0x0F;
   for (t = 0, mask = 0x01; t < 4; ++t, mask <<= 1)
   {
    if (i & mask)
    {
     ++count[t];
    }
   }
  }
  while ((counter++ < 0x000FFFFF) && (i & myPresent));
  _enable();
  // See if a timeout occured
  if (counter >= 0x000FFFFF)
  {
   t_printf(E_VERBOSE_NONE,"Joystick port read has timed out!\n\n");
   t_printf(E_VERBOSE_NONE,"The operation to read the joystick could not be completed.\n");
   t_printf(E_VERBOSE_NONE,"Your joystick port may not be working \n");
   t_printf(E_VERBOSE_NONE,"correctly or the joystick may have become disconnected.\n");
  }
  // Do axis checking and autocalibration
  for (t = 0; t < 4; ++t)
  {
   if (myPresent & (1 << t))
   {
    if (count[t] > myMaximum[t])
    {
     T_INT itemp;
     T_FLOAT ftemp;
     myMaximum[t] = count[t];
     itemp=myMaximum[t]-myZero[t];
     ftemp=(itemp)/127.000001;
     if (ftemp>divider[t])
     divider[t]=ftemp;
    }
    if (count[t] < myMinimum[t])
    {
     T_INT itemp;
     T_FLOAT ftemp;
     myMinimum[t] = count[t];
     itemp=myZero[t]-myMinimum[t];
     ftemp=(itemp)/127.000001;
     if (ftemp>divider[t])
     divider[t]=ftemp;
    }
   }
  }
  if (myPresent & 0x03)
  {
   T_INT this_x_value=(count[0]-myZero[0])/divider[0];
   T_INT this_y_value=(count[1]-myZero[1])/divider[1];
   if (abs(this_x_value)>20)
    joy1x=this_x_value;
   if (abs(this_y_value)>20)
    joy1y=this_y_value;
  }
  if (myPresent & 0x0C)
  {
   T_INT this_x_value=(count[2]-myZero[2])/divider[2];
   T_INT this_y_value=(count[3]-myZero[3])/divider[3];
   if (abs(this_x_value)>20)
    joy2x=this_x_value;
   if (abs(this_y_value)>20)
    joy2y=this_y_value;
  }
 }//if (timer_tick>=next_timer)
}

T_VOID positions_digital(T_VOID)
{
 static T_INT next_timer=0;
 if (timer_tick>=next_timer)
 {
  T_UCHAR i;
  T_LONG count[4] = {0, 0, 0, 0};
  T_UWORD t;
  T_ULONG counter = 0;
  next_timer=timer_tick+ADD_TO_TIMER_TICK;
  joy1x=0;
  joy1y=0;
  joy2x=0;
  joy2y=0;
  buttons();
  _disable();
  outp(myGamePort, 0);
  do
  {
   T_UWORD mask;
   i = inp(myGamePort) & 0x0F;
   for (t = 0, mask = 0x01; t < 4; ++t, mask <<= 1)
   {
    if (i & mask)
    {
     ++count[t];
    }
   }
  }
  while ((counter++ < 0x000FFFFF) && (i & myPresent));
  _enable();

  // See if a timeout occured
  if (counter >= 0x000FFFFF)
  {
   t_printf(E_VERBOSE_NONE,"Joystick port read has timed out!\n\n");
   t_printf(E_VERBOSE_NONE,"The operation to read the joystick could not be completed.\n");
   t_printf(E_VERBOSE_NONE,"Your joystick port may not be working \n");
   t_printf(E_VERBOSE_NONE,"correctly or the joystick may have become disconnected.\n");
  }
  // Do axis checking and autocalibration
  for (t = 0; t < 4; ++t)
  {
   if (myPresent & (1 << t))
   {
    if (count[t] > myMaximum[t])
    {
     myMaximum[t] = count[t];
    }
    if (count[t] < myMinimum[t])
    {
     myMinimum[t] = count[t];
    }
    myTrigger[t] = ((myMaximum[t] - myMinimum[t]) >> 3) + 32;
   }
  }
  if (myPresent & 0x03)
  {
   if (count[0] < (myZero[0] - myTrigger[0]))
    joy1x=-127;
   else if (count[0] > (myZero[0] + myTrigger[0]))
    joy1x=127;
   if (count[1] < (myZero[1] - myTrigger[1]))
    joy1y=-127;
   else if (count[1] > (myZero[1] + myTrigger[1]))
    joy1y=127;
  }
  if (myPresent & 0x0C)
  {
  if (count[2] < (myZero[2] - myTrigger[2]))
   joy2x=-127;
  if (count[2] > (myZero[2] + myTrigger[2]))
   joy2x=127;
  if (count[3] < (myZero[3] - myTrigger[3]))
   joy2y=-127;
  if (count[3] > (myZero[3] + myTrigger[3]))
   joy2y=127;
  }
 }//if (timer_tick>=next_timer)
}
