using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using Microsoft.DirectX.Direct3D;
using Microsoft.DirectX;
using System.Drawing;

namespace Obligatorisk
{
    public class Car : ModelComponent
    {
        private float speed;
        private Gears gear;
        private float yawIncrement;
        private float maxYawIncrement;
        private int kameraPosition;
        private float distance;

        public float Speed
        {
            get { return speed; }
            set { speed = value; }
        }

        public float YawIncrement
        {
            get { return yawIncrement; }
            set { yawIncrement = value; }
        }

        public float Distance
        {
            get { return distance; }
            set { distance = value; }
        }
        public Gears Gear
        {
            get { return this.gear; }
            set { this.gear = value; }
        }
        #region  3D-models (Frank & Kasper) 3. Maj
        // flyttet device og position ud på Modelcomponent da alle modeller har disse variabler indtil videre
        public Car(Model aModel, Device aDevice, Vector3 aPosition)
            : base(aModel, aDevice, aPosition)
        {
            CreateMesh();
            Yaw = 0.000000f;//(float)(2F * Math.PI / 360F) * 500;
            Pitch = 4.7f;//(float)(2F * Math.PI / 360F) * 10F;
            kameraPosition = 1;
            Distance = 5;
            this.gear = Gears.Neutral;
            this.maxYawIncrement = 0.040f;
        }
        #endregion

        public enum Gears
        {
            Reverse,
            Neutral,
            First,
            Second,
            Third,
            Fourth,
            Fifth,
            Sixth,
        }
        public void CreateMesh()
        {
            ExtendedMaterial[] materials = null;
            String path = @"..\..\";
            
            this.Mesh = Mesh.FromFile(path + @"3D-Models\Audi.x",
                MeshFlags.SystemMemory, this.TheDevice, out materials);
            if (this.MeshTextures == null)
            {
                // Egenskaber for materialer og texture udtrækkes 
                this.MeshTextures = new Texture[materials.Length];
                this.MeshMaterials = new Material[materials.Length];
                for (int i = 0; i < materials.Length; i++)
                {
                    this.MeshMaterials[i] = materials[i].Material3D;
                    // Set the ambient color for the material (D3DX does not do this)
                    this.MeshMaterials[i].Ambient = this.MeshMaterials[i].Diffuse;
                    //meshTextures[i] = TextureLoader.FromFile(this.TheDevice, path + "banana.bmp");
                }
            }
        }

        #region  3D-models (Frank & Kasper) 2. Maj
        // lavet render metoden til en override af ModelComponents Render metode.
        public override void Render()
        {
            // tegn boundingbox
            if (true)
            {
                this.DrawBoundingBox();
            }

            // Kamera
            this.TheDevice.RenderState.Lighting = true;
            this.TheDevice.Transform.World = Matrix.RotationYawPitchRoll(Yaw, Pitch, Roll) *
                Matrix.Translation(Position);
            for (int i = 0; i < this.MeshMaterials.Length; i++)
            {
                this.TheDevice.Material = this.MeshMaterials[i];
                this.TheDevice.SetTexture(0, this.MeshTextures[i]);
                this.Mesh.DrawSubset(i);
            }
        }
        #endregion

        private void PowerCurveRecipe()
        {
            //private float power = 3;
            //turn += PowerCurve(gamepad.ThumbSticks.Left.X) * turnRate;
            //(float)Math.Pow(Math.Abs(value), power) * Math.Sign(value);
        }

        #region  3D-models (Frank & Kasper) 9. Maj

