#region Using directives

using System;
using System.IO;
using System.Collections;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using D3D = Microsoft.DirectX.Direct3D;
using Microsoft.DirectX.DirectInput;
using DI = Microsoft.DirectX.DirectInput;
using System.Windows;
using System.Windows.Forms;
using System.Drawing;
using PunkMan.Shared;

#endregion

namespace PunkMan.Game
{


/// <summary>
/// The main Game class
/// </summary>
    public class Game : Form
    {
        /// <summary>
        /// Show FPS counter in HUD?
        /// </summary>
        private bool fps = false;

        // aby to byla spravna hra, musi to umet godmode ;)
        /// <summary>
        /// Is GOD mode ON?
        /// </summary>
        private static bool god = false;

        /// <summary>
        /// Direct3D device
        /// </summary>
        private D3D.Device display = null;

        /// <summary>
        /// DirectInput keyboard
        /// </summary>
        private DI.Device keyboard = null;

        private VertexBuffer data = null;
        //private Texture tex = null;

        /// <summary>
        /// Current map
        /// </summary>
        private Map map;
        /// <summary>
        /// Player object
        /// </summary>
        private Player punker;

        /// <summary>
        /// The entity manager
        /// </summary>
        private EntityManager entityMgr = null;

        /// <summary>
        /// HUD background
        /// </summary>
        private Bitmap hudTemplate;

        /// <summary>
        /// Sound Effects Engine
        /// </summary>
        private SoundFX sfx = null;

        /// <summary>
        /// MP3 Jukebox
        /// </summary>
        private Jukebox jukebox = null;

        /// <summary>
        /// Top Score Manager
        /// </summary>
        private TopScore topscore = null;


        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="showFps"> show FPS counter in HUD</param>
        public Game(bool showFps)
        {

            fps = showFps;
            ClientSize = new Size(800, 600);
            Text = "Punk Man X1";
            //                    RUM           ABSiNTH        KiLLED        KiLLiNG         BLiTKA
            string[] sfxFiles = { "bozkov.wav", "absinth.wav", "killed.wav", "killing.wav" , "bliti.wav"};
            sfx = new SoundFX(this, GetDataFilePath("sound"), sfxFiles);
            sfx.Volume = -1500;
            jukebox = new Jukebox();
            jukebox.PlaylistFromDirector(GetDataFilePath("music"));
            jukebox.Play();
            jukebox.Volume = -1500;
        }


        /// <summary>
        /// Player sound effect
        /// </summary>
        /// <param name="sfx">what sound effect to play</param>
        public void SFXPlay(SoundFX.SFX sfx)
        {
            this.sfx.Play(sfx);
        }
            
        /// <summary>
        /// Map texture manager
        /// </summary>
        private TextureManager texMgr;

        /// <summary>
        /// Initialize graphics
        /// </summary>
        /// <returns>true if everything OK</returns>
        public bool Init()
        {
            try
            {
                // initialize DI
                keyboard = new DI.Device(SystemGuid.Keyboard);
                keyboard.Acquire();
                

                // initialize D3D
                PresentParameters par = new PresentParameters();

                par.EnableAutoDepthStencil = true;
                par.AutoDepthStencilFormat = DepthFormat.D16;
                par.BackBufferFormat = Format.Unknown;
                par.Windowed = true;
                par.SwapEffect = SwapEffect.Discard;


                display = new D3D.Device(0, D3D.DeviceType.Hardware, this,
                    CreateFlags.SoftwareVertexProcessing, par);
                display.DeviceReset += new EventHandler(OnResetDevice);
                OnCreateDevice(display, null);
                OnResetDevice(display, null);


                InitHUD();


            }
            catch (Exception e) {
                LogFile.WriteLine("Initialize error: ", e.ToString());
                return false; 
            }
            return true;

        }

        /// <summary>
        /// Create data vertex buffer
        /// </summary>
        /// <param name="sender"> the Direct3D device</param>
        /// <param name="args"></param>
        public void OnCreateDevice(object sender, EventArgs args)
        {
            D3D.Device dev = (D3D.Device)sender;

            data = new VertexBuffer(typeof(CustomVertex.PositionNormalTextured), 100, dev, Usage.WriteOnly,
                CustomVertex.PositionNormalTextured.Format, Pool.Default);
            data.Created += new EventHandler(OnCreateData);
            OnCreateData(data, null);


        }

