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;

        // Świat gry

        struct GameSpriteStruct {
            public Texture2D SpriteTexture;
            public Rectangle SpriteRectangle;
            public float X;
            public float Y;
            public float XSpeed;
            public float X;
            public float WidthFactor;
            public float TicksToCrossScreen;
        }

        GameSpriteStruct cheese;
        GameSpriteStruct bread;


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

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

        private

                void setupScreen() {
            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;
        }

        void scaleSprites() {
            cheese.TicksToCrossScreen = 200.0f;
            cheese.WidthFactor = 0.05f;

            cheese.SpriteRectangle.Width =
                    (int) ((displayWidth * cheese.WidthFactor) + 0.5f);
            float aspectRatio =
                    (float) cheese.SpriteTexture.Width / cheese.SpriteTexture.Height;
            cheese.SpriteRectangle.Height =
                    (int) ((cheese.SpriteRectangle.Width / aspectRatio) + 0.5f);
            cheese.X = minDisplayX;
            cheese.Y = minDisplayY;
            cheese.XSpeed = displayWidth / cheese.TicksToCrossScreen;
            cheese.YSpeed = cheese.XSpeed;

            bread.WidthFactor = 0.15f;
            bread.TicksToCrossScreen = 120.0f;

            bread.SpriteRectangle.Width =
                    (int) ((displayWidth * bread.WidthFactor) + 0.5f);
            aspectRatio =
                    (float) bread.SpriteTexture.Width / bread.SpriteTexture.Height;
            bread.SpriteRectangle.Height =
                    (int) ((bread.SpriteRectangle.Width / aspectRatio) + 0.5f);
            bread.X = displayWidth / 2;
            bread.Y = displayHeight / 2;
            bread.XSpeed = displayWidth / bread.TicksToCrossScreen;
            bread.YSpeed = bread.XSpeed;
        }

        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() {
            setupScreen();

            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);

            cheese.SpriteTexture = Content.Load<Texture2D > ("Images/Cheese");
            bread.SpriteTexture = Content.Load<Texture2D > ("Images/Bread");

            scaleSprites();

        }

        /// <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);
            // Pozwala opuścić grę
            if (gamePad1.Buttons.Back == ButtonState.Pressed)
                this.Exit();

            // Ruch chleba

            bread.X = bread.X + (bread.XSpeed * gamePad1.ThumbSticks.Left.X);
            bread.Y = bread.Y - (bread.YSpeed * gamePad1.ThumbSticks.Left.Y);
            bread.SpriteRectangle.X = (int) bread.X;
            bread.SpriteRectangle.Y = (int) bread.Y;

            // Ruch sprajtu sera

            cheese.X = cheese.X + cheese.XSpeed;
            cheese.Y = cheese.Y + cheese.YSpeed;
            cheese.SpriteRectangle.X = (int) (cheese.X + 0.5f);
            cheese.SpriteRectangle.Y = (int) (cheese.Y + 0.5f);

            if (cheese.X + cheese.SpriteRectangle.Width >= maxDisplayX) {
                cheese.XSpeed = cheese.XSpeed * -1;
            }

            if (cheese.X <= minDisplayX) {
                cheese.XSpeed = cheese.XSpeed * -1;
            }

            if (cheese.Y + cheese.SpriteRectangle.Height >= maxDisplayY) {
                cheese.YSpeed = cheese.YSpeed * -1;
            }

            if (cheese.Y <= minDisplayY) {
                cheese.YSpeed = cheese.YSpeed * -1;
            }

            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();

            spriteBatch.Draw(cheese.SpriteTexture, cheese.SpriteRectangle, Color.White);
            spriteBatch.Draw(bread.SpriteTexture, bread.SpriteRectangle, Color.White);

            spriteBatch.End();

            base.Draw(gameTime);
        }
    }
}
