#region Using directives

using System;
using System.Collections;
using System.IO;
using System.Drawing;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using DI = Microsoft.DirectX.DirectInput;

#endregion

namespace PunkMan.Game
{
    /// <summary>
    /// Top Score manager
    /// </summary>
    public class TopScore
    {
        /// <summary>
        /// Top score item
        /// </summary>
        private class TopScoreItem
        {
            /// <summary>
            /// Player name
            /// </summary>
            private string name;
            /// <summary>
            /// Player score
            /// </summary>
            private int score;

            /// <summary>
            /// player name
            /// </summary>
            /// <value>name of player</value>
            public string Name
            {
                get { return name; }
                set { name = value; }
            }

            /// <summary>
            /// player score
            /// </summary>
            /// <value>the score</value>
            public int Score
            {
                get { return score; }
                set { score = value; }
            }
            
            /// <summary>
            /// Constructor
            /// </summary>
            public TopScoreItem()
            {
                name = "PnK";
                score = 100;
            }

            /// <summary>
            /// Constructor
            /// </summary>
            /// <param name="score">new score</param>
            public TopScoreItem(int score)
            {
                name = "PnK";
                this.score = score;
            }

            /// <summary>
            /// Save this item
            /// </summary>
            /// <param name="writer">output writer</param>
            public void Store(BinaryWriter writer)
            {
                writer.Write(name);
                writer.Write(score);
            }

            /// <summary>
            /// Load this item
            /// </summary>
            /// <param name="reader">input reader</param>
            public void Load(BinaryReader reader)
            {
                name = reader.ReadString();
                score = reader.ReadInt32();
            }


        }

        /// <summary>
        /// Top Score Items
        /// </summary>
        ArrayList items = null;

        /// <summary>
        /// Load all items
        /// </summary>
        /// <param name="fileName">file to load items</param>
        private void Load(string fileName)
        {
            if (items == null) items = new ArrayList();
            items.Clear();

            try
            {
                BinaryReader reader = new BinaryReader(new FileStream(fileName, FileMode.Open));

                for (int i = 0; i < 250; i++)
                {
                    TopScoreItem it = new TopScoreItem();
                    it.Load(reader);
                    items.Add(it);
                }
                reader.Close();
            }
            catch (IOException)
            {
                New();
            }
        }

        /// <summary>
        /// Store all items in file
        /// </summary>
        /// <param name="fileName">file to store items</param>
        private void Save(string fileName)
        {
            try
            {
                BinaryWriter writer = new BinaryWriter(new FileStream(fileName, FileMode.CreateNew));
                for (int i = 0; i < items.Count; i++)
                {
                    TopScoreItem it = (TopScoreItem)items[i];
                    it.Store(writer);
                }
                writer.Close();
            }
            catch (IOException)
            {
                return;
            }
        }

        /// <summary>
        /// Store all items into fileName file
        /// </summary>
        public void Store()
        {
            Save(fileName);
        }

        
        /// <summary>
        /// Create new topscore table
        /// </summary>
        private void New()
        {
            if (items == null) items = new ArrayList();
            items.Clear();
            for (int i = 0; i < 10; i++) items.Add(new TopScoreItem((250 - i) * 10));
        }

        /// <summary>
        /// Direct3D device
        /// </summary>
        private Device dev;

        /// <summary>
        /// List font
        /// </summary>
        private Microsoft.DirectX.Direct3D.Font font = null;

        /// <summary>
        /// Number of first row
        /// </summary>
        private int active = 0;

        /// <summary>
        /// Game owner object
        /// </summary>
        private Game owner;

        /// <summary>
        /// DirectInput device
        /// </summary>
        private DI.Device keyboard;

        /// <summary>
        /// File name for score table
        /// </summary>
        private string fileName;

        /// <summary>
        /// Mihgty constructor
        /// </summary>
        /// <param name="owner">game owner object</param>
        /// <param name="dev">D3D device</param>
        /// <param name="keyb">DI device</param>
        public TopScore(Game owner, Device dev, DI.Device keyb)
        {
            this.owner = owner;
            this.dev = dev;
            this.keyboard = keyb;
            font = new Microsoft.DirectX.Direct3D.Font(dev,
                new System.Drawing.Font("Arial", 12));
            New();
            fileName = Game.GetDataFilePath("hall-of-fame.dat");
            if (File.Exists(fileName)) Load(fileName);

        }