        /// <summary>
        /// Reincarnate after device reset
        /// </summary>
        /// <param name="sender">D3D device</param>
        /// <param name="args"></param>
        public void OnResetDevice(object sender, EventArgs args)
        {
            D3D.Device dev = (D3D.Device)sender;
            dev.RenderState.CullMode = Cull.None;
            dev.RenderState.ZBufferEnable = true;
            dev.RenderState.Lighting = true;
            texMgr = new TextureManager(display, Game.GetDataFilePath("textures"));
        }

        /// <summary>
        /// Common game event handler
        /// </summary>
        /// <param name="sender">who create this event</param>
        /// <param name="x">map position of event</param>
        /// <param name="y">map position of event</param>
        public delegate void GameEventHandler(object sender, int x, int y);

        /// <summary>
        /// after device reset resincarnation
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        public void OnCreateData(object sender, EventArgs args)
        {

            VertexBuffer vb = (VertexBuffer)sender;
            // Create a vertex buffer (100 customervertex)
            CustomVertex.PositionNormalTextured[] verts = (CustomVertex.PositionNormalTextured[])vb.Lock(0, 0); // Lock the buffer (which will return our structs)
            for (int i = 0; i < 50; i++)
            {
                // Fill up our structs
                float theta = (float)(2 * Math.PI * i) / 49;
                verts[2 * i].Position = (new Vector3((float)Math.Sin(theta), -1, (float)Math.Cos(theta)));
                verts[2 * i].Normal = (new Vector3((float)Math.Sin(theta), 0, (float)Math.Cos(theta)));
                verts[2 * i].Tu = ((float)i) / (50 - 1);
                verts[2 * i].Tv = 1.0f;

                verts[2 * i + 1].Position = (new Vector3((float)Math.Sin(theta), 1, (float)Math.Cos(theta)));
                verts[2 * i + 1].Normal = (new Vector3((float)Math.Sin(theta), 0, (float)Math.Cos(theta)));
                verts[2 * i + 1].Tu = ((float)i) / (50 - 1);
                verts[2 * i + 1].Tv = 0.0f;

            }
            // Unlock (and copy) the data
            vb.Unlock();


        }



        /// <summary>
        /// Last position of camer
        /// </summary>
        private Vector3 camPos;
        /// <summary>
        /// Last time of camera update
        /// </summary>
        private float camLastTime = -1;

		/// <summary>
		/// Camera distance in normal mode
		/// </summary>
		private readonly Vector3 camDistanceNormal = new Vector3(0, 15, -10);

		/// <summary>
		/// Camera distance in delirium mode
		/// </summary>
		private readonly Vector3 camDistanceDelirium = new Vector3(0, 10, -7);

        /// <summary>
        /// Setup transform matricies
        /// </summary>
        private void SetupMatrices()
        {
			Vector3 currentWantedPosition = (punker.Delirium) ? camDistanceDelirium : camDistanceNormal;

            if (camLastTime < 0)
            {
                camPos = currentWantedPosition;
                camPos.Add(punker.Position);
            }
            else
            {
                // calculate camera position
                Vector3 wantedPos = currentWantedPosition;
                wantedPos.Add(punker.Position);

                float ratio = (Game.Time() - camLastTime);
                if (ratio > 1) ratio = 1;
                Vector3 ncp = Vector3.Lerp(camPos, wantedPos, ratio);
                camPos = ncp;
            }
            camLastTime = Game.Time();
            Vector3 target = punker.Position;
            
            

            display.Transform.View = Matrix.LookAtLH(camPos,    // position
                                                     target,           // target
                                                     new Vector3(0, 1, 0));          // up

            float aspect = Width / ((Height > 0) ? Height : 1);
            display.Transform.Projection = Matrix.PerspectiveFovLH((float)Math.PI / 4, aspect, 1.0f, 100.0f);

        }


        /// <summary>
        /// Setup lights
        /// </summary>
        private void SetupLights()
        {
            Material mtl = new Material();
            
            Color col = Color.White;
            mtl.Diffuse = col;
            mtl.Ambient = col;
            display.Material = mtl;

            display.RenderState.Ambient = Color.LightGray;
            display.Lights[0].Type = LightType.Directional;
            display.Lights[0].Diffuse = Color.White;
            display.Lights[0].Specular = Color.Yellow;
            display.Lights[0].Position = punker.Position;
            display.Lights[0].Direction = new Vector3(0, -1, 0);
            
            
            display.Lights[0].Enabled = true;
            //display.RenderState.Ambient = Color.FromArgb(0x909090);

        }

