using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Serialization;
using System.Drawing;



using Motion6D;
using BitmapConsumer;

namespace InterfaceOpenGL
{
    [Serializable()]
    public class OpenGLCamera : Camera, ISerializable, IBitmapProvider
    {

        #region Fields

        private OpenGL_Library.CameraGL camera = null;
        private int width;
        private int height;
        static private int cameraWidth = 600;
        static private int cameraHeight = 600;
        private Graphics graphics;
        private double angle = 40;
        private double[,] matr4 = new double[4, 4];
        private ReferenceFrame helperFrame = new ReferenceFrame();
        private double[] vector16 = new double[16];
        private double[] shift = new double[3];
        protected Bitmap bmp;


        #endregion

        #region Ctor

        internal OpenGLCamera()
        {
            width = cameraWidth;
            height = cameraHeight;
            init();
        }

        protected OpenGLCamera(SerializationInfo info, StreamingContext context)
        {
            width = (int)info.GetValue("Width", typeof(int));
            height = (int)info.GetValue("Height", typeof(int));
            angle = (double)info.GetValue("Angle", typeof(double));
            init();
        }

        #endregion

        #region Overriden Members

        public override void UpdateImage()
        {
            if (graphics == null)
            {
                return;
            }
            draw(graphics);
        }

        #endregion

        #region ISerializable Members

        void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("Width", width, typeof(int));
            info.AddValue("Height", height, typeof(int));
            info.AddValue("Angle", angle, typeof(double));
        }

        #endregion

        #region IBitmapProvider Members

        Bitmap IBitmapProvider.Bitmap
        {
            get 
            {
                Graphics g = Graphics.FromImage(bmp);
                draw(g, true);
                return bmp;
            }
        }

        #endregion

        #region Specific Members

        internal unsafe void Prepare(Graphics g, int mode)
        {
           IntPtr hdc = g.GetHdc();
           camera.PrepareHDC(hdc.ToPointer(), mode);
           g.ReleaseHdc(hdc);
        }

        unsafe private void draw(Graphics g)
        {
            IntPtr hdc = graphics.GetHdc();
            camera.BeginPaint(hdc.ToPointer());
            ReferenceFrame b = BaseFrame;
            int n = Count;
            for (int i = 0; i < n; i++)
            {
                IPosition p = this[i];
                object obj = p.Parameters;
                if (!(obj is ShapeGL))
                {
                    continue;
                }
                ShapeGL s = obj as ShapeGL;
                ReferenceFrame f = ReferenceFrame.GetParentFrame(p);
                ReferenceFrame.GetRelative(b, f, helperFrame, shift, matr4, vector16);
                camera.Draw(hdc.ToPointer(), s.Shape, vector16);
            }
            camera.EndPaint(hdc.ToPointer());
            graphics.ReleaseHdc(hdc);
        }

        unsafe private void draw(Graphics g, bool invertY)
        {
            IntPtr hdc = g.GetHdc();
            camera.BeginPaint(hdc.ToPointer(), invertY);
            ReferenceFrame b = BaseFrame;
            int n = Count;
            for (int i = 0; i < n; i++)
            {
                IPosition p = this[i];
                object obj = p.Parameters;
                if (!(obj is ShapeGL))
                {
                    continue;
                }
                ShapeGL s = obj as ShapeGL;
                ReferenceFrame f = ReferenceFrame.GetParentFrame(p);
                ReferenceFrame.GetRelative(b, f, helperFrame, shift, matr4, vector16);
                camera.Draw(hdc.ToPointer(), s.Shape, vector16);
            }
            camera.EndPaint(hdc.ToPointer());
            g.ReleaseHdc(hdc);
        }

        internal Graphics Graphics
        {
            get
            {
                return graphics;
            }
            set
            {
                graphics = value;
            }
        }

        private unsafe void init()
        {
            camera = new OpenGL_Library.CameraGL(width, height);
            camera.SetReferenceAngle(angle);
            bmp = new Bitmap(width, height);
            Graphics g = Graphics.FromImage(bmp);
            camera.PrepareHDC(g.GetHdc().ToPointer(), 1);
        }

        #endregion
    }
}