        /// <summary>
        /// Put new record
        /// </summary>
        /// <param name="name">player name</param>
        /// <param name="score">score</param>
        public void Put(string name, int score)
        {
            TopScoreItem it = new TopScoreItem();
            it.Name = name;
            it.Score = score;

            for (int i = 0; i < items.Count; i++){
                if (score > ((TopScoreItem)items[i]).Score)
                {
                    items.Insert(i, it);
                    return;
                }
            }

        }


        /// <summary>
        /// Render highscores
        /// </summary>
        private void Render()
        {
            if (dev == null) return;
            if (items == null) return;
            dev.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.Black, 1.0f, 0);

            dev.BeginScene();
            dev.Transform.World = Matrix.Identity;

            dev.RenderState.Lighting = false;
            dev.RenderState.ZBufferEnable = false;

            dev.Transform.World = Matrix.Identity;
            dev.Transform.View = Matrix.Identity;
            dev.Transform.Projection = Matrix.OrthoLH(owner.Width, owner.Height, 0, 1);

            int iii = 0;

            for (int i = active; i < active + 50; i++)
            {
                int ii = i % items.Count;
                if (ii < 0) ii += items.Count;
                TopScoreItem it = (TopScoreItem)items[ii];
                font.DrawText(null, (ii+1) + ": " + it.Name, new Rectangle(10, (20 * owner.Height / 600) + iii * 20 + 20, 100, 100), 
                    DrawTextFormat.Left, Color.LightGreen);
                font.DrawText(null, it.Score + "", new Rectangle(400, (20 * owner.Height / 600) + iii * 20, 100, 100),
                    DrawTextFormat.Right, Color.LightGreen);

                iii++;

            }

            if (capture)
            {
                font.DrawText(null, "Enter Ya Name: " + capString, new Rectangle(0, 0, owner.Width, 100),
                    DrawTextFormat.Center, Color.Red);
            }


            dev.EndScene();
            dev.Present();

        }

        /// <summary>
        /// End of view highscore
        /// </summary>
        private bool end = false;
        /// <summary>
        /// Reading player name
        /// </summary>
        private bool capture = false;
        /// <summary>
        /// Player name position
        /// </summary>
        private int pos = 0;
        /// <summary>
        /// Captured player name
        /// </summary>
        private string capString = "";
        /// <summary>
        /// Handle keyboard input
        /// </summary>
        private void HandleEvents()
        {
            float time = Game.Time();
            while (Game.Time() < time + 0.1f) ;
            DI.KeyboardState state = keyboard.GetCurrentKeyboardState();
            if (capture)
            {
                for (DI.Key k = DI.Key.Q; k <= DI.Key.P; k++)
                    if (state[k])
                    {
                        capString += k.ToString();
                        pos++;
                    }

                for (DI.Key k = DI.Key.A; k <= DI.Key.L; k++)
                    if (state[k])
                    {
                        capString += k.ToString();
                        pos++;
                    }

                for (DI.Key k = DI.Key.Z; k <= DI.Key.M; k++)
                    if (state[k])
                    {
                        capString += k.ToString();
                        pos++;
                    }

                if (state[DI.Key.Return]) 
                    end = true;
                if (state[DI.Key.Back] || state[DI.Key.Delete])
                    if (capString.Length > 0) 
                        capString = capString.Remove(capString.Length - 1, 1);

            }
            else
            {
                if (state[DI.Key.UpArrow]) active--;
                else if (state[DI.Key.DownArrow]) active++;
                else if (state[DI.Key.Escape])
                {
                    end = true;
                }
                if (active < -100) active += items.Count;
                if (active > items.Count + 100) active -= items.Count;
            }
        }

        /// <summary>
        /// Show highscore
        /// </summary>
        public void Show()
        {
            end = false;
            capture = false;
            while (!end)
            {
                HandleEvents();
                Render();
                float time = Game.Time();
                while (time + 0.01 > Game.Time()) ;

            }
        }

        /// <summary>
        /// Get minimal score
        /// </summary>
        /// <returns>minimal score</returns>
        public int MinScore()
        {
            if (items == null || items.Count <= 0) return 0;
            return ((TopScoreItem)items[items.Count - 1]).Score;
        }

        /// <summary>
        /// Get player name
        /// </summary>
        /// <returns>the read string (player name)</returns>
        public string ReadName()
        {
            end = false;
            capString = "";
            capture = true;
            while (!end)
            {
                HandleEvents();
                Render();
                float time = Game.Time();
                while (time + 0.075 > Game.Time()) ;

            }
            capture = false;
            return capString;
        }


    }
}