        /// <summary>
        /// Setup texture options
        /// </summary>
        private void SetupTexture()
        {
            display.TextureState[0].ColorOperation = TextureOperation.Modulate;
            display.TextureState[0].ColorArgument1 = TextureArgument.TextureColor;
            display.TextureState[0].ColorArgument2 = TextureArgument.Diffuse;
            display.TextureState[0].AlphaOperation = TextureOperation.Disable;
            display.SamplerState[0].MagFilter = TextureFilter.Linear;
            display.SamplerState[0].MinFilter = TextureFilter.Linear;
            display.RenderState.AlphaBlendEnable = false;
        }

        /// <summary>
        /// On paint (form) event handler
        /// </summary>
        /// <param name="args"></param>
        protected override void OnPaint(PaintEventArgs args)
        {
            Render();
        }

        /// <summary>
        /// Full screen mode
        /// </summary>
        private bool fullscreen = false;

        private bool __fullscreen = false;

        /// <summary>
        /// Read keys events
        /// </summary>
        /// <returns>false if player interrupted (pressed Escape)</returns>
        protected bool HandleEvents()
        {
            DI.KeyboardState state = keyboard.GetCurrentKeyboardState();
            Point nextPos = punker.MapPosition;
            if (state[Key.LeftArrow])
            {
                nextPos.X--;
                
                if (map[nextPos] != null && map[nextPos].Walkable)
                    punker.MoveTo(Entity.MoveDirection.Left);
            }
            if (state[Key.RightArrow])
            {
                nextPos = punker.MapPosition;
                nextPos.X++;
                if (map[nextPos] != null && map[nextPos].Walkable)
                    punker.MoveTo(Entity.MoveDirection.Right);
            }
            if (state[Key.UpArrow])
            {
                nextPos = punker.MapPosition;
                nextPos.Y++;
                if (map[nextPos] != null && map[nextPos].Walkable)
                    punker.MoveTo(Entity.MoveDirection.Up);
            }
            if (state[Key.DownArrow])
            {
                nextPos = punker.MapPosition;
                nextPos.Y--;
                if (map[nextPos] != null && map[nextPos].Walkable)
                    punker.MoveTo(Entity.MoveDirection.Down);
            }
            if (state[Key.Escape]) return false;

            if ((state[Key.Return] && state[Key.LeftAlt]) || state[Key.F])
            {
                fullscreen = !fullscreen;
                SwitchFullscreen();

            }

            if (state[Key.N])
            {
                jukebox.Next();
            }
            else if (state[Key.M])
            {
                jukebox.Prev();
            }



            return true;
        }

        private void SwitchFullscreen()
        {
            if (__fullscreen != fullscreen)
            {
                __fullscreen = fullscreen;
                // reset D3D
                PresentParameters par = new PresentParameters();

                par.EnableAutoDepthStencil = true;
                par.AutoDepthStencilFormat = DepthFormat.D16;
                par.BackBufferFormat = Format.Unknown;
                par.Windowed = !fullscreen;
                par.SwapEffect = SwapEffect.Discard;

                Game.LogFile.WriteLine("fullscreen switch");
            }
        }


        /// <summary>
        /// Dispose game resources.
        /// </summary>
        /// <param name="disposing"></param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && display != null)
                display.Dispose();
            display = null;
            base.Dispose(disposing);

        }

        /// <summary>
        /// Vertex buffer for HUD
        /// </summary>
        private VertexBuffer vbHUD = null;
        /// <summary>
        /// Texture for C2H5OH-bar
        /// </summary>
        private Texture hudPointTex = null;

        /// <summary>
        /// Texture for lives
        /// </summary>
        private Texture hudLiveTex = null;

        /// <summary>
        /// HUD font
        /// </summary>
        private D3D.Font HudFont = null;

