using System;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using MySQL.GUI.Mdc;

namespace MySQL.Utilities
{
  public class WindowsCanvasViewer : Panel
  {
    #region Member Variables

    private WindowsCanvasViewerPanel canvasPanel = null;

    #endregion

    #region Constructor

    public WindowsCanvasViewer()
    {
      canvasPanel = new WindowsCanvasViewerPanel();
      canvasPanel.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;

      canvasPanel.VScrollbar = new VScrollBar();
      canvasPanel.VScrollbar.Anchor = AnchorStyles.Right | AnchorStyles.Top | AnchorStyles.Bottom;
      canvasPanel.HScrollbar = new HScrollBar();
      canvasPanel.HScrollbar.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;

      canvasPanel.VScrollbar.Scroll += new ScrollEventHandler(canvasPanel.HandleScroll);
      canvasPanel.HScrollbar.Scroll += new ScrollEventHandler(canvasPanel.HandleScroll);

      Controls.Add(canvasPanel.VScrollbar);
      Controls.Add(canvasPanel.HScrollbar);
      Controls.Add(canvasPanel);

      canvasPanel.Width = ClientSize.Width - canvasPanel.VScrollbar.Width;
      canvasPanel.Height = ClientSize.Height - canvasPanel.HScrollbar.Height;

      canvasPanel.VScrollbar.Top = 0;
      canvasPanel.VScrollbar.Left = canvasPanel.Width;
      canvasPanel.VScrollbar.Height = canvasPanel.Height;

      canvasPanel.HScrollbar.Top = canvasPanel.Height;
      canvasPanel.HScrollbar.Left = 0;
      canvasPanel.HScrollbar.Width = canvasPanel.Width;
    }

    #endregion

    #region Properties

    public BaseWindowsCanvasView Canvas
    {
      get { return canvasPanel.Canvas; }
    }

    public Form OwnerForm
    {
      get { return canvasPanel.OwnerForm; }
      set { canvasPanel.OwnerForm = value; }
    }

    public Panel CanvasPanel
    {
      get { return canvasPanel; }
    }

    #endregion

    #region Public Functions

    public WindowsGLCanvasView InitializeGLCanvas(Form ownerForm, bool handleInput)
    {
      return canvasPanel.InitializeGLCanvas(ownerForm, handleInput);
    }

    public WindowsGDICanvasView InitializeGDICanvas(Form ownerForm, bool handleInput)
    {
      return canvasPanel.InitializeGDICanvas(ownerForm, handleInput);
    }

    public void FinalizeCanvas()
    {
      canvasPanel.FinalizeCanvas();
    }

    #endregion
    
  }

	public class WindowsCanvasViewerPanel : Panel
	{
    private const int WM_PAINT = 0x000F;

		#region Member Variables

    private ScrollBar vScrollbar= null;
    private ScrollBar hScrollbar= null;

		private BaseWindowsCanvasView canvas = null;
		private bool canvasInitialized = false;
	
    private bool viewportChanged = false;
    private bool scrolling = false;

    private bool handleInput = false;

    public ToolStripLabel canvasFPSLabel = null;

		#endregion

    #region Constructor

    public WindowsCanvasViewerPanel()
    {
      Click += new EventHandler(ScrollablePanel_Click);
      handleInput = true;

      SetStyle(ControlStyles.AllPaintingInWmPaint|ControlStyles.UserPaint|ControlStyles.Opaque, true);
    }

    #endregion

    #region Public Functions

    public WindowsGLCanvasView InitializeGLCanvas(Form ownerForm, bool HandleInput)
    {
      handleInput = HandleInput;

      canvas = new WindowsGLCanvasView(Handle, ClientRectangle.Width, ClientRectangle.Height);
      if (canvas != null)
      {
        canvas.initialize();
        canvas.set_on_needs_repaint(OnNeedsRepaint);
        canvas.set_on_viewport_changed(OnViewportChanged);
        OwnerForm = ownerForm;
        canvasInitialized = true;

        UpdateScrollBarSizes();
      }
      return (WindowsGLCanvasView)canvas;
    }

