#region Using directives

using System;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;

#endregion

namespace PunkMan.Game
{
    /// <summary>
    /// Particle system class. Conatiner for particle objects.
    /// </summary>
    public class ParticleSystem
    {
        /// <summary>
        /// list of particles
        /// </summary>
        private Particle[] particle;
        /// <summary>
        /// Random number generator
        /// </summary>
        private Random randomek;
        /// <summary>
        /// Direct3D device
        /// </summary>
        private Device dev;
        /// <summary>
        /// Texture of particle
        /// </summary>
        private Texture blitka = null;
        /// <summary>
        /// Position of emiter
        /// </summary>
        private Vector3 position;
        /// <summary>
        /// Direction of emition
        /// </summary>
        private Vector3 direction;

        private VertexBuffer vb;


        /// <summary>
        /// postion of emiter
        /// </summary>
        /// <value></value>
        public Vector3 Position
        {
            get { return position; }
            set { position = value; }
        }

        /// <summary>
        /// direciton of emiter
        /// </summary>
        /// <value></value>
        public Vector3 Direction
        {
            get { return direction; }
            set { direction = value; }
        }


        /// <summary>
        /// mighty constructor
        /// </summary>
        /// <param name="dev">D3D device</param>
        /// <param name="count">number of particles</param>
        /// <param name="pos">position of emiter</param>
        /// <param name="dir">direction of emision</param>
        public ParticleSystem(Device dev, int count, Vector3 pos, Vector3 dir)
        {
            randomek = new Random();
            this.dev = dev;
            this.vb = new VertexBuffer(typeof(CustomVertex.PositionNormalTextured), 4, dev,
                Usage.WriteOnly, CustomVertex.PositionNormalTextured.Format, Pool.Default);
            this.vb.Created += new EventHandler(this.OnDeviceReset);
            OnDeviceReset(vb, null);

            this.position = pos;
            this.direction = new Vector3();
            if (dir.X > 0) direction.X = 1;
            else if (dir.X < 0) direction.X = -1;
            if (dir.Y > 0) direction.Y = 1;
            else if (dir.Y < 0) direction.Y = -1;
            if (dir.Z > 0) direction.Z = 1;
            else if (dir.Z < 0) direction.Z = -1;

            blitka = TextureLoader.FromFile(dev, Game.GetDataFilePath(@"artwork\particle_blitka.png"));

            particle = new Particle[count];
            for (int i = 0; i < count; i++)
                particle[i] = NewParticle();
        }

        /// <summary>
        /// Resurection after device reset
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        private void OnDeviceReset(object sender, EventArgs args)
        {
            VertexBuffer vb = (VertexBuffer)sender;
            CustomVertex.PositionNormalTextured[] vert = (CustomVertex.PositionNormalTextured[])vb.Lock(0, 0);
            vert[0].Position = (new Vector3(0, 0, 1));
            vert[0].Tu = 0;
            vert[0].Tv = 1;
            vert[1].Position = (new Vector3(1, 0, 1));
            vert[1].Tu = 1;
            vert[1].Tv = 1;
            vert[2].Position = (new Vector3(0, 1, 1));
            vert[2].Tu = 0;
            vert[2].Tv = 0;
            vert[3].Position = (new Vector3(1, 1, 1));
            vert[3].Tu = 1;
            vert[3].Tv = 0;
            for (int i = 0; i < 4; i++) vert[i].Normal = (new Vector3(0, 0, -1));
            vb.Unlock();
        }

        /// <summary>
        /// create new particle
        /// </summary>
        /// <returns>new created particle</returns>
        private Particle NewParticle()
        {
            float dx = randomek.Next(4) % 2 == 0 ? 1 : -1;//(this.direction.X != 0) ? this.direction.X : 1f;
            float dz = randomek.Next(4) % 2 == 0 ? 1 : -1;//(this.direction.Z != 0) ? this.direction.Z : 1f;
            float x = (randomek.Next(100) * 0.01f) * dx;
            float y = (randomek.Next(100) * 0.01f);
            float z = (randomek.Next(100) * 0.01f) * dz;

            Vector3 position = new Vector3(x, y, z);
            position.Normalize();
            position.Add(this.position);
            
            Vector3 direction = this.direction;
            /*direction.X *= this.direction.X;
            direction.Y *= this.direction.Y;
            direction.Z *= this.direction.Z;*/
            direction.Normalize();


            /*Game.LogFile.WriteLine("New Particle: [{0},{1},{2}], dir[{3},{4},{5}]",
                position.X, position.Y, position.Z,
                direction.X, direction.Y, direction.Z);*/
            float delta = randomek.Next(100) * 0.005f;
            return new Particle(dev, vb, blitka, position, direction, 
                (randomek.Next(100) * 0.1f),delta);
        }

        /// <summary>
        /// Draw whole particle system
        /// </summary>
        public void Render()
        {
            /*Matrix oldWorld = dev.Transform.World;
            dev.Transform.World = Matrix.Translation(position);
            */
            dev.RenderState.AlphaBlendEnable = true;

            for (int i = 0; i < particle.Length; i++)
            {
                Particle p = particle[i];
                if (p != null && !p.Dead)
                {
                    p.Update();
                    p.Render();
                }
                else
                    particle[i] = NewParticle();
            }
            dev.RenderState.AlphaBlendEnable = false;
            //dev.Transform.World = oldWorld;
        }
    }
}
