using System;
using System.Collections.Generic;
using System.Text;
using Tao.OpenGl;

namespace GLUtils
{
	public class GLObject
	{
		public enum ObjectTypes { Background, Normal, HUD };

        #region member
        //=============
        // general
        protected Vector3 thePosition;
        protected Vector3 theRotation = new Vector3();
        protected Vector3 theSize;
		protected Vector3 theColor = new Vector3(1.0f, 1.0f, 1.0f); // x=r, y=g, z=b
        protected string theTexture; // name of the texture to be used
        protected ObjectTypes theObjectType = ObjectTypes.Normal;
		protected bool theIsVisible = true;

        // effects
        protected bool theUseAlphaBlending = false;
        protected float theAlphaBlending = 0.5f;

        // animation
        protected DateTime theLastUpdate = DateTime.Now;
        protected Vector3 theSpeed = new Vector3(); // [units/s]
        protected Vector3 theRotationSpeed = new Vector3(); // [rad/s]
        #endregion // member


        #region properties
        //=================
        /// <summary>
        /// Objects drawing type. Determines the drawing order.
		/// </summary>
		public ObjectTypes ObjectType
			{
            get { return theObjectType; }
            set { theObjectType = value; }
        }

        /// <summary>
        /// 3D vector with color values of the object
        /// x=red, y=green, z=blue, components should be between 0.0f an 1.0f
        /// </summary>
        public Vector3 Color
        {
            get { return theColor; }
            set { theColor = value; }
        }

        /// <summary>
        /// 3D vector with current position of the object
        /// </summary>
        public Vector3 Position
        {
            get { return thePosition; }
            set { thePosition = value; }
        }

        /// <summary>
        /// 3D vector with current rotation of the object
        /// </summary>
        public Vector3 Rotation
        {
            get { return theRotation; }
            set { theRotation = value; }
        }

        /// <summary>
        /// 3D Vector with objects size
        /// </summary>
        public Vector3 Size
        {
            get { return theSize; }
            set { theSize = value; }
        }

        /// <summary>
        /// Name of used texture
        /// </summary>
        public string Texture
        {
            get { return theTexture; }
            set { theTexture = value; }
        }
		
        /// <summary>
        /// Object is visible
        /// </summary>
		public bool IsVisible
		{
			get { return theIsVisible; }
			set { theIsVisible = value; }
		}


        /// <summary>
        /// Specifies whether to use alpha blending or not
        /// </summary>
        public bool UseAlphaBlending
        {
            get { return theUseAlphaBlending; }
            set { theUseAlphaBlending = value; }
        }

        /// <summary>
        /// Blend factor (from 0 to 1)
        /// </summary>
        public float AlphaBlending
        {
            get { return theAlphaBlending; }
            set { theAlphaBlending = value; }
        }


        /// <summary>
        /// Vector3 containing the object's current speed [units/s]
        /// </summary>
        public Vector3 Speed
        {
            get { return theSpeed; }
            set { theSpeed = value; }
        }

        /// <summary>
        /// Vector3 containing the object's current rotation speed [rad/s]
        /// </summary>
        public Vector3 RotationSpeed
        {
            get { return theRotationSpeed; }
            set { theRotationSpeed = value; }
        }
        #endregion // properties


        // constructor: position, size
        public GLObject(Vector3 position, Vector3 size)
        {
            this.thePosition = position;
            this.theSize = size;
        }

        // constructor: position
        public GLObject(Vector3 position)
            : this(position, new Vector3(1.0f, 1.0f, 1.0f))
		{
		}
		
		public GLObject()
			: this(new Vector3(0.0f, 0.0f, 0.0f))
		{
		}


        /// <summary>
		/// Draw object to current OpenGL screen
		/// </summary>
		public virtual void Draw()
		{
            Gl.glLoadIdentity(); // Reset The Current Modelview Matrix
            Gl.glTranslatef(thePosition.X, thePosition.Y, thePosition.Z);

            // XYZ-rotation
            // rotation angle must be given in degrees
            Gl.glRotatef((float)(180.0 / Math.PI * theRotation.X), 1.0f, 0.0f, 0.0f);
            Gl.glRotatef((float)(180.0 / Math.PI * theRotation.Y), 0.0f, 1.0f, 0.0f);
            Gl.glRotatef((float)(180.0 / Math.PI * theRotation.Z), 0.0f, 0.0f, 1.0f);

            if (theUseAlphaBlending)
            {
                Gl.glEnable(Gl.GL_BLEND);
                Gl.glColor4f(theColor.X, theColor.Y, theColor.Z, theAlphaBlending);
            }
            else
            {
                Gl.glDisable(Gl.GL_BLEND);
                Gl.glColor3f(theColor.X, theColor.Y, theColor.Z);
            }


            int textureAddress = GLScreen.GetTextureAddress(theTexture);
			if (textureAddress == -1)
				textureAddress = GLScreen.GetTextureAddress("empty");
			
			if (textureAddress != -1)
				Gl.glBindTexture(Gl.GL_TEXTURE_2D, textureAddress);
				
           
            Gl.glBegin(Gl.GL_TRIANGLE_STRIP); // draw a quad using a triangle strip
            {
                Gl.glTexCoord2f(0.0f, 0.0f);
                Gl.glVertex3f(-0.5f * theSize.X, 0.5f * theSize.Y, 0.0f); // upper left corner
                Gl.glTexCoord2f(1.0f, 0.0f);
                Gl.glVertex3f(0.5f * theSize.X, 0.5f * theSize.Y, 0.0f); // upper right corner
                Gl.glTexCoord2f(0.0f, 1.0f);
                Gl.glVertex3f(-0.5f * theSize.X, -0.5f * theSize.Y, 0.0f); // lower left corner
                Gl.glTexCoord2f(1.0f, 1.0f);
                Gl.glVertex3f(0.5f * theSize.X, -0.5f * theSize.Y, 0.0f); // lower right corner
            }
            Gl.glEnd();	// done drawing the triangle strip

			Gl.glDisable(Gl.GL_BLEND);
        }

        /// <summary>
        /// Calculate collisions with other objects
        /// </summary>
		/// <param name="objects"></param>
		public virtual bool Collide(LinkedList<GLObject> objects)
		{
			return false;
	    }


        /// <summary>
        /// Do special animation
        /// </summary>
        public virtual void Animate(Random rnd)
        {
            float timeSpan = (float)(0.001*(DateTime.Now - theLastUpdate).TotalMilliseconds);

            thePosition = thePosition + timeSpan * theSpeed;
            theRotation = theRotation + timeSpan * theRotationSpeed;

            theLastUpdate = DateTime.Now;
        }
    }
}