    public WindowsGDICanvasView InitializeGDICanvas(Form ownerForm, bool HandleInput)
    {
      handleInput = HandleInput;

      canvas = new WindowsGDICanvasView(Handle, ClientRectangle.Width, ClientRectangle.Height, true);
      if (canvas != null)
      {
        //SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

        canvas.initialize();
        canvas.set_on_needs_repaint(OnNeedsRepaint);
        canvas.set_on_viewport_changed(OnViewportChanged);
        OwnerForm = ownerForm;
        canvasInitialized = true;

        UpdateScrollBarSizes();
      }
      return (WindowsGDICanvasView)canvas;
    }

    public void FinalizeCanvas()
    {
      canvasInitialized = false;
      canvas = null;
    }

    #endregion

    #region Properties

    public BaseWindowsCanvasView Canvas
    {
      get { return canvas; }
    }

    public Form OwnerForm
    {
      get
      {
        if (canvas != null)
          return canvas.GetOwnerForm();
        else
          return null;
      }
      set
      {
        if (canvas != null)
          canvas.SetOwnerForm(value);
      }
    }

    public ScrollBar VScrollbar
    {
      get { return vScrollbar; }
      set { vScrollbar = value; }
    }

    public ScrollBar HScrollbar
    {
      get { return hScrollbar; }
      set { hScrollbar = value; }
    }

    #endregion

    #region Implemenation

		private void OnNeedsRepaint(int x, int y, int w, int h)
		{
			Invalidate(new System.Drawing.Rectangle(x, y, w, h));
		}

    private void OnViewportChanged()
    {
      if (scrolling)
        return;
      viewportChanged = true;
      Invalidate();
    }

		private void UpdateScrollbar()
		{
			UpdateScrollBarSizes();
			UpdateScrollBarPositions();
		}

    private void UpdateScrollBarPositions()
    {
      double x, y, w, h;

      if (canvas != null)
      {
        canvas.get_viewport(out x, out y, out w, out h);

        if (y < 0) 
          y = 0; 
        else if (y > vScrollbar.Maximum) 
          y = vScrollbar.Maximum;

        if (x < 0) 
          x = 0; 
        else if (x > hScrollbar.Maximum) 
          x = hScrollbar.Maximum;

        if (vScrollbar.Value != (int)y)
          vScrollbar.Value= (int)y;
        if (hScrollbar.Value != (int)x)
          hScrollbar.Value = (int)x;
      }
    }

    private void UpdateScrollBarSizes()
    {
      double x, y, w, h;
      double total_w, total_h;
     
      if (canvas != null)
      {
        canvas.get_total_view_size(out total_w, out total_h);

        canvas.get_viewport(out x, out y, out w, out h);

        vScrollbar.Minimum = 0;
        hScrollbar.Minimum = 0;

        vScrollbar.Maximum = (int)(total_h);
        vScrollbar.SmallChange = ClientSize.Height/20;
        vScrollbar.LargeChange = (int)(h);

        hScrollbar.Maximum = (int)(total_w);
        hScrollbar.SmallChange = ClientSize.Width/20;
        hScrollbar.LargeChange = (int)(w);
      }
    }

    public void HandleScroll(Object sender, ScrollEventArgs args)
    {
      scrolling = true;
      canvas.scroll_to(hScrollbar.Value, vScrollbar.Value);
      UpdateScrollBarPositions();
      scrolling = false;
    }

    public void DoMouseMove(MouseEventArgs e)
    {
      if (canvasInitialized)
        canvas.OnMouseMove(e, ModifierKeys, MouseButtons);
    }


    protected override void OnMouseMove(MouseEventArgs e)
    {
      if (canvasInitialized && handleInput)
        canvas.OnMouseMove(e, ModifierKeys, MouseButtons);
      base.OnMouseMove(e);
     //-alfredo (what is this for?) UpdateScrollBarPositions();
    }

