using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;

using BizHawk.Client.Common;
using BizHawk.Emulation.Cores.PCEngine;

namespace BizHawk.Client.EmuHawk
{
	public partial class PceBgViewer : Form, IToolForm
	{
		private PCEngine _pce;
		private int _vdcType;

		public PceBgViewer()
		{
			InitializeComponent();
			TopMost = Global.Config.PceBgViewerSettings.TopMost;
			Activated += (o, e) => Generate();
			Closing += (o, e) =>
				{
					Global.Config.PceBgViewerSettings.Wndx = Location.X;
					Global.Config.PceBgViewerSettings.Wndy = Location.Y;
					Global.Config.PCEBGViewerRefreshRate = RefreshRate.Value;
				};
		}

		private void PceBgViewer_Load(object sender, EventArgs e)
		{
			_pce = Global.Emulator as PCEngine;

			if (Global.Config.PceBgViewerSettings.UseWindowPosition)
			{
				Location = Global.Config.PceBgViewerSettings.WindowPosition;
			}

			if (Global.Config.PCEBGViewerRefreshRate >= RefreshRate.Minimum && Global.Config.PCEBGViewerRefreshRate <= RefreshRate.Maximum)
			{
				RefreshRate.Value = Global.Config.PCEBGViewerRefreshRate;
			}
			else
			{
				RefreshRate.Value = RefreshRate.Maximum;
			}
		}

		private void RefreshFloatingWindowControl()
		{
			Owner = Global.Config.PceBgViewerSettings.FloatingWindow ? null : GlobalWin.MainForm;
		}

		#region Public API

		public bool AskSave() { return true; }
		public bool UpdateBefore { get { return true; } }

		public unsafe void Generate()
		{
			if (Global.Emulator.Frame % RefreshRate.Value != 0)
			{
				return;
			}

			var vdc = _vdcType == 0 ? _pce.VDC1 : _pce.VDC2;

			var width = 8 * vdc.BatWidth;
			var height = 8 * vdc.BatHeight;
			var buf = canvas.Bat.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, canvas.Bat.PixelFormat);
			var pitch = buf.Stride / 4;
			var begin = (int*)buf.Scan0.ToPointer();

			int* p = begin;
			for (int y = 0; y < height; ++y)
			{
				int yTile = y / 8;
				int yOfs = y % 8;
				for (int x = 0; x < width; ++x, ++p)
				{
					int xTile = x / 8;
					int xOfs = x % 8;
					int tileNo = vdc.VRAM[(ushort)(((yTile * vdc.BatWidth) + xTile))] & 0x07FF;
					int paletteNo = vdc.VRAM[(ushort)(((yTile * vdc.BatWidth) + xTile))] >> 12;
					int paletteBase = paletteNo * 16;

					byte c = vdc.PatternBuffer[(tileNo * 64) + (yOfs * 8) + xOfs];
					if (c == 0)
					{
						*p = _pce.VCE.Palette[0];
					}
					else
					{
						*p = _pce.VCE.Palette[paletteBase + c];
					}
				}

				p += pitch - width;
			}

			canvas.Bat.UnlockBits(buf);
			canvas.Refresh();
		}

		public void Restart()
		{
			if (Global.Emulator is PCEngine)
			{
				_pce = Global.Emulator as PCEngine;
			}
			else
			{
				Close();
			}
		}

		public void UpdateValues()
		{
			if (Global.Emulator is PCEngine)
			{
				Generate();
			}
			else
			{
				Close();
			}
		}

		#endregion

		#region Events

		#region Menu

		private void FileSubMenu_DropDownOpened(object sender, EventArgs e)
		{
			VDC2MenuItem.Enabled = _pce.SystemId == "SGX";

			VDC1MenuItem.Checked = _vdcType == 0;
			VDC2MenuItem.Checked = _vdcType == 1;
		}

		private void VDC1MenuItem_Click(object sender, EventArgs e)
		{
			_vdcType = 0;
		}

		private void VDC2MenuItem_Click(object sender, EventArgs e)
		{
			_vdcType = 1;
		}

		private void ExitMenuItem_Click(object sender, EventArgs e)
		{
			Close();
		}

		private void OptionsSubMenu_DropDownOpened(object sender, EventArgs e)
		{
			SaveWindowPositionMenuItem.Checked = Global.Config.PceBgViewerSettings.SaveWindowPosition;
			AutoloadMenuItem.Checked = Global.Config.PCEBGViewerAutoload;
			AlwaysOnTopMenuItem.Checked = Global.Config.PceBgViewerSettings.TopMost;
			FloatingWindowMenuItem.Checked = Global.Config.PceBgViewerSettings.FloatingWindow;
		}

		private void AutoloadMenuItem_Click(object sender, EventArgs e)
		{
			Global.Config.PCEBGViewerAutoload ^= true;
		}

		private void SaveWindowPositionMenuItem_Click(object sender, EventArgs e)
		{
			Global.Config.PceBgViewerSettings.SaveWindowPosition ^= true;
		}

		private void AlwaysOnTopMenuItem_Click(object sender, EventArgs e)
		{
			Global.Config.PceBgViewerSettings.TopMost ^= true;
			TopMost = Global.Config.PceBgViewerSettings.TopMost;
		}

		private void FloatingWindowMenuItem_Click(object sender, EventArgs e)
		{
			Global.Config.PceBgViewerSettings.FloatingWindow ^= true;
			RefreshFloatingWindowControl();
		}

		#endregion

		#region Dialog and Controls

		private void Canvas_MouseMove(object sender, MouseEventArgs e)
		{
			var vdc = _vdcType == 0 ? _pce.VDC1 : _pce.VDC2;
			int xTile = e.X / 8;
			int yTile = e.Y / 8;
			int tileNo = vdc.VRAM[(ushort)((yTile * vdc.BatWidth) + xTile)] & 0x07FF;
			int paletteNo = vdc.VRAM[(ushort)((yTile * vdc.BatWidth) + xTile)] >> 12;
			TileIDLabel.Text = tileNo.ToString();
			XYLabel.Text = xTile + ":" + yTile;
			PaletteLabel.Text = paletteNo.ToString();
		}

		protected override void OnShown(EventArgs e)
		{
			RefreshFloatingWindowControl();
			base.OnShown(e);
		}

		#endregion

		#endregion
	}
}
