using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace BreadAndCheese {
    /// <summary>
    /// To jest główny typ Twojej gry.
    /// </summary>
    public class BreadAndCheeseGame : Microsoft.Xna.Framework.Game {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        struct BatSpriteStruct {
            private Texture2D spriteTexture;
            private Rectangle spriteRectangle;
            private float x;
            private float y;
            private float xSpeed;
            private float ySpeed;

            public void LoadTexture(Texture2D inSpriteTexture) {
                spriteTexture = inSpriteTexture;
            }

            public void StartGame(
                    float widthFactor,
                    float ticksToCrossScreen,
                    float inDisplayWidth,
                    float initialX,
                    float initialY) {
                spriteRectangle.Width = (int) ((inDisplayWidth * widthFactor) + 0.5f);
                float aspectRatio =
                        (float) spriteTexture.Width / spriteTexture.Height;
                spriteRectangle.Height =
                        (int) ((spriteRectangle.Width / aspectRatio) + 0.5f);
                x = initialX;
                y = initialY;
                xSpeed = inDisplayWidth / ticksToCrossScreen;
                ySpeed = xSpeed;
            }

            public void Draw(SpriteBatch spriteBatch) {
                spriteBatch.Draw(spriteTexture, spriteRectangle, Color.White);
            }

            public void Update() {
                GamePadState gamePad1 = GamePad.GetState(PlayerIndex.One);
                x = x + (xSpeed * gamePad1.ThumbSticks.Left.X);
                y = y - (ySpeed * gamePad1.ThumbSticks.Left.Y);
                spriteRectangle.X = (int) x;
                spriteRectangle.Y = (int) y;
            }
        }

        // Świat gry
        BatSpriteStruct BreadBat;

#region Wartości reprezentujące wymiary ekranu

        float displayWidth;
        float displayHeight;
        float overScanPercentage = 10.0f;
        float minDisplayX;
        float maxDisplayX;
        float minDisplayY;
        float maxDisplayY;

        private void setScreenSizes() {
            displayWidth = graphics.GraphicsDevice.Viewport.Width;
            displayHeight = graphics.GraphicsDevice.Viewport.Height;
            float xOverscanMargin = getPercentage(overScanPercentage, displayWidth) / 2.0f;
            float yOverscanMargin = getPercentage(overScanPercentage, displayHeight) / 2.0f;

            minDisplayX = xOverscanMargin;
            minDisplayY = yOverscanMargin;

            maxDisplayX = displayWidth - xOverscanMargin;
            maxDisplayY = displayHeight - yOverscanMargin;
        }


#endregion

#region Metody pomocnicze

        /// <summary>
        /// Oblicza wartości procentowe
        /// </summary>
        /// <param name="percentage">procent, który ma zostać wyznaczony</param>
        /// <param name="inputValue">wartość do przeliczenia</param>
        /// <returns>wartość wynikowa</returns>

        float getPercentage(float percentage, float inputValue) {
            return (inputValue * percentage) / 100;
        }

#endregion


        public BreadAndCheeseGame() {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        /// <summary>
        /// Umożliwia ewentualną inicjalizację przed uruchomieniem właściwej gry.
        /// W tym miejscu można odnaleźć wszystkie wymagane zasoby i załadować treści
        /// related content. Wywołanie metody base.Initialize spowoduje przeszukanie wszystkich komponentów
        /// i ich inicjalizację.
        /// </summary>
        protected override void Initialize() {
            setScreenSizes();

            base.Initialize();
        }

        /// <summary>
        /// Metoda LoadContent jest wywoływana tylko raz dla całej gry i jako taka jest właściwym miejscem
        /// dla kodu ładującego treść.
        /// </summary>
        protected override void LoadContent() {
            // Tworzy nowy obiekt klasy SpriteBatch, którego można używać do rysowania tekstur.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            BreadBat.LoadTexture(Content.Load<Texture2D > ("Images/Bread"));
            BreadBat.StartGame(0.1f, 150, displayWidth, displayWidth / 2, displayHeight / 2);
        }

        /// <summary>
        /// Metoda UnloadContent jest wywoływana tylko raz dla całej gry i jako taka jest właściwym miejscem
        /// dla kodu usuwającego całą treść z pamięci.
        /// </summary>
        protected override void UnloadContent() {
            // TODO: Należy usunąć całą treść, którą nie zarządza ContentManager.
        }

        /// <summary>
        /// Umożliwia grze wykonywanie logiki związanej z aktualizacją świata gry,
        /// sprawdzaniem kolizji, pobieraniem danych wejściowych czy odtwarzaniem dźwięków.
        /// </summary>
        /// <param name="gameTime">Udostępnia wartości reprezentujące bieżący czas.</param>
        protected override void Update(GameTime gameTime) {
            GamePadState gamePad1 = GamePad.GetState(PlayerIndex.One);

            if (gamePad1.Buttons.Back == ButtonState.Pressed)
                this.Exit();

            BreadBat.Update();

            base.Update(gameTime);
        }

        /// <summary>
        /// Ta metoda jest wywoływana w momencie, w którym gra musi narysować swój świat.
        /// </summary>
        /// <param name="gameTime">Udostępnia wartości reprezentujące bieżący czas.</param>
        protected override void Draw(GameTime gameTime) {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            spriteBatch.Begin();

            BreadBat.Draw(spriteBatch);

            spriteBatch.End();

            base.Draw(gameTime);
        }
    }
}
