using BizHawk.Common;

namespace BizHawk.Emulation.Cores.Atari.Atari2600
{
	public partial class TIA
	{
		private struct PlayerData
		{
			public MissileData Missile;

			public byte Grp;
			public byte Dgrp;
			public byte Color;
			public byte HPosCnt;
			public byte ScanCnt;
			public byte ScanStrchCnt;
			public byte HM;
			public bool Reflect;
			public bool Delay;
			public byte Nusiz;
			public bool Reset;
			public byte ResetCnt;
			public byte Collisions;

			public bool Tick()
			{
				var result = false;
				if (ScanCnt < 8)
				{
					// Make the mask to check the graphic
					byte playerMask = (byte)(1 << (8 - 1 - ScanCnt));

					// Reflect it if needed
					if (Reflect)
					{
						playerMask = (byte)ReverseBits(playerMask, 8);
					}

					// Check the graphic (depending on delay)
					if (!Delay)
					{
						if ((Grp & playerMask) != 0)
						{
							result = true;
						}
					}
					else
					{
						if ((Dgrp & playerMask) != 0)
						{
							result = true;
						}
					}

					// Reset missile, if desired
					if (ScanCnt == 0x04 && HPosCnt <= 16 && Missile.ResetToPlayer)
					{
						Missile.HPosCnt = 0;
					}

					// Increment counter
					// When this reaches 8, we've run out of pixel

					// If we're drawing a stretched player, only incrememnt the
					// counter every 2 or 4 clocks

					// Double size player
					if ((Nusiz & 0x07) == 0x05)
					{
						ScanStrchCnt++;
						ScanStrchCnt %= 2;
					}

					// Quad size player
					else if ((Nusiz & 0x07) == 0x07)
					{
						ScanStrchCnt++;
						ScanStrchCnt %= 4;
					}

					// Single size player
					else
					{
						ScanStrchCnt = 0;
					}

					if (ScanStrchCnt == 0)
					{
						ScanCnt++;
					}
				}

				// At counter position 0 we should start drawing, a pixel late
				// Set the scan counter at 0, and at the next pixel the graphic will start drawing
				if (HPosCnt == 0 && !Reset)
				{
					ScanCnt = 0;
					if ((Nusiz & 0x07) == 0x05 || (Nusiz & 0x07) == 0x07)
					{
						ScanStrchCnt = 0;
					}
				}

				if (HPosCnt == 16 && ((Nusiz & 0x07) == 0x01 || ((Nusiz & 0x07) == 0x03)))
				{
					ScanCnt = 0;
				}

				if (HPosCnt == 32 && ((Nusiz & 0x07) == 0x02 || ((Nusiz & 0x07) == 0x03) || ((Nusiz & 0x07) == 0x06)))
				{
					ScanCnt = 0;
				}

				if (HPosCnt == 64 && ((Nusiz & 0x07) == 0x04 || ((Nusiz & 0x07) == 0x06)))
				{
					ScanCnt = 0;
				}

				// Reset is no longer in effect
				Reset = false;

				// Increment the counter
				HPosCnt++;

				// Counter loops at 160 
				HPosCnt %= 160;

				if (ResetCnt < 4)
				{
					ResetCnt++;
				}

				if (ResetCnt == 4)
				{
					HPosCnt = 0;
					Reset = true;
					ResetCnt++;
				}

				return result;
			}

			public void SyncState(Serializer ser)
			{
				Missile.SyncState(ser);
				ser.Sync("grp", ref Grp);
				ser.Sync("dgrp", ref Dgrp);
				ser.Sync("color", ref Color);
				ser.Sync("hPosCnt", ref HPosCnt);
				ser.Sync("scanCnt", ref ScanCnt);
				ser.Sync("scanStrchCnt", ref ScanStrchCnt);
				ser.Sync("HM", ref HM);
				ser.Sync("reflect", ref Reflect);
				ser.Sync("delay", ref Delay);
				ser.Sync("nusiz", ref Nusiz);
				ser.Sync("reset", ref Reset);
				ser.Sync("resetCnt", ref ResetCnt);
				ser.Sync("collisions", ref Collisions);
			}
		}
	}
}
