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 MessageBoard {
    /// <summary>
    /// To jest główny typ Twojej gry.
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        // Świat gry

        // czcionka używana do wyświetlania komunikatu
        SpriteFont font;

        // tekstura tła i prostokąt
        Texture2D gameTexture;
        Rectangle spriteRect;

        // wyświetlany komunikat
        // łańcuch początkowo jest pusty
        string messageString = "";

        // klawisze naciśnięte wcześniej (ta tablica początkowo jest pusta)
        Keys[] oldKeys = new Keys[0];

        // wartości opisujące kolory animacji
        byte redIntensity = 0;
        bool redCountingUp = true;
        byte redUpdateLimit = 3;
        byte redUpdateCount = 0;

        byte greenIntensity = 0;
        bool greenCountingUp = true;
        byte greenUpdateLimit = 5;
        byte greenUpdateCount = 0;

        byte blueIntensity = 0;
        bool blueCountingUp = true;
        byte blueUpdateLimit = 7;
        byte blueUpdateCount = 0;

        public Game1() {
            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ć zasoby inne niż graficzne.
        /// related content. Wywołanie metody base.Initialize spowoduje przeszukanie wszystkich komponentów
        /// i ich inicjalizację.
        /// </summary>
        protected override void Initialize() {
            spriteRect = new Rectangle(
                    0, // współrzędna pozioma lewego, górnego rogu
                    0, // współrzędna pionowa lewego, górnego rogu
                    GraphicsDevice.Viewport.Width, // szerokość prostokąta
                    GraphicsDevice.Viewport.Height); // wysokość prostokąta

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

            font = Content.Load<SpriteFont > ("SpriteFont1");
            gameTexture = Content.Load<Texture2D > ("MoodSquares");
        }

        /// <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) {
            // Umożliwia wyjście z gry.
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            KeyboardState keyState = Keyboard.GetState();

            // Umożliwia wyjście z gry po naciśnięciu klawisza Esc.
            if (keyState.IsKeyDown(Keys.Escape)) {
                this.Exit();
            }

            // aktualnie wciśnięte klawisze
            Keys[] pressedKeys;
            pressedKeys = keyState.GetPressedKeys();

            // przeszukuje kolejno wszystkie aktualnie wciśnięte klawisze
            for (int i = 0; i < pressedKeys.Length; i++) {
                // ustawia flagę określającą, że nie znaleziono klawisza
                bool foundIt = false;

                // przeszukuje kolejno wszystkie poprzednio wciśnięte klawisze
                for (int j = 0; j < oldKeys.Length; j++) {
                    if (pressedKeys[i] == oldKeys[j]) {
                        // znaleziono klawisz w tablicy wcześniej wciśniętych klawiszy
                        foundIt = true;
                    }
                }
                if (foundIt == false) {
                    // skoro sterowanie trafiło w to miejsce, nie znaleziono klawisza w tablicy poprzednio wciśniętych klawiszy,
                    // należy zdekodować wartość klawisza, aby wygenerować odpowiedni komunikat
                    string keyString = ""; // ten łańcuch początkowo jest pusty
                    switch (pressedKeys[i]) {
                        case Keys.D0:
                            keyString = "0";
                            break;
                        case Keys.D1:
                            keyString = "1";
                            break;
                        case Keys.D2:
                            keyString = "2";
                            break;
                        case Keys.D3:
                            keyString = "3";
                            break;
                        case Keys.D4:
                            keyString = "4";
                            break;
                        case Keys.D5:
                            keyString = "5";
                            break;
                        case Keys.D6:
                            keyString = "6";
                            break;
                        case Keys.D7:
                            keyString = "7";
                            break;
                        case Keys.D8:
                            keyString = "8";
                            break;
                        case Keys.D9:
                            keyString = "9";
                            break;
                        case Keys.A:
                            keyString = "A";
                            break;
                        case Keys.B:
                            keyString = "B";
                            break;
                        case Keys.C:
                            keyString = "C";
                            break;
                        case Keys.D:
                            keyString = "D";
                            break;
                        case Keys.E:
                            keyString = "E";
                            break;
                        case Keys.F:
                            keyString = "F";
                            break;
                        case Keys.G:
                            keyString = "G";
                            break;
                        case Keys.H:
                            keyString = "H";
                            break;
                        case Keys.I:
                            keyString = "I";
                            break;
                        case Keys.J:
                            keyString = "J";
                            break;
                        case Keys.K:
                            keyString = "K";
                            break;
                        case Keys.L:
                            keyString = "L";
                            break;
                        case Keys.M:
                            keyString = "M";
                            break;
                        case Keys.N:
                            keyString = "N";
                            break;
                        case Keys.O:
                            keyString = "O";
                            break;
                        case Keys.P:
                            keyString = "P";
                            break;
                        case Keys.Q:
                            keyString = "Q";
                            break;
                        case Keys.R:
                            keyString = "R";
                            break;
                        case Keys.S:
                            keyString = "S";
                            break;
                        case Keys.T:
                            keyString = "T";
                            break;
                        case Keys.U:
                            keyString = "U";
                            break;
                        case Keys.W:
                            keyString = "W";
                            break;
                        case Keys.V:
                            keyString = "V";
                            break;
                        case Keys.X:
                            keyString = "X";
                            break;
                        case Keys.Y:
                            keyString = "Y";
                            break;
                        case Keys.Z:
                            keyString = "Z";
                            break;
                        case Keys.Space:
                            keyString = " ";
                            break;
                        case Keys.OemPeriod:
                            keyString = ".";
                            break;
                        case Keys.Enter:
                            keyString = "\n";
                            break;

                    }

                    if (keyState.IsKeyUp(Keys.LeftShift) && keyState.IsKeyUp(Keys.RightShift)) {
                        keyString = keyString.ToLower();
                    }

                    if (pressedKeys[i] == Keys.Back) {
                        if (messageString.Length > 0) {
                            messageString = messageString.Remove(messageString.Length - 1, 1);
                        }
                    }

                    messageString = messageString + keyString;
                }
            }

            // zapamiętuje klawisze na potrzeby następnego wywołania
            oldKeys = pressedKeys;

            // Aktualizuje kolejno wszystkie barwy
            redUpdateCount++;
            if (redUpdateCount == redUpdateLimit) {
                if (redCountingUp) redIntensity++;
                else redIntensity--;
                if (redIntensity == 255) redCountingUp = false;
                if (redIntensity == 0) redCountingUp = true;
                redUpdateCount = 0;
            }

            greenUpdateCount++;
            if (greenUpdateCount == greenUpdateLimit) {
                if (greenCountingUp) greenIntensity++;
                else greenIntensity--;
                if (greenIntensity == 255) greenCountingUp = false;
                if (greenIntensity == 0) greenCountingUp = true;
                greenUpdateCount = 0;
            }

            blueUpdateCount++;
            if (blueUpdateCount == blueUpdateLimit) {
                if (blueCountingUp) blueIntensity++;
                else blueIntensity--;
                if (blueIntensity == 255) blueCountingUp = false;
                if (blueIntensity == 0) blueCountingUp = true;
                blueUpdateCount = 0;
            }

            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) {
            Color backgroundColor;
            backgroundColor = new Color(redIntensity, greenIntensity, blueIntensity);

            string displayString = messageString + "\n" + DateTime.Now.ToLongTimeString();
            Vector2 nowVector = new Vector2(50, 50);
            int layer;

            spriteBatch.Begin();

            spriteBatch.Draw(gameTexture, spriteRect, backgroundColor);

            // Rysuje cień
            Color nowColor = new Color(0, 0, 0, 20);
            for (layer = 0; layer < 10; layer++) {
                spriteBatch.DrawString(font, displayString, nowVector, nowColor);
                nowVector.X++;
                nowVector.Y++;
            }

            // Rysuje podstawę znaków
            nowColor = new Color(190, 190, 190);
            for (layer = 0; layer < 5; layer++) {
                spriteBatch.DrawString(font, displayString, nowVector, nowColor);
                nowVector.X++;
                nowVector.Y++;
            }

            // Rysuje przednią część znaków
            spriteBatch.DrawString(font, displayString, nowVector, Color.White);

            spriteBatch.End();

            base.Draw(gameTime);
        }
    }
}

