using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;

using Sunlight.DirectX.Graphics;
using Sunlight.DirectX.Input;
using Sunlight.DirectX.SoundMusic;

namespace DXTest
{
    /// <summary>
    /// Main form class for DXTest.
    /// </summary>
    public class Form1 : Sunlight.IdleForm
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.Container components = null;

        /// <summary>
        /// <c>Graphics.Direct3D</c> object, used by the device
        /// </summary>
        private Direct3D d3d = new Direct3D();
        /// <summary>
        /// <c>Graphics.Device</c> object, which performs all display actions
        /// </summary>
        private Device device;
        /// <summary>
        /// <c>Input.DirectInput</c> object, to handle all user input (mouse, keyboard, joystick etc.).
        /// </summary>
        protected DirectInput di = new DirectInput();
        /// <summary>
        /// <c>Graphics.SpriteManager</c> object, to handle sprites.
        /// </summary>
        protected SpriteManager manager = new SpriteManager();
        /// <summary>
        /// <c>SoundMusic.DirectMusic</c> object, to handle sound effects and background music.
        /// </summary>
        protected DirectMusic dm = new DirectMusic();
        /// <summary>
        /// Background texture object.
        /// </summary>
        private Texture texBackground = new Texture();
        /// <summary>
        /// Sprite texture object.
        /// </summary>
        private Texture texSprites = new Texture();
        /// <summary>
        /// Background sprite.
        /// </summary>
        private Sprite spriteBackground;
        /// <summary>
        /// Fixed sprite.
        /// </summary>
        private Sprite spriteFixed;
        /// <summary>
        /// Moving sprite.
        /// </summary>
        private Sprite spriteMoving;
        /// <summary>
        /// Player sprite.
        /// </summary>
        private Sprite spritePlayer;
        /// <summary>
        /// Background music object.
        /// </summary>
        private BackgroundSound soundMusic = new BackgroundSound();
        /// <summary>
        /// x offset of the moving sprite.
        /// </summary>
        private int xAutomaticSprite = 0;
        /// <summary>
        /// x offset of the player sprite.
        /// </summary>
        private int xPlayer = 0;
        /// <summary>
        /// True when the player has pressed the 'Left' key, or moved left with the joystick.
        /// </summary>
        private bool bLeft;
        /// <summary>
        /// True when the player has pressed the 'Right' key, or moved right with the joystick.
        /// </summary>
        private bool bRight;
        /// <summary>
        /// True when the player has pressed the 'Quit' key.
        /// </summary>
        private bool bQuit;
        /// <summary>
        /// True when the player has pressed the 'Pause' key.
        /// </summary>
        private bool bPaused;
        /// <summary>
        /// True when the player has pressed the 'Help' key.
        /// </summary>
        private bool bShowHelp;
        /// <summary>
        /// True when the player has pressed the 'Mode Switch' key.
        /// </summary>
        private bool bModeSwitch;

