using System;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;

namespace Phidget22.ExampleUtils {
	public partial class PhidgetInfoBox : UserControl {

		LocationData locationData;
		Phidget attachedDevice;

		// track whether we've hooked the parent events
		private bool parentSizeHooked = false;

		private Font startingSmallFont;
		private float startingDpi;

		public PhidgetInfoBox() {
			InitializeComponent();

			startingSmallFont = remoteLbl.Font;
			startingDpi = DeviceDpi;

			Clear();
		}

		private void PhidgetInfoBox_ParentChanged(object sender, EventArgs e) {
			// If we were previously hooked, unhook old parent (defensive)
			if (parentSizeHooked && this.Parent != null) {
				UnhookParentEvents();
			}

			// Hook new parent so we can react to size/layout changes immediately
			HookParentEvents();
			// Make an immediate adjustment to ensure width matches parent
			AdjustWidthToParent();
		}

		private void HookParentEvents() {
			try {
				if (this.Parent == null || parentSizeHooked)
					return;

				// SizeChanged covers normal resize and other layout changes.
				this.Parent.SizeChanged += Parent_SizeChanged;

				// Layout is a good fallback for dock/anchor/children changes
				this.Parent.Layout += Parent_Layout;

				parentSizeHooked = true;
			} catch { /* swallow - defensive */ }
		}

		private void UnhookParentEvents() {
			try {
				if (this.Parent == null || !parentSizeHooked)
					return;

				this.Parent.SizeChanged -= Parent_SizeChanged;
				this.Parent.Layout -= Parent_Layout;
			} catch { /* swallow - defensive */ }
			parentSizeHooked = false;
		}

		private void Parent_SizeChanged(object sender, EventArgs e) {
			AdjustWidthToParent();
		}

		private void Parent_Layout(object sender, LayoutEventArgs e) {
			// layout changes can affect available client width
			if (e.AffectedProperty == "Bounds" || e.AffectedProperty == "ClientSize" || String.IsNullOrEmpty(e.AffectedProperty))
				AdjustWidthToParent();
		}

		private void AdjustWidthToParent() {
			// Only run if we have a parent
			if (this.Parent == null)
				return;

			// If docked to top (or anchored left+right) then enforce full client width
			if (this.Dock == DockStyle.Top || (this.Anchor & AnchorStyles.Right) == AnchorStyles.Right) {
				try {
					// compute target width in parent's client coordinates, account for margins
					int targetWidth = this.Parent.ClientSize.Width - this.Margin.Left - this.Margin.Right;

					// enforce a sane minimum
					if (targetWidth < 20)
						targetWidth = 20;

					// apply synchronously
					this.SuspendLayout();
					this.Width = targetWidth;

					// If your inner layout depends on groupBox1.Width, make sure it's refreshed.
					try {
						groupBox1.Width = Math.Max(0, this.ClientSize.Width - 12);
						// if you draw an explicit line, recompute its size
						line1.Size = new Size(Math.Max(1, groupBox1.Width - 12), line1.Height);
					} catch { /* designer controls might not exist at certain times */ }

					this.ResumeLayout(true);

					// Force immediate layout + paint so the change is visible right away
					this.Parent.PerformLayout();
					this.PerformLayout();
					this.Invalidate(true);
					this.Update();
				} catch (Exception) {
					// non-fatal
				}
			}
		}

		public void FillPhidgetInfo(Phidget phidget) {
			attachedDevice = phidget;
			locationData = new LocationData(attachedDevice);
			channelTxt.Text = phidget.Channel.ToString();
			versionTxt.Text = phidget.DeviceVersion.ToString();

			if (phidget.IsHubPortDevice)
				attachedDeviceNameTxt.Text = phidget.Parent.Parent.DeviceSKU + " - " + phidget.Parent.Parent.DeviceName;
			else
				attachedDeviceNameTxt.Text = phidget.DeviceSKU + " - " + phidget.DeviceName;

			if (phidget.DeviceClass == DeviceClass.VINT) {

				serialNumberLbl.Text = "Hub Serial Number:";
				serialNumberTxt.Text = phidget.DeviceSerialNumber.ToString();

				hubPortLbl.Visible = true;
				hubPortTxt.Visible = true;
				hubPortTxt.Text = phidget.HubPort.ToString();
			} else {
				serialNumberTxt.Text = phidget.DeviceSerialNumber.ToString();
			}

			try {
				updateImage();

				if (phidget.IsRemote)
					remoteLbl.Visible = true;
				else
					remoteLbl.Visible = false;

				if (phidget.ChannelPersistence)
					persitenceLbl.Visible = true;
				else
					persitenceLbl.Visible = false;
			} catch { }

			Control par = this.Parent;
			while (!(par is Form))
				par = par.Parent;

			((Form)par).Text = phidget.ChannelName;
		}

		private void updateImage() {

			String sku;
			if (attachedDevice != null && attachedDevice.Attached) {
				if (attachedDevice.IsHubPortDevice)
					sku = attachedDevice.Parent.Parent.DeviceSKU.Split(new char[] { '/' })[0];
				else
					sku = attachedDevice.DeviceSKU.Split(new char[] { '/' })[0];

				//Special attention to the 1018 because it's so common
				if (attachedDevice.DeviceSKU.Contains("1018"))
					sku = "1018";

				Assembly _assembly = Assembly.GetExecutingAssembly();
				String imageName = null;

				if (DeviceDpi / 96f > 2)
					imageName = _assembly.GetManifestResourceNames().Where(img => img.EndsWith("." + sku + "_x3.png")).FirstOrDefault();
				else if (DeviceDpi / 96f > 1)
					imageName = _assembly.GetManifestResourceNames().Where(img => img.EndsWith("." + sku + "_x2.png")).FirstOrDefault();

				if (imageName == null)
					imageName = _assembly.GetManifestResourceNames().Where(img => img.EndsWith("." + sku + ".png")).FirstOrDefault();

				if (imageName != null) {
					pictureBox1.Image = Image.FromStream(_assembly.GetManifestResourceStream(imageName));
					line1.Size = new System.Drawing.Size(groupBox1.Size.Width - 101, 1);
					pictureBox1.Visible = true;
				}
			}
		}

		public void UpdatePersistence() {
			try {
				if (attachedDevice.ChannelPersistence)
					persitenceLbl.Visible = true;
				else
					persitenceLbl.Visible = false;
			} catch { }
		}

		public void Clear() {
			attachedDeviceNameTxt.Text = "Nothing";
			channelTxt.Clear();
			versionTxt.Clear();
			serialNumberTxt.Clear();
			hubPortTxt.Clear();
			serialNumberLbl.Text = "Serial Number:";
			line1.Size = new System.Drawing.Size(groupBox1.Size.Width - 12, 1);
			pictureBox1.Visible = false;

			hubPortLbl.Visible = false;
			hubPortTxt.Visible = false;
			remoteLbl.Visible = false;
			if (locationData != null)
				locationData.Hide();
		}

		private void locationButton_Click(object sender, EventArgs e) {
			if (serialNumberTxt.Text != "") {
				locationData.ShowDialog();
			}
		}

		private void PhidgetInfoBox_DpiChangedAfterParent(object sender, EventArgs e) {
			float factor = DeviceDpi / startingDpi;
			var smallFont = new Font(startingSmallFont.FontFamily, startingSmallFont.Size * factor, startingSmallFont.Style);
			remoteLbl.Font = smallFont;
			persitenceLbl.Font = smallFont;
			try {
				updateImage();
			} catch { }
		}
	}
}