    protected override void OnMouseDown(MouseEventArgs e)
    {
      if (canvasInitialized && handleInput)
        canvas.OnMouseDown(e, ModifierKeys, MouseButtons);
      base.OnMouseDown(e);
    }

    protected override void OnMouseUp(MouseEventArgs e)
    {
      if (canvasInitialized && handleInput)
        canvas.OnMouseUp(e, ModifierKeys, MouseButtons);
      base.OnMouseUp(e);
      //UpdateScrollBarPositions();
    }

    protected override void OnMouseWheel(MouseEventArgs e)
    {
      if (canvasInitialized)
      {
        double x, y, w, h;
        canvas.get_viewport(out x, out y, out w, out h);

        if ((ModifierKeys & Keys.Control) != 0)
          x -= e.Delta / 5;
        else
          y -= e.Delta/5;

        if (y < 0) y = 0; else if (y > vScrollbar.Maximum) y = vScrollbar.Maximum;
        if (x < 0) x = 0; else if (x > hScrollbar.Maximum) x = hScrollbar.Maximum;

        if (vScrollbar.Value != (int)y)
          vScrollbar.Value = (int)y;
        if (hScrollbar.Value != (int)x)
          hScrollbar.Value = (int)x;

        HandleScroll(null, null);
      }
      base.OnMouseWheel(e);
    }

    protected override void OnKeyDown(KeyEventArgs e)
    {
      if (canvasInitialized)
        canvas.OnKeyDown(e, ModifierKeys);
      base.OnKeyDown(e);
    }

    protected override void OnKeyUp(KeyEventArgs e)
    {
      if (canvasInitialized)
        canvas.OnKeyUp(e, ModifierKeys);
      base.OnKeyUp(e);
    }

    protected override void OnSizeChanged(EventArgs e)
    {
      base.OnSizeChanged(e);
      if (canvasInitialized)
        canvas.OnSizeChanged(ClientRectangle.Width, ClientRectangle.Height);
    }

	  protected override void OnPaintBackground(PaintEventArgs e)
	  {
		  // don't do anything to avoid flickering
		  if (canvas == null)
			  base.OnPaintBackground(e);
    }


    protected override void OnPaint(PaintEventArgs e)
    {
      try
      {
        if (canvasInitialized)
        {
          if (viewportChanged)
          {
            viewportChanged = false;
            UpdateScrollbar();
          }

          canvas.repaint(e.ClipRectangle.Left, e.ClipRectangle.Top,
            e.ClipRectangle.Width, e.ClipRectangle.Height);

          if (canvasFPSLabel != null)
            canvasFPSLabel.Text = String.Format("{0:0.00}fps", canvas.get_fps());
        }
      }
      catch (Exception exc)
      {
        MessageBox.Show(exc.Message);
      }
    }

    #endregion

    /* why this instead of OnPaint?*/
		#region WndProd override
    /*
		protected override void WndProc(ref Message msg)
		{
			base.WndProc(ref msg);

			if (msg.HWnd != this.Handle)
				return;

      try
      {
        switch (msg.Msg)
        {
          case WM_PAINT:
            if (canvasInitialized)
            {
              if (viewportChanged)
              {
                viewportChanged = false;
                UpdateScrollbar();
              }
              canvas.repaint(0, 0, ClientRectangle.Width, ClientRectangle.Height);

              if (canvasFPSLabel != null)
                canvasFPSLabel.Text = String.Format("{0:0.00}fps", canvas.get_fps());
            }
            break;

          default:
            break;

        }
      }
      catch (Exception e)
      {
        MessageBox.Show(e.Message);
      }
		}
    */
		#endregion
     

		#region Panel Got focus

		private void ScrollablePanel_Click(object sender, EventArgs e)
		{
			this.Focus();
		}

		#endregion


	}
}