        public override bool CollisionDetect()
        {
            foreach (ModelComponent mc in this.TheModel.ModelList)
            {
                if (mc is Car) { continue; }
                double distance = 0;
                //Console.WriteLine(mc.GetType() + " distance is " + distance);
                
                // check distance til de yderste world koordinater
                // so anyway Z koordinatet er negativt ind mod skærmen og positivt væk fra skærmen......  ihvertfald
                // bounding
                Vector3 mcUpperLeft = new Vector3(mc.Position.X - (float)(mc.BoundingBox.Length / 2), 0f, mc.Position.Z - (float)(mc.BoundingBox.Width / 2));
                Vector3 mcUpperRight = new Vector3(mc.Position.X + (float)(mc.BoundingBox.Length / 2), 0f, mc.Position.Z - (float)(mc.BoundingBox.Width / 2));
                Vector3 mcLowerLeft = new Vector3(mc.Position.X - (float)(mc.BoundingBox.Length / 2), 0f, mc.Position.Z + (float)(mc.BoundingBox.Width / 2));
                Vector3 mcLowerRight = new Vector3(mc.Position.X + (float)(mc.BoundingBox.Length / 2), 0f, mc.Position.Z + (float)(mc.BoundingBox.Width / 2));

                Vector3 carUpperLeft = new Vector3(this.Position.X - (float)(this.BoundingBox.Length / 2), 0f, this.Position.Z - (float)(this.BoundingBox.Width / 2));
                Vector3 carUpperRight = new Vector3(this.Position.X + (float)(this.BoundingBox.Length / 2), 0f, this.Position.Z - (float)(this.BoundingBox.Width / 2));
                Vector3 carLowerLeft = new Vector3(this.Position.X - (float)(this.BoundingBox.Length / 2), 0f, this.Position.Z + (float)(this.BoundingBox.Width / 2));
                Vector3 carLowerRight = new Vector3(this.Position.X + (float)(this.BoundingBox.Length / 2), 0f, this.Position.Z + (float)(this.BoundingBox.Width / 2));


                // y = ax + b
                // skulle til at lave SYYYYGE beregninger med skæringspunkter ^^

                Rectangle mcRec = new Rectangle(Convert.ToInt32(mcUpperLeft.X), Convert.ToInt32(mcUpperLeft.Z), Convert.ToInt32(mc.BoundingBox.Length), Convert.ToInt32(mc.BoundingBox.Width));
                Rectangle carRec = new Rectangle(Convert.ToInt32(carUpperLeft.X), Convert.ToInt32(carUpperLeft.Z), Convert.ToInt32(this.BoundingBox.Length), Convert.ToInt32(this.BoundingBox.Width));
                
                if (Rectangle.Intersect(carRec,mcRec) != Rectangle.Empty)
                {
                    Console.WriteLine(mc.GetType() + " collided, distance was " + distance);
                    this.Speed *= -1;

                    return true;
                }

            }
            return false;
        }