        /// <summary>
        /// Initialize HUD attributes
        /// </summary>
        private void InitHUD()
        {

            vbHUD = new VertexBuffer(typeof(CustomVertex.PositionNormalTextured), 4, display,
            Usage.WriteOnly, CustomVertex.PositionNormalTextured.Format, Pool.Default);
            vbHUD.Created += new EventHandler(this.OnCreateHUDVertexBuffer);
            OnCreateHUDVertexBuffer(vbHUD, null);
            hudTexx = TextureLoader.FromFile(display, Game.GetDataFilePath(@"artwork\hud.png"));
            hudTemplate = new Bitmap(Game.GetDataFilePath(@"artwork\hud.png"));
            hudPointTex = TextureLoader.FromFile(display, Game.GetDataFilePath(@"artwork\hud_point.png"));
            hudLiveTex = TextureLoader.FromFile(display, Game.GetDataFilePath(@"artwork\hud_live.png"));
            HudFont = new Microsoft.DirectX.Direct3D.Font(display, new System.Drawing.Font("Arial", 12));
        }

        /// <summary>
        /// Create HUD vertex buffer
        /// </summary>
        /// <param name="sender">the vertex buffer</param>
        /// <param name="args"></param>
        private void OnCreateHUDVertexBuffer(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();
        }



        private Texture hudTexx = null;

        /// <summary>
        /// Retrun path to data directory
        /// 
        /// </summary>
        /// <param name="name">repository name</param>
        /// <returns>Path to file / directory</returns>
        public static string GetDataFilePath(string name)
        {
            string exePath = Application.StartupPath;
            // check for data path
            // standard path
            string dataPath1 = exePath + @"\..\data";
            // build path
            string dataPath2 = exePath + @"\..\..\..\data";
            // editor build path
            string dataPath3 = exePath + @"\..\..\..\..\data";
            if (Directory.Exists(dataPath1)) return dataPath1 + "\\" + name;
            if (Directory.Exists(dataPath2)) return dataPath2 + "\\" + name;
            else return dataPath3 + "\\" + name;
        }

        /// <summary>
        /// Last time the FPS counter was update.
        /// </summary>
        private int __lastFpsTime = Environment.TickCount;

        /// <summary>
        /// Delta frames until last FPS measure
        /// </summary>
        private int __frames = 0;

        /// <summary>
        /// Last FPS count
        /// </summary>
        private float __lastFps = 0;

        /// <summary>
        /// Get real FPS count and update FPS counter attributes
        /// </summary>
        /// <returns>frames per seconds</returns>
        private float FPS()
        {
            
            int now = Environment.TickCount;
            if (__lastFpsTime + 5000 < now)
            {
                __lastFps = (float)(now - __lastFpsTime) / __frames;
                __lastFpsTime = now;
                __frames = 0;
            }

            __frames++;
            return (float)Math.Round(__lastFps);

        }

        /// <summary>
        /// Draw HUD
        /// </summary>
        public void RenderHUD()
        {
            //D3D.Font fnt = Microsoft.DirectX.Direct3D.Font(display, new System.Drawing.Font("Arial",12.0f));
            // set 2D camera
            display.Transform.Projection = Matrix.OrthoLH(this.Width, this.Height, 0f, 1f);
            display.Transform.View = Matrix.Identity;
            //display.Transform.World = Matrix.Identity;
            Matrix trans = Matrix.Scaling(this.Width, this.Height, 1);
            trans.Multiply(Matrix.Translation(-Width / 2, -Height / 2, 0));
            display.Transform.World = trans;

            // prepare texture
            //Bitmap sqHud = new Bitmap(hudTemplate, 512, 512);
            //Texture hudTex = new Texture(display, sqHud, 0, Pool.Default);


            //if (hudTexx == null) MessageBox.Show("FUCK");
            display.SetTexture(0, hudTexx);
            display.TextureState[0].ColorOperation = TextureOperation.Modulate;
            display.TextureState[0].ColorArgument1 = TextureArgument.TextureColor;
            display.TextureState[0].ColorArgument2 = TextureArgument.Diffuse;

            display.RenderState.AlphaBlendEnable = true;
            display.RenderState.SourceBlend = Blend.SourceColor;
            display.RenderState.DestinationBlend = Blend.DestinationAlpha;
            display.RenderState.ZBufferEnable = false;
            display.RenderState.Lighting = false;


            // draw HUD background
            display.SetStreamSource(0, vbHUD, 0);
            display.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 2);

