using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;

using Icarus.Graphics.Animation;
using Icarus.Graphics.Animation.GDI;

namespace FramesetViewer
{
	/// <summary>
	/// Summary description for FramePanel.
	/// </summary>
	public class FramePanel : System.Windows.Forms.UserControl
	{
		/// <summary> 
		/// Required designer variable.
		/// </summary>
		private System.ComponentModel.Container components = null;

		private Frameset m_Frames = null;
		private int m_CurrentFrameIndex = 0;
		private Point m_CenterPoint = new Point(0, 0);
		private Rectangle m_BoundsRectangle = new Rectangle(0, 0, 0, 0);
		private bool m_ShowGuides = false;
		private Point m_OldMouse = new Point(0, 0);
		private Frameset m_Background = null;

		//Some pens:
		Pen m_PenGray = new Pen(Color.Gray);
		Pen m_PenCyan = new Pen(Color.Cyan);

		public Frameset Frames 
		{
			get { return m_Frames; }
			set 
			{
				m_Frames = value; 
				CurrentFrame = 0;
				this.Invalidate();
			}
		}

		public Frameset BackgroundFrameset
		{
			get { return m_Background; }
			set 
			{
				m_Background = value; 
				this.Invalidate();
			}
		}

		public int CurrentFrame 
		{
			get { return m_CurrentFrameIndex; }
			set 
			{
				m_CurrentFrameIndex = value;
				UpdateBoundsRectangle();
				this.Invalidate();
			}
		}

		public bool ShowGuides 
		{
			get { return m_ShowGuides; }
			set 
			{
				m_ShowGuides = value;
				this.Invalidate();
			}
		}

		public bool HasFrames 
		{
			get { return (this.Frames != null) && (this.Frames.getFrameCount() > 0); }
		}

		public bool HasBackgroundFrames 
		{
			get { return (this.BackgroundFrameset != null) && (this.BackgroundFrameset.getFrameCount() > 0); }
		}

		public FramePanel()
		{
			InitializeComponent();
			UpdateCenterPoint();
		}

		/// <summary> 
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if(components != null)
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		#region Component Designer generated code
		/// <summary> 
		/// Required method for Designer support - do not modify 
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			// 
			// FramePanel
			// 
			this.Name = "FramePanel";
			this.Resize += new System.EventHandler(this.FramePanel_Resize);
			this.MouseUp += new System.Windows.Forms.MouseEventHandler(this.FramePanel_MouseUp);
			this.Paint += new System.Windows.Forms.PaintEventHandler(this.FramePanel_Paint);
			this.MouseMove += new MouseEventHandler(FramePanel_MouseMove);

		}
		#endregion

		private void UpdateCenterPoint() 
		{
			m_CenterPoint.X = this.Width / 2;
			m_CenterPoint.Y = this.Height / 2;
			this.Invalidate();
		}

		private void UpdateBoundsRectangle() 
		{
			if (this.HasFrames) 
			{
				GDIFrame f = (GDIFrame) this.Frames.getFrameAt(this.CurrentFrame);

				m_BoundsRectangle.X = -f.getAnchorPoint().X;
				m_BoundsRectangle.Y = -f.getAnchorPoint().Y;
				m_BoundsRectangle.Width = f.getImageWidth();
				m_BoundsRectangle.Height = f.getImageHeight();
			}
		}

		private void FramePanel_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
		{
			if (this.HasFrames) 
			{
				Graphics g = e.Graphics;
				GDIRenderParameters param = new GDIRenderParameters(g);

				//Render background if we have it:
				if (this.HasBackgroundFrames)
				{
					this.BackgroundFrameset.getFrameAt(this.CurrentFrame % this.BackgroundFrameset.getFrameCount()).Render(m_CenterPoint, param);
				}

				//Render the actual animation frame:
				IFrame f = this.Frames.getFrameAt(this.CurrentFrame);
				f.Render(m_CenterPoint, param);

				if (m_ShowGuides) 
				{
					//Render center rulers:
					g.DrawLine(m_PenGray, 0, m_CenterPoint.Y, this.Width, m_CenterPoint.Y);
					g.DrawLine(m_PenGray, m_CenterPoint.X, 0, m_CenterPoint.X, this.Height);

					//Render bounds rulers:
					int left = m_CenterPoint.X + m_BoundsRectangle.Left - 1;
					int top = m_CenterPoint.Y + m_BoundsRectangle.Top - 1;
					int right = m_CenterPoint.X + m_BoundsRectangle.Right;
					int bottom = m_CenterPoint.Y + m_BoundsRectangle.Bottom;

					g.DrawLine(m_PenCyan, left, 0, left, this.Height);
					g.DrawLine(m_PenCyan, 0, top, this.Width, top);
					g.DrawLine(m_PenCyan, right, 0, right, this.Height);
					g.DrawLine(m_PenCyan, 0, bottom, this.Width, bottom);
				}
			}
		}

		private void FramePanel_Resize(object sender, System.EventArgs e)
		{
			UpdateCenterPoint();
		}

		private void FramePanel_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
		{
			if (this.Frames == null) return;

			AbstractFrame f = this.Frames.getFrameAt(this.CurrentFrame) as AbstractFrame;
			if (f == null) return;

			if (System.Windows.Forms.Control.ModifierKeys == Keys.Control) 
			{
				int x = e.X - m_CenterPoint.X + Frames.getFrameAt(CurrentFrame).getAnchorPoint().X;
				int y = e.Y - m_CenterPoint.Y + Frames.getFrameAt(CurrentFrame).getAnchorPoint().Y;

				f.setAnchorPoint(new Point(x, y));
			}

			this.UpdateBoundsRectangle();
			this.Invalidate();
		}

		private void FramePanel_MouseMove(object sender, MouseEventArgs e)
		{
			if (this.Frames == null) return;

			AbstractFrame f = this.Frames.getFrameAt(this.CurrentFrame) as AbstractFrame;
			if (f == null) return;

			if (e.Button == MouseButtons.Left)
			{
				// We are dragging:
				Point pnt = f.getAnchorPoint();
				pnt.Offset(m_OldMouse.X - e.X, m_OldMouse.Y - e.Y);
				f.setAnchorPoint(pnt);

				this.UpdateBoundsRectangle();
				this.Invalidate();
			}

			m_OldMouse.X = e.X;
			m_OldMouse.Y = e.Y;
		}
	}
}