        // lavet Update metoden til en override af ModelComponents Update metode.
        static int iCollide = 0;
        public override void Update()
        {

            // Collision Detect
            bool collide = this.CollisionDetect();

            if (collide)
            {
                iCollide++;
                Console.WriteLine(iCollide + " ][ Collission Detected");
            }


            if (!this.TheModel.PressedKeys.Contains(Keys.Left) && !this.TheModel.PressedKeys.Contains(Keys.Right))
            {
                if (YawIncrement >= 0.000f)
                    YawIncrement -= 0.002f;
                if (YawIncrement <= 0.000f)
                    YawIncrement += 0.002f;
            }
            if (this.TheModel.PressedKeys.Contains(Keys.Right))
            { // Flyet drejer og krænger til højre
                //Formel for centifugalkraft og skridpunkt (dæk og vejoverflade)
                if (Speed < 0.05f && Speed > -0.05f)
                    YawIncrement = 0;
                if (Speed < -0.05f && Speed >= -5)
                {
                    if (YawIncrement < 0.010f)
                        YawIncrement += 0.0005f;
                    else
                    {
                        YawIncrement = 0.010f;
                        if (YawIncrement < 0.020f)
                            YawIncrement += 0.0005f;
                    }
                }
                if (Speed < -5 && Speed >= -10)
                {
                    if (YawIncrement < 0.020f)
                        YawIncrement += 0.001f;
                    else
                    {
                        YawIncrement = 0.020f;
                        if (YawIncrement < 0.020f)
                            YawIncrement += 0.001f;
                    }
                }
                if (Speed < -10 && Speed >= -20)
                {
                    if (YawIncrement < 0.030f)
                        YawIncrement += 0.002f;
                    else
                    {
                        YawIncrement = 0.030f;
                        if (YawIncrement < 0.030f)
                            YawIncrement += 0.002f;
                    }
                }
                if (Speed < -20 && Speed >= -40)
                {
                    if (YawIncrement < 0.040f)
                        YawIncrement += 0.003f;
                    else
                    {
                        YawIncrement = 0.040f;
                        if (YawIncrement < 0.040f)
                            YawIncrement += 0.003f;
                    }
                }
                if (Speed < -40 && Speed >= -251)
                {
                    if (YawIncrement < 0.040f)
                        YawIncrement += 0.005f;
                    else
                    {
                        YawIncrement = 0.040f;
                        if (YawIncrement < 0.040f)
                            YawIncrement += 0.005f;
                    }
                }
                //Roll -= 0.01f;
            }
            if (this.TheModel.PressedKeys.Contains(Keys.Left))
            { // Bilen drejer og krænger til venstre
                //Formel for centifugalkraft og skridpunkt (dæk og vejoverflade)
                if (Speed < 0.05f && Speed >= -0.05f)
                    YawIncrement = 0;
                if (Speed < -0.05f && Speed >= -5)
                {
                    if (YawIncrement > -0.010f)
                        YawIncrement -= 0.0005f;
                    else
                    {
                        YawIncrement = -0.010f;
                        if (YawIncrement > -0.020f)
                            YawIncrement -= 0.0005f;
                    }
                }
                if (Speed < -5 && Speed >= -10)
                {
                    if (YawIncrement > -0.020f)
                        YawIncrement -= 0.001f;
                    else
                    {
                        YawIncrement = -0.020f;
                        if (YawIncrement > -0.020f)
                            YawIncrement -= 0.001f;
                    }
                }
                if (Speed < -10 && Speed >= -20)
                {
                    if (YawIncrement > -0.030f)
                        YawIncrement -= 0.002f;
                    else
                    {
                        YawIncrement = -0.030f;
                        if (YawIncrement > -0.030f)
                            YawIncrement -= 0.002f;
                    }
                }
                if (Speed < -20 && Speed >= -40)
                {
                    if (YawIncrement > -0.040f)
                        YawIncrement -= 0.003f;
                    else
                    {
                        YawIncrement = -0.040f;
                        if (YawIncrement > -0.040f)
                            YawIncrement -= 0.003f;
                    }
                }
                if (Speed < -40 && Speed >= -251)
                {
                    if (YawIncrement > -0.040f)
                        YawIncrement -= 0.005f;
                    else
                    {
                        YawIncrement = -0.040f;
                        if (YawIncrement > -0.040f)
                            YawIncrement -= 0.005f;
                    }
                }
                //Roll += 0.01f;
            }
            if (this.TheModel.PressedKeys.Contains(Keys.Down))
            { // Styrepind tilbage - flyet hæver næsen
                //Pitch -= 0.01f;
                Pitch = 4.7f;
            }
            if (this.TheModel.PressedKeys.Contains(Keys.Up))
            { // Styrepind tilbage - flyet hæver næsen
                //Pitch += 0.01f;
                Pitch = 4.7f;
            }
            if (this.TheModel.PressedKeys.Contains(Keys.A))
            { // Mere fart
                //Formel for acceleration
                if (Speed > -30 && Speed < 0)
                    Speed -= 1.50F;
                if (Speed > -30)
                    Speed -= 1.45F;
                if (Speed > -70)
                    Speed -= 1.40F;
                if (Speed > -110)
                    Speed -= 1.30F;
                if (Speed > -150)
                    Speed -= 1.20F;
                if (Speed > -180)
                    Speed -= 1.10F;
                if (Speed > -250)
                    Speed -= 0.80F;
                if (Speed > -30 && Speed < 0)
                    this.gear = Gears.First;
                if (Speed > -70 && Speed <= -30)
                    this.gear = Gears.Second;
                if (Speed > -110 && Speed <= -70)
                    this.gear = Gears.Third;
                if (Speed > -150 && Speed <= -110)
                    this.gear = Gears.Fourth;
                if (Speed > -180 && Speed <= -150)
                    this.gear = Gears.Fifth;
                if (Speed > -250 && Speed <= -180)
                    this.gear = Gears.Sixth;
            }
            if (!this.TheModel.PressedKeys.Contains(Keys.A))
            { // Vind modstand og motorbrems
                if (Speed < 0.000f)
                    Speed += 0.075F;
                if (Speed > -30 && Speed < 0)
                    this.gear = Gears.First;
                if (Speed > -70 && Speed <= -30)
                    this.gear = Gears.Second;
                if (Speed > -110 && Speed <= -70)
                    this.gear = Gears.Third;
                if (Speed > -150 && Speed <= -110)
                    this.gear = Gears.Fourth;
                if (Speed > -180 && Speed <= -150)
                    this.gear = Gears.Fifth;
                if (Speed > -250 && Speed <= -180)
                    this.gear = Gears.Sixth;
            }
            if (this.TheModel.PressedKeys.Contains(Keys.Z))
            { // Mindre fart
                //Formel for bremselængde, deacceleration
                Speed += 2.00F;
                if (Speed < 0)
                    this.gear = Gears.Reverse;
                if (Speed == 0)
                    this.gear = Gears.Neutral;
                if (Speed > -30 && Speed < 0)
                    this.gear = Gears.First;
                if (Speed > -70 && Speed <= -30)
                    this.gear = Gears.Second;
                if (Speed > -110 && Speed <= -70)
                    this.gear = Gears.Third;
                if (Speed > -150 && Speed <= -110)
                    this.gear = Gears.Fourth;
                if (Speed > -180 && Speed <= -150)
                    this.gear = Gears.Fifth;
                if (Speed > -250 && Speed <= -180)
                    this.gear = Gears.Sixth;
            }
            if (this.TheModel.PressedKeys.Contains(Keys.Space))
            {
                if (Speed < -10 && Speed > -250)
                    Speed += 5;
                if (Speed > -10 && Speed < 1)
                    Speed = 0;
            }
            if (!this.TheModel.PressedKeys.Contains(Keys.Z))
            { // // Vind modstand og motorbrems
                if (Speed > 0.000f)
                    Speed -= 0.015F;
            }
            if (this.TheModel.PressedKeys.Contains(Keys.K))
            { // Toggle kameraposition
                if (kameraPosition == 1)
                    kameraPosition = 2;
                else if (kameraPosition == 2)
                    kameraPosition = 3;
                else
                    kameraPosition = 1;
            }
            if (this.TheModel.PressedKeys.Contains(Keys.Oemplus))
            {
                this.distance = this.distance + 5.0f;
            }
            if (this.TheModel.PressedKeys.Contains(Keys.OemMinus))
            {
                this.distance = this.distance - 5.0f;
            }
            //this.TheModel.Keyboard = Keys.Space;
            // Beregning af næste position
            Vector3 v = new Vector3(0, 0, 0);
            v.TransformCoordinate(Matrix.Translation(new Vector3(0, 0, Speed))
                * Matrix.RotationYawPitchRoll(Yaw, Pitch - (float)(2F * Math.PI / 360F) * 0F, 0));
            Position += v;
            Position = new Vector3(Position.X, 0.001f, Position.Z);
            
            Yaw += YawIncrement;
            Vector3 nyPosition;
            Vector3 nyOp;
            switch (kameraPosition)
            {
                case 1:
                    {
                        this.TheDevice.Transform.View = 
                            Matrix.LookAtLH(new Vector3(0, 10, 150), Position, new Vector3(0, 1, 0));
                        break;
                    }
                case 2:
                    {
                        //* Matrix.Scaling(0.3f, 0.3f, 0.3f) 
                        v = new Vector3(0, 0, 0);
                        v.TransformCoordinate(Matrix.Translation(new Vector3(0, 20, Distance))
                             * Matrix.RotationYawPitchRoll(Yaw, Pitch, 0f));
                        nyPosition = Position + v;
                        this.TheDevice.Transform.View = Matrix.LookAtLH(nyPosition, Position, new Vector3(0, 1, 0));
                        break;
                    }
                case 3:
                    {
                        v = new Vector3(0, 0, 0);
                        v.TransformCoordinate(Matrix.Translation(new Vector3(0, 0, 20f))
                            * Matrix.RotationYawPitchRoll(Yaw, Pitch, Roll));
                        nyPosition = Position + v;
                        nyOp = new Vector3(0, 1, 0);
                        nyOp.TransformCoordinate(Matrix.RotationYawPitchRoll(Yaw, Pitch, Roll));
                        this.TheDevice.Transform.View =
                            Matrix.LookAtLH(Position + new Vector3(0f, 3f, 0f),
                            nyPosition, nyOp);
                        break;
                    }
                default:
                    break;
            }
        }
        #endregion
    }
}