            // draw c2h5oh bar
            int c2h5oh = (punker.C2H5OH > 140) ? 140 : punker.C2H5OH;
            float ratio = c2h5oh / 140f;
            int c2h5ohWidth = (int)((ratio * 712 * 712) / 800);
            trans = Matrix.Scaling(c2h5ohWidth, 5 * Height / 600, 1);
            int offX = 63 * Width / 800;
            int offY = 18 * Height / 600;
            trans.Multiply(Matrix.Translation(-Width / 2 + offX, Height / 2 - offY, 0));
            display.Transform.World = trans;
            display.SetTexture(0, hudPointTex);
            display.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 2);

            // draw lives
            trans = Matrix.Scaling(64, 64, 1);
            display.SetTexture(0, hudLiveTex);
            for (int i = 0; i < punker.Lives; i++)
            {
                Matrix trans2 = trans;
                
                trans2.Multiply(Matrix.Translation(-Width / 2 + (i * 64f + 10f), -Height/2 + 10, 0));
                display.Transform.World = trans2;
                display.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 2);
            }

            // score
            HudFont.DrawText(null, "score: "+punker.Score, new Rectangle(10, 64 * Height / 600, 100, 100), 
                DrawTextFormat.Left, Color.LightGreen);

            if (fps)
            {
                HudFont.DrawText(null, "FPS: " + FPS(), new Rectangle(10, (64 * Height / 600) + 20, 100, 100), DrawTextFormat.Left,
                    Color.LightGreen);
            }
            string msg = "BTLS: " + map.PickableItemCount();

            HudFont.DrawText(null, msg, new Rectangle(10, (64 * Height / 600) + 40, 100, 100), DrawTextFormat.Left,
                Color.LightGreen);



        }

        /// <summary>
        /// Setup all and draw whole game screen
        /// </summary>
        public void Render()
        {
            if (display == null) return;
            display.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.Black, 1.0f, 0);

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

            display.RenderState.Lighting = true;
            display.RenderState.ZBufferEnable = true;

            SetupLights();
            SetupMatrices();
            SetupTexture();

            RenderAll();


            display.EndScene();
            display.Present();

        }


        /// <summary>
        /// draw whole game screen
        /// </summary>
        public void RenderAll()
        {

            map.Render(0, 0, map.DataWidth - 1, map.DataHeight - 1);
            punker.Render();
            entityMgr.RenderMonsters();
            entityMgr.RenderBottles();
            entityMgr.RenderEndMark();

            RenderHUD();


        }

        /// <summary>
        /// Load new map
        /// </summary>
        /// <param name="map">new map path</param>
        public void LoadMap(string map)
        {
            this.map = new Map(display, texMgr, map);
            entityMgr = new EntityManager(this, punker, this.map, display);
            punker.Map = this.map;
        }

        /// <summary>
        /// Reset map (on player dead)
        /// </summary>
        public void ResetMap()
        {
            entityMgr.Clear(map.MonsterCount());
            
        }

        /// <summary>
        /// Log file
        /// </summary>
        public static StreamWriter LogFile;
        /// <summary>
        /// is game running?
        /// </summary>
        public static bool running = true;
        /// <summary>
        /// is game paused?
        /// </summary>
        public static bool paused = false;

        /// <summary>
        /// Called after player's death
        /// </summary>
        public void PlayerDeath()
        {
            if (god) return;
            punker.Killed();
            running = running && punker.Alive;
            ResetMap();
        }

        /// <summary>
        /// Called when level finished
        /// </summary>
        public void EndLevel()
        {
            running = false;
        }

        /// <summary>
        /// Pause delta time
        /// </summary>
        private int __pauseStart = Environment.TickCount;

        /// <summary>
        /// Pause Game
        /// </summary>
        public void Pause()
        {
            __pauseStart = Environment.TickCount;
            paused = true;
        }

        /// <summary>
        /// UnPause game
        /// </summary>
        public void UnPause()
        {
            if (!paused) return;
            float delta = (Environment.TickCount - __pauseStart) * 0.001f;
            pauseDelta += delta;
        }

        /// <summary>
        /// Get player score
        /// </summary>
        /// <returns>player's score</returns>
        public int Score()
        {
            return punker.Score;
        }


        /// <summary>
        /// the pause delta
        /// </summary>
        private static float pauseDelta = 0;

        /// <summary>
        /// Get game time (pause orthogonal)
        /// </summary>
        /// <returns>the time</returns>
        public static float Time()
        {
            float now = Environment.TickCount * 0.001f;
            return now - pauseDelta;
            
        }

        /// <summary>
        /// Level end type ;)
        /// </summary>
        public enum LevelEndType
        {
            /// <summary>
            /// Player win
            /// </summary>
            PlayerWin, 
            /// <summary>
            /// Player loose
            /// </summary>
            PlayerLoose, 
            /// <summary>
            /// Playe foregive game
            /// </summary>
            PlayerChicken
        }

        /// <summary>
        /// Play level
        /// </summary>
        /// <param name="map">map path</param>
        /// <param name="playerModel">player model path</param>
        /// <returns>how was the level ended</returns>
        public LevelEndType PlayLevel(string map, string playerModel)
        {
            
            //god = true;
            running = true;
            // load data

            punker = new Player(this, display,playerModel);
            LoadMap(map);


            while (Created && running)
            {
                if (!paused)
                {
                    if (!HandleEvents()) return LevelEndType.PlayerChicken;
                    Render();
                    if (__fullscreen != fullscreen) SwitchFullscreen();
                }
                Application.DoEvents();
            }
            if (punker.Alive) return LevelEndType.PlayerWin;
            else return LevelEndType.PlayerLoose;
        }



        /// <summary>
        /// run game
        /// </summary>
        /// <param name="levelSetDir">level set directory path</param>
        /// <returns>player's score</returns>
        public int RunGame(string levelSetDir)
        {
            ArrayList levelSet = new ArrayList();


            foreach (string fileName in Directory.GetFiles(levelSetDir, "*.xml"))
            {
                levelSet.Add(fileName);
            }

            for (int i = 0; i < levelSet.Count; i++)
            {
                LevelEndType let = PlayLevel((string)levelSet[i],
                    Game.GetDataFilePath(@"models\krocpunk.x"));
                if (let != LevelEndType.PlayerWin) break;
            }

            return punker.Score;
        }

        /// <summary>
        /// Run game (main menu)
        /// </summary>
        public void Run()
        {
            // Game init
            if (!Init())
            {
                MessageBox.Show("Initialization failed. See data/Log.txt for more informations.");
                return;
            }
            topscore = new TopScore(this, display, keyboard);
            
            Show();


            string[] menuItems = { "New Game", "TOP score", "exxiit" };
            Menu menu = new Menu(this, display, keyboard);
            bool end = false;
            while (!end)
            {
                float time = Time();
                while (Time() < time + 0.25) ;
                int choice = menu.Execute(menuItems, true);
                if (choice == -1) end = true;
                else if (choice == 0)
                {
                    int score = RunGame(GetDataFilePath("maps"));
                    if (score > topscore.MinScore())
                    {
                        
                        string name = topscore.ReadName();
                        topscore.Put(name, score);
                    }
                }
                else if (choice == 1)
                {
                    topscore.Show();
                }
                else if (choice == 2)
                {
                    end = true;
                }

                
            }
            


            // game uninit
            keyboard.Unacquire();
            topscore.Store();
            jukebox.Dispose();
            display.Dispose();
            keyboard.Dispose();

        }

        /// <summary>
        /// The BiG MAiN
        /// </summary>
        /// <param name="args">command line args</param>
        public static void Main(string[] args)
        {
            LogFile = new StreamWriter(Game.GetDataFilePath("Log.txt"));
            try
            {
                bool fps = false;
                string mapFile = "";
                if (args.Length > 0)
                {
                    for (int i = 0; i < args.Length; i++)
                    {


                        if (args[i].Equals("-fps")) fps = true;
                        else if (args[i].Equals("-map"))
                        {
                            mapFile = args[i + 1];
                        }
                    }
                }

                if (mapFile.Equals(""))
                    (new Game(fps)).Run();
                else
                {
                    LogFile.WriteLine("Playing level {0}", mapFile);
                    Game game = new Game(fps);
                    if (!game.Init())
                    {
                        MessageBox.Show("Initialization failed");
                        return;
                    }
                    game.topscore = new TopScore(game, game.display, game.keyboard);

                    game.Show();

                    //(game).PlayLevel(GetDataFilePath(@"maps\" + mapFile), GetDataFilePath(@"models\punk.x"));
                }
            }
            catch (Exception e)
            {
                LogFile.WriteLine("Exception: {0}", e.ToString());
                LogFile.WriteLine("Exception stack: {0}", e.StackTrace);
				MessageBox.Show(null, "Exception occures. See Log.txt file for more description on exception.","Something wrong");
            }
            LogFile.Close();
            
            
        }

    }
}