/*
  AppleWin : An Apple //e emulator for Windows

  Copyright (C) 1994-1996, Michael O'Brien
  Copyright (C) 1999-2001, Oliver Schmidt
  Copyright (C) 2002-2005, Tom Charlesworth
  Copyright (C) 2006-2007, Tom Charlesworth, Michael Pohoreski

  AppleWin is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  AppleWin is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with AppleWin; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
/*
  FourPlay.CPP

  Emulate a 4Play Joystick card

  4 ports (one for each of the four possible joysticks)

  Each port 
  Bit 0 = Up, Active High
  Bit 1 = Down, Active High
  Bit 2 = Left, Active High
  Bit 3 = Right, Active High
  Bit 4 = Trigger 2, Active High
  Bit 5 = Not Used, Always High
  Bit 6 = Trigger 2, Active High
  Bit 7 = Trigger 1, Active High

  Address = C0nx
  n = 8 + slot number
  x = 0 - Joystick 1
      1 - Joystick 2
      2 - Joystick 3
      3 - Joystick 4

  Alex Lukacz  Aug 2021
*/
#include "StdAfx.h"

#include "FourPlay.h"
#include "Joystick.h"
#include "Memory.h"
#include "YamlHelper.h"

BYTE __stdcall FourPlayCard::IORead(WORD pc, WORD addr, BYTE bWrite, BYTE value, ULONG nExecutedCycles)
{
	BYTE nOutput = MemReadFloatingBus(nExecutedCycles);
	BOOL up = 0;
	BOOL down = 0;
	BOOL left = 0;
	BOOL right = 0;
	BOOL trigger1 = 0;
	BOOL trigger2 = 0;
	BOOL trigger3 = 0;
	BOOL alwaysHigh = 1;
	UINT xAxis = 0;
	UINT yAxis = 0;

	JOYINFOEX infoEx;
	infoEx.dwSize = sizeof(infoEx);
	infoEx.dwFlags = JOY_RETURNPOV | JOY_RETURNBUTTONS;

	switch (addr & 0xF)
	{
	case 0: // Joystick 1
		if (GetJoystick1() >= 0 && joyGetPosEx(GetJoystick1(), &infoEx) == JOYERR_NOERROR)
		{
			xAxis = (infoEx.dwXpos >> 8) & 0xFF;
			yAxis = (infoEx.dwYpos >> 8) & 0xFF;
			trigger1 = infoEx.dwButtons & 0x01;
			trigger2 = (infoEx.dwButtons & 0x02) >> 1;
			up = yAxis < 103 || infoEx.dwPOV == 0 || infoEx.dwPOV == 4500 || infoEx.dwPOV == 31500;
			down = yAxis > 153 || (infoEx.dwPOV >= 13500 && infoEx.dwPOV <= 22500);
			left = xAxis < 103 || (infoEx.dwPOV >= 22500 && infoEx.dwPOV <= 31500);
			right = xAxis > 153 || (infoEx.dwPOV >= 4500 && infoEx.dwPOV <= 13500);
		}
		nOutput = up | (down << 1) | (left << 2) | (right << 3) | (alwaysHigh << 5) | (trigger2 << 6) | (trigger1 << 7);
		break;
	case 1: // Joystick 2
		if (GetJoystick2() >= 0 && joyGetPosEx(GetJoystick2(), &infoEx) == JOYERR_NOERROR)
		{
			xAxis = (infoEx.dwXpos >> 8) & 0xFF;
			yAxis = (infoEx.dwYpos >> 8) & 0xFF;
			trigger1 = infoEx.dwButtons & 0x01;
			trigger2 = (infoEx.dwButtons & 0x02) >> 1;
			up = yAxis < 103 || infoEx.dwPOV == 0 || infoEx.dwPOV == 4500 || infoEx.dwPOV == 31500;
			down = yAxis > 153 || (infoEx.dwPOV >= 13500 && infoEx.dwPOV <= 22500);
			left = xAxis < 103 || (infoEx.dwPOV >= 22500 && infoEx.dwPOV <= 31500);
			right = xAxis > 153 || (infoEx.dwPOV >= 4500 && infoEx.dwPOV <= 13500);
		}
		nOutput = up | (down << 1) | (left << 2) | (right << 3) | (alwaysHigh << 5) | (trigger2 << 6) | (trigger1 << 7);
		break;
	case 2: // Joystick 3
		nOutput = FourPlayCard::JOYSTICKSTATIONARY; // esdf - direction buttons, zx - trigger buttons
		nOutput = nOutput | (MyGetAsyncKeyState('E') | (MyGetAsyncKeyState('D') << 1) | (MyGetAsyncKeyState('S') << 2) | (MyGetAsyncKeyState('F') << 3) | (MyGetAsyncKeyState('X') << 6) | (MyGetAsyncKeyState('Z') << 7));
		break;
	case 3: // Joystick 4
		nOutput = FourPlayCard::JOYSTICKSTATIONARY; // ijkl - direction buttons, nm - trigger buttons
		nOutput = nOutput | (MyGetAsyncKeyState('I') | (MyGetAsyncKeyState('K') << 1) | (MyGetAsyncKeyState('J') << 2) | (MyGetAsyncKeyState('L') << 3) | (MyGetAsyncKeyState('M') << 6) | (MyGetAsyncKeyState('N') << 7));
		break;
	default:
		break;
	}

	return nOutput;
}

BYTE FourPlayCard::MyGetAsyncKeyState(int vKey)
{
	return GetAsyncKeyState(vKey) < 0 ? 1 : 0;
}

void FourPlayCard::InitializeIO(LPBYTE pCxRomPeripheral)
{
	RegisterIoHandler(m_slot, &FourPlayCard::IORead, IO_Null, IO_Null, IO_Null, this, NULL);
}

//===========================================================================

static const UINT kUNIT_VERSION = 1;

const std::string& FourPlayCard::GetSnapshotCardName(void)
{
	static const std::string name("4Play");
	return name;
}

void FourPlayCard::SaveSnapshot(YamlSaveHelper& yamlSaveHelper)
{
	YamlSaveHelper::Slot slot(yamlSaveHelper, GetSnapshotCardName(), m_slot, kUNIT_VERSION);

	YamlSaveHelper::Label unit(yamlSaveHelper, "%s: null\n", SS_YAML_KEY_STATE);
	// NB. No state for this card
}

bool FourPlayCard::LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT version)
{
	if (version < 1 || version > kUNIT_VERSION)
		ThrowErrorInvalidVersion(version);

	return true;
}
