using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

using Tao.OpenGl;

namespace Log740
{
    public class ObjectGL
    {
        protected Quaternion rotation = Quaternion.Identity();
        protected Vecteur3F size = new Vecteur3F(1, 1, 1);
        protected Vecteur3F location = new Vecteur3F();
        protected bool selectable = true;

        public int name;

        private ObjectGL parent;
        private List<ObjectGL> children = new List<ObjectGL>();

        public ObjectGL()
        {
        }

        public bool Selectable
        {
            get
            {
                return selectable;
            }
            set
            {
                selectable = value;
            }
        }

        public Quaternion Rotation
        {
            get
            {
                return this.rotation;
            }
            set
            {
                this.rotation = value;
            }
        }

        public Vecteur3F Size
        {
            get
            {
                return this.size;
            }
            set
            {
                this.size = value;
            }
        }

        public Vecteur3F Location
        {
            get
            {
                return this.location;
            }
            set
            {
                this.location = value;
            }
        }

        virtual protected void AnimateInternal()
        {
        }

        public void Animate()
        {
            AnimateInternal();
            foreach (ObjectGL child in children)
            {
                child.Animate();
            }
        }

        public void AddChildren(ObjectGL obj)
        {
            if (obj.parent == null)
            {
                this.children.Add(obj);
                obj.parent = this;
            }
        }

        public void RemoveChildren(ObjectGL obj)
        {
            if (obj.parent == this)
            {
                this.children.Remove(obj);
                obj.parent = null;
            }
        }

        virtual protected bool CollisionInternal(Vecteur3F point, Vecteur3F vitesse)
        {
            return false;
        }

        public bool Collision(Vecteur3F point, Vecteur3F vitesse)
        {
            point -= location;
            point = -rotation * point;
            point.X /= size.X;
            point.Y /= size.Y;
            point.Z /= size.Z;

            vitesse = -rotation * vitesse;
            vitesse.X /= size.X;
            vitesse.Y /= size.Y;
            vitesse.Z /= size.Z;

            if (CollisionInternal(point, vitesse))
            {
                return true;
            }

            foreach (ObjectGL child in children)
            {
                if (child.Collision(point, vitesse))
                {
                    return true;
                }
            }

            return false;
        }

        virtual protected void DrawInternal()
        {
        }

        virtual protected void DrawWithNamesInternal()
        {
            DrawInternal();
        }

        private int DrawWithName(int name)
        {
            Gl.glPushMatrix();
            Orientation();

            if (selectable)
            {
                name += 1;
                this.name = name;

                Gl.glLoadName(this.name);
                DrawWithNamesInternal();
            }
            else
            {
                this.name = -1;
            }

            name = DrawChildrenWithNames(name);
            Gl.glPopMatrix();

            return name;
        }

        public void DrawWithNames()
        {
            Gl.glPushName(0);
            DrawWithName(0);
            Gl.glPopName();
        }

        public ObjectGL Selected(int name)
        {
            if (name == this.name)
            {
                return this;
            }
            else
            {
                foreach (ObjectGL child in children)
                {
                    ObjectGL selected = child.Selected(name);

                    if (selected != null)
                    {
                        return selected;
                    }
                }
            }

            return null;
        }

        public void Draw()
        {
            Gl.glPushMatrix();
            Orientation();

            DrawInternal();

            DrawChildren();
            Gl.glPopMatrix();
        }

        protected void DrawChildren()
        {
            foreach (ObjectGL child in children)
            {
                child.Draw();
            }
        }

        protected int DrawChildrenWithNames(int name)
        {
            foreach (ObjectGL child in children)
            {
                name = child.DrawWithName(name);
            }

            return name;
        }

        protected void Orientation()
        {
            double x, y, z, a;
            a = rotation.Angle;
            x = rotation.X;
            y = rotation.Y;
            z = rotation.Z;
            Gl.glTranslated(location.X, location.Y, location.Z);
            Gl.glRotated(180 * a / Math.PI, x, y, z);
            Gl.glScaled(size.X, size.Y, size.Z);
        }
    }
}