        /// <summary>
        /// Form1 constructor.
        /// </summary>
        public Form1()
        {
            //
            // Required for Windows Form Designer support
            //
            InitializeComponent();

            //
            // TODO: Add any constructor code after InitializeComponent call
            //
            Init += new EventHandler(OnInit);
            Idle += new EventHandler(OnIdle);
        }

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose( bool disposing )
        {
            if( disposing )
            {
                if (components != null) 
                {
                    components.Dispose();
                }
            }
            base.Dispose( disposing );
        }

        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            // 
            // Form1
            // 
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
            this.ClientSize = new System.Drawing.Size(640, 480);
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
            this.Name = "Form1";
            this.Text = "DXTest";

        }
        #endregion

        /// <summary>
        /// Called when DirectX is to be initialised.
        /// </summary>
        /// <param name="sender">Object that sent this event.</param>
        /// <param name="e">Parameters for this event.</param>
        protected void OnInit(object sender, EventArgs e)
        {
            // Initialise the DirectX Graphics device.
            device = new Device(d3d);
            device.ParentWindow = this;
            device.Windowed = true;

            // Initialise the DirectInput object, including the action map.
            di.ActionMapName = "DXTest";
            di.AppID = new Guid("{CA761232-ED42-11CE-BACD-00AA0057B223}");
            di.Genre = Genres.ARCADE_SIDE2SIDE;
            di.Actions.Add(new ActionMap.Entry(0, Actions.AXIS_ARCADES_LATERAL, "Left/Right"));
            di.Actions.Add(new ActionMap.Entry(1, Actions.KEYBOARD_LEFT, "Left"));
            di.Actions.Add(new ActionMap.Entry(2, Actions.KEYBOARD_RIGHT, "Right"));
            di.Actions.Add(new ActionMap.Entry(3, Actions.KEYBOARD_ESCAPE, "Quit"));
            di.Actions.Add(new ActionMap.Entry(4, Actions.KEYBOARD_P, "Pause"));
            di.Actions.Add(new ActionMap.Entry(5, Actions.KEYBOARD_F1, "Help"));
            di.Actions.Add(new ActionMap.Entry(6, Actions.KEYBOARD_S, "Full Screen On/Off"));
            di.Action += new DirectInput.ActionEventHandler(OnInputAction);
            di.ParentWindow = this;
            di.Direct3DDevice = device;

            // Initialise the DirectMusic object.
            dm.ParentWindow = this;
            dm.Create();

            // Load the background music. This has an event handler to allow it to repeat.
            soundMusic.DirectMusicObject = dm;
            soundMusic.Filename = "passport.mid";
            soundMusic.Finished += new EventHandler(OnMusicFinished);
            
            // Initialise the sprite manager.
            manager.DeviceObject = device;

            // Initialise the textures.
            texBackground.DeviceObject = device;
            texBackground.Filename = "a.png";
            texSprites.DeviceObject = device;
            texSprites.Filename = "sprites.png";
    
            // Build the sprites.
            spriteBackground = new Sprite(manager, new Rectangle(0, 0, 640, 480), texBackground, new Point(0, 0));
            spriteFixed = new Sprite(manager, new Rectangle(288, 208, 64, 64), texSprites, new Point(128, 0));
            spriteMoving = new Sprite(manager, new Rectangle(288, 100, 64, 64), texSprites, new Point(0, 0));
            spritePlayer = new Sprite(manager, new Rectangle(288, 150, 64, 64), texSprites, new Point(64, 0));

            device.Create();            

            di.Configure();

            soundMusic.Play();
        }

        /// <summary>
        /// Called when the music has reached the end.
        /// </summary>
        /// <param name="sender">Object that sent this event.</param>
        /// <param name="e">Parameters for this event.</param>
        private void OnMusicFinished(object sender, System.EventArgs e)
        {
            // Continuous repeat
            soundMusic.Play();
        }

        /// <summary>
        /// Called when the application is idle (i.e. no messages are being processed).
        /// Contains the main application logic.
        /// </summary>
        /// <param name="sender">Object that sent this event.</param>
        /// <param name="e">Parameters for this event.</param>
        protected void OnIdle(object sender, EventArgs e)
        {
            if (!device.IsCreated || device.Paused)
                return;

            di.Check();
            if (bQuit)
            {
                Close();
                return;
            }

            if (bModeSwitch)
            {
                device.Windowed = !device.Windowed;
                device.Reset();
                bModeSwitch = false;
            }

            if (bShowHelp)
            {
                bShowHelp = false;
                di.Display();
            }

            if (!bPaused)
            {
                // Move a sprite around with the input.
                if (bLeft)
                    xPlayer--;
                if (bRight)
                    xPlayer++;

                spritePlayer.Left = 288 + xPlayer;

                // Move a sprite around automatically.
                xAutomaticSprite++;
                if (xAutomaticSprite > 100)
                    xAutomaticSprite = -100;

                spriteMoving.Left = 288 + xAutomaticSprite;
            }

            spriteBackground.Draw();
            spriteFixed.Draw();
            spriteMoving.Draw();
            spritePlayer.Draw();

            device.BeginScene();
            manager.FinishDraw();
            device.EndScene();
            device.Flip();
        }

        /// <summary>
        /// Called when an input event occurs.
        /// </summary>
        /// <param name="sender">Object that sent this event.</param>
        /// <param name="e">Parameters for this event.</param>
        void OnInputAction(DirectInput sender, DirectInputEventArgs e)
        {
            switch (e.ID)
            {
            case 0:
                if (e.AxisPosition < -20)
                {
                    bLeft = true;
                    bRight = false;
                }
                else if (e.AxisPosition > 20)
                {
                    bRight = true;
                    bLeft = false;
                }
                else
                {
                    bLeft = bRight = false;
                }
                break;

            case 1:
                bLeft = e.ButtonPressed;
                break;

            case 2:
                bRight = e.ButtonPressed;
                break;

            case 3:
                if (e.ButtonPressed)
                    bQuit = true;
                break;

            case 4:
                if (e.ButtonPressed)
                    bPaused = !bPaused;
                break;

            case 5:
                if (e.ButtonPressed)
                    bShowHelp = true;
                break;

            case 6:
                if (e.ButtonPressed)
                    bModeSwitch = true;
                break;

            default:
                break;
            }
        }
        
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main() 
        {
            Form1 form = new Form1();

            form.Run();
        }
    }
}