using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace Bouncer
{
    public partial class Form1 : Form
    {
        // <summary>
        /// Изображение, содержащее сыр
        /// </summary>
        private Image cheeseImage = null;

        /// <summary>
        /// Изображение, содержащее батон хлеба
        /// </summary>
        private Image breadImage = null;

        /// <summary>
        /// Изображение, содержащее помидор
        /// </summary>
        private Image tomatoImage = null;

        /// <summary>
        /// Изображение, содержащее ветчину
        /// </summary>
        private Image bonusHamImage = null;

        /// <summary>
        /// Изображение, содержащее фон игры.
        /// </summary>
        private Image backgroundImage = null;


        /// <summary>
        ///  Координата X для рисования сыра
        /// </summary>
        // private int cx = 0;   // старая версия

        /// <summary>
        /// Координата Y для рисования сыра
        /// </summary>
        // private int cy = 0;   // старая версия

        /// <summary>
        /// Скорость движения сыра по горизонтали
        /// </summary>
        private int xSpeed = 1;

        /// <summary>
        /// Скорость движения сыра по вертикали
        /// </summary>
        private int ySpeed = 1;

        /// <summary>
        /// Направление движения по оси X
        /// </summary>
        private bool goingRight = true;

        /// <summary>
        /// Направление движения по оси Y
        /// </summary>
        private bool goingDown = true;

        /// <summary>
        ///  Координата X для батона хлеба
        /// </summary>
        // private int bx = 0;  // старая версия

        /// <summary>
        /// Координата Y для батона хлеба
        /// </summary>
        // private int by = 0;  // старая версия

        /// <summary>
        /// Позиция и ограничивающий прямоугольник для сыра
        /// </summary>
        private Rectangle cheeseRectangle;

        /// <summary>
        /// Позиция и ограничивающий прямоугольник для батона хлеба
        /// </summary>
        private Rectangle breadRectangle;

        /// <summary>
        /// Позиция и ограничивающий прямоугольник для ветчины
        /// </summary>
        private Rectangle bonusHamRectangle;

        /// <summary>
        ///  Позиция и состояние помидора
        /// </summary>
        struct tomato
        {
            public Rectangle rectangle;
            public bool visible;
        }

        /// <summary>
        /// Расстояние межды помидорами. 
        /// Устанавливаем один раз для игры
        /// </summary>
        private int tomatoSpacing = 4;

        /// <summary>
        /// Высота, на которой рисуется помидор
        /// Высота может меняться в процессе игры
        /// Начинаем с верхней части экрана
        /// </summary>
        private int tomatoDrawHeight = 20;

        /// <summary>
        /// Начальная высота, на которой располагаются помидоры
        /// </summary>
        private int tomatoLevelStartHeight = 20;

        /// <summary>
        /// Число помидоров на экране.
        /// Устанавливается при старте игры 
        /// методом initialiseTomatoes.
        /// </summary>
        private int noOfTomatoes;

        /// <summary>
        /// Позиции всех помидоров на экране
        /// </summary>
        private tomato[] tomatoes;

        /// <summary>
        /// Шрифт для вывода счета
        /// </summary>
        private Font messageFont = null;

        /// <summary>
        /// Прямоугольник, в котором будет отображаться счет игры
        /// </summary>
        private Rectangle messageRectangle;

        /// <summary>
        /// Высота панели для счета.
        /// </summary>
        private int scoreHeight = 15;

        /// <summary>
        /// Кисть, используемая для сообщений
        /// </summary>
        private SolidBrush messageBrush;

        /// <summary>
        /// Строка для вывода сообщений
        /// </summary>
        private string messageString = "Нажмите на Старт для начала игры";

        /// <summary>
        /// Счет в игре
        /// </summary>
        private int scoreValue = 0;

        /// <summary>
        /// Звук, воспроизводимый при столкновении с батоном хлеба
        /// </summary>
        private Sound batHitSound;

        /// <summary>
        /// Звук, воспроизводимый при столкновении с помидором
        /// </summary>
        private Sound tomatoHitSound;

        /// <summary>
        /// Звук, воспроизводимый при столкновении с ветчиной
        /// </summary>
        private Sound bonusHamSound;


        /// <summary>
        /// True, если игра запущена на экране.
        /// </summary>
        private bool gameLive = false;

        /// <summary>
        /// Число оставшихся жизней.
        /// </summary>
        private int livesLeft;

        /// <summary>
        /// Число жизней, доступных для игрока.
        /// </summary>
        private int startLives = 3;

        /// <summary>
        /// Лучший результат, достигнутый в игре
        /// </summary>
        private int highScoreValue = 100;

        /// <summary>
        /// Максимально допустимая скорость в игре
        /// </summary>
        private int maxSpeed = 5;

        /// <summary>
        /// Тестирование программы. Батон автоматически отслеживает движение сыра 
        /// </summary>
        private bool testingGame = true;

        /// <summary>
        /// Форма для ввода имени игрока с лучшим результатом.
        /// </summary>
        private HighScore highScore;

        /// <summary>
        /// Имя игрока, достигшего лучшего результата.
        /// </summary>
        private string highScorePlayer = "Rob";

        /// <summary>
        /// Папка, в которой находится программа.
        /// Используется как место для хранения настроек игры.
        /// </summary>
        private string applicationDirectory;

        /// <summary>
        /// Имя файла для хранения лучших результатов.
        /// </summary>
        private string highScoreFile = "highscore.bin";

        /// <summary>
        /// Маска для белого цвета, который будет считаться прозрачным
        /// </summary>
        private System.Drawing.Imaging.ImageAttributes transparentWhite;



        public Form1()
        {
            InitializeComponent();

            // Получим ссылку на сборку
            System.Reflection.Assembly execAssem =
                System.Reflection.Assembly.GetExecutingAssembly();

            // Получим имя файла программы из текущей сборки
            string appFilePath =
                execAssem.GetModules()[0].FullyQualifiedName;
            // Выделяем из полного пути имени файла только путь к файлу
            applicationDirectory =
                System.IO.Path.GetDirectoryName(appFilePath);
            // Обязательно должен быть разделитель в конце пути
            if (!applicationDirectory.EndsWith(@"\"))
            {
                applicationDirectory += @"\";
            }


            // Получим доступ к картинке с сыром
            cheeseImage = new System.Drawing.Bitmap(
                execAssem.GetManifestResourceStream(@"Bouncer.cheese.gif")
            );

            // Получаем изображение батона хлеба
            breadImage = new System.Drawing.Bitmap(
                execAssem.GetManifestResourceStream(@"Bouncer.bread.gif")
            );
           
            // Получим координаты и ограничивающие прямоугольники
            cheeseRectangle = new Rectangle(0, 0, cheeseImage.Width, cheeseImage.Height);
            
            //***Старая версия
            //breadRectangle = new Rectangle(0, 0,  breadImage.Width, breadImage.Height);
            //****************************************************************************
            // Поместим батон хлеба в нижнюю часть экрана по центру
            breadRectangle = new Rectangle(
                    (this.ClientSize.Width - breadImage.Width) / 2,
                    this.ClientSize.Height - breadImage.Height,
                    breadImage.Width,
                    breadImage.Height);

            // Получаем изображение помидора
            tomatoImage = new System.Drawing.Bitmap(
                execAssem.GetManifestResourceStream(@"Bouncer.tomato.gif")
                );

            // Получим изображение ветчины
            bonusHamImage = new System.Drawing.Bitmap(
                execAssem.GetManifestResourceStream(@"Bouncer.ham.gif")
                );

            // Получим изображение фона игры
            backgroundImage = new System.Drawing.Bitmap(
                execAssem.GetManifestResourceStream(@"Bouncer.tablecloth.gif")
                ); 

            // Инициализируем массив помидоров и прямоугольников
            initialiseTomatoes();

            // Располагаем помидоры в верхней части экрана
            placeTomatoes();

            // Создадим шрифт для показа набранных очков
            messageFont = new Font(FontFamily.GenericSansSerif,
            10, FontStyle.Regular);

            // Устанавливаем размеры прямоугольника для счета
            messageRectangle = new Rectangle(0, 0, this.ClientSize.Width, scoreHeight);

            // Выбираем красную кисть
            messageBrush = new SolidBrush(Color.Red);

            // Получим звук при столкновении с батоном хлеба
            batHitSound =
                    new Sound(execAssem.GetManifestResourceStream(@"Bouncer.click.wav"));

            // Получим звук при столкновении с помидором
            tomatoHitSound =
                new Sound(execAssem.GetManifestResourceStream(@"Bouncer.burp.wav"));

            // Получим изображение ветчины
			bonusHamImage = new System.Drawing.Bitmap(
				execAssem.GetManifestResourceStream(@"Bouncer.ham.gif")
				);

			// Создадим прямоугольник для ветчины
			bonusHamRectangle = new Rectangle( 0, 0,
				bonusHamImage.Width,bonusHamImage.Height );

            // Получим звук при столкновении с ветчиной
            bonusHamSound =
                new Sound(execAssem.GetManifestResourceStream(@"Bouncer.pig.wav"));

            // Генерируем новое случайное число
            randomNumbers = new Random();

            // Создаем форму для лучших результатов
            highScore = new HighScore(this);

            //  Задаем белую маску.
            transparentWhite = new System.Drawing.Imaging.ImageAttributes();
            transparentWhite.SetColorKey(Color.White, Color.White);



            // Включаем таймер
            timer1.Enabled = true;

        }


        private void updatePositions()
        {
            // Движение кусочка сыра

            if (goingRight)
            {
                // Старая версия
                // cx+=xSpeed;

                cheeseRectangle.X += xSpeed;
            }
            else
            {
                //cx-=xSpeed;                //старая версия
                cheeseRectangle.X -= xSpeed;
            }
            //***Старая версия***
            //if ((cx + cheeseImage.Width) >= this.Width) // старая версия
            //{
            //    goingRight = false;
            //}

            //if (cx <= 0)
            //{
            //    goingRight = true;
            //}

            //if (goingDown)
            //{
            //    cy+=ySpeed;
            //}
            //else
            //{
            //    cy-=ySpeed;
            //}

            //if ((cy + cheeseImage.Height) >= this.Height)
            //{
            //    goingDown = false;
            //}

            //if (cy <= 0)
            //{
            //    goingDown = true;
            //}
            //***********************

            if ((cheeseRectangle.X + cheeseImage.Width) >= this.Width)
            {
                goingRight = false;
            }

            if (cheeseRectangle.X <= 0)
            {
                goingRight = true;
            }
          
            if (goingDown)
            {
                cheeseRectangle.Y += ySpeed;
            }
            else
            {
                cheeseRectangle.Y -= ySpeed;
            }
                       
            
            if ((cheeseRectangle.Y + cheeseImage.Height) >= this.Height)
            {
                // сыр достиг нижней части экрана
                loseLife();
                goingDown = false;
            }

            if (cheeseRectangle.Y <= 0)
            {
                goingDown = true;
            }

            if (!gameLive)
            {
                return;
            }

            // Управление батоном

            if (keyArgs != null)
            {
                switch (keyArgs.KeyCode)
                {
                        //***Старая версия***
                        //case Keys.Up:
                        //    by -= ySpeed;
                        //    break;
                        //case Keys.Down:
                        //    by += ySpeed;
                        //    break;
                        //case Keys.Left:
                        //    bx -= xSpeed;
                        //    break;
                        //case Keys.Right:
                        //    bx += xSpeed;
                        //    break;
                        //****************
                   
                        case Keys.Up:
                            breadRectangle.Y -= ySpeed;
                            break;
                        case Keys.Down:
                            breadRectangle.Y += ySpeed;
                            break;
                        case Keys.Left:
                            breadRectangle.X -= xSpeed;
                            break;
                        case Keys.Right:
                            breadRectangle.X += xSpeed;
                            break;
                }

            }

            //if (testingGame)
            //{
            //    breadRectangle.X = cheeseRectangle.X;
            //    breadRectangle.Y = ClientSize.Height - breadRectangle.Height;
            //}


            // Проверка на столкновение
            //if (cheeseRectangle.IntersectsWith(breadRectangle))
            //{
            //    goingDown = !goingDown;
            //}

            if (goingDown)
            {
                // если сыр движется вниз
                if (cheeseRectangle.IntersectsWith(breadRectangle))
                {
                    // столкновение
                    // воспроизводим удар
                    batHitSound.Play();

                    bool rightIn = breadRectangle.Contains(
                       cheeseRectangle.Right,
                       cheeseRectangle.Bottom);
                    bool leftIn = breadRectangle.Contains(
                       cheeseRectangle.Left,
                       cheeseRectangle.Bottom);

                    // способ отражения
                    if (rightIn & leftIn)
                    {
                        // отражаемся вверх
                        goingDown = false;
                    }
                    else
                    {
                        // отражаемся вверх
                        goingDown = false;
                        // в зависимости от вида столкновений
                        if (rightIn)
                        {
                            goingRight = false;
                        }
                        if (leftIn)
                        {
                            goingRight = true;
                        }
                    }
                }

                // Уничтожаем помидоры при столкновении с сыром
                for (int i = 0; i < tomatoes.Length; i++)
                {
                    if (!tomatoes[i].visible)
                    {
                        continue;
                    }
                    if (cheeseRectangle.IntersectsWith(tomatoes[i].rectangle))
                    {
                        // воспроизводим звук столкновения сыра с помидором
                        tomatoHitSound.Play();

                        // прячем томат
                        tomatoes[i].visible = false;
                        // отражаемся вниз
                        goingDown = true;

                        // обновляем счет
                        scoreValue = scoreValue + 10;
                        messageString = "Счет: " + scoreValue;

                        // Активизируем ветчину
                        startHam();

                        // только удаляем помидор за раз
                        break;
                    }
                }

              }


        }

        private void changeSpeed(int change)
        {
            xSpeed += change;
            ySpeed += change;
        }

        /// <summary>
        /// Вызывается один раз для установки всех помидоров
        /// </summary>
        private void initialiseTomatoes()
        {
            noOfTomatoes = (this.ClientSize.Width - tomatoSpacing) /
               (tomatoImage.Width + tomatoSpacing);

            // создаем массив, содержащий позицию помидоров
            tomatoes = new tomato[noOfTomatoes];

            // Координата x каждого помидора
            int tomatoX = tomatoSpacing / 2;

            for (int i = 0; i < tomatoes.Length; i++)
            {
                tomatoes[i].rectangle =
                   new Rectangle(tomatoX, tomatoDrawHeight,
                   tomatoImage.Width, tomatoImage.Height);
                tomatoX = tomatoX + tomatoImage.Width + tomatoSpacing;
            }
        }

        /// <summary>
        /// Вызывается для создания ряда помидоров.
        /// </summary>
        private void placeTomatoes()
        {
            for (int i = 0; i < tomatoes.Length; i++)
            {
                tomatoes[i].rectangle.Y = tomatoDrawHeight;
                tomatoes[i].visible = true;
            }
        }

        private void startGame()
        {
            // Устанавливаем число жизней, счет и сообщения
            livesLeft = startLives;
            scoreValue = 0;
            messageString = "Счет: 0 Жизнь: " + livesLeft;

            // Располагаем помидоры наверху экрана
            tomatoDrawHeight = tomatoLevelStartHeight;
            placeTomatoes();

            // Поместим батон в центре экрана
            breadRectangle.X = (this.ClientSize.Width - breadRectangle.Width) / 2;
            breadRectangle.Y = this.ClientSize.Height / 2;

            // Поместим сыр над батоном в центре экрана
            cheeseRectangle.X = (this.ClientSize.Width - cheeseRectangle.Width) / 2;
            cheeseRectangle.Y = breadRectangle.Y - cheeseRectangle.Height;

            // Установим начальную скорость
            xSpeed = 1;
            ySpeed = 1;

            // Установим флаг, позволяющий начать игру
            gameLive = true;
        }

        private void loseLife()
        {
            if (!gameLive)
            {
                return;
            }
            // Потеряли еще одну жизнь 
            livesLeft--;
            if (livesLeft > 0)
            {
                // обновим сообщение на экране
                messageString = "Счет: " + scoreValue + "  Жизнь: " + livesLeft;
            }
            else
            {
                // Останавливаем игру
                gameLive = false;
                // сравниваем с лучшим результатом
                if (scoreValue > highScoreValue)
                {
                    highScoreValue = scoreValue;
                    timer1.Enabled = false;
                    // Показываем форму для лучших результатов
                    highScore.ShowDialog();
                    timer1.Enabled = true;
                    highScorePlayer = highScore.PlayerName;
                }
                // меняем сообщение на экране
                messageString = "Лучший результат: " + highScoreValue;
            }
        }

        private void newLevel()
        {
            if (!gameLive)
            {
                return;
            }
            // Рисуем помидоры чуть ниже
            tomatoDrawHeight += tomatoSpacing;

            if (tomatoDrawHeight >
               (ClientSize.Height - (breadRectangle.Height + tomatoImage.Height)))
            {
                //  Рисуем помидоры снова в верхней части экрана
                tomatoDrawHeight = tomatoLevelStartHeight;
            }
            placeTomatoes();
            // Увеличиваем скорость
            if (xSpeed < maxSpeed)
            {
                xSpeed++;
                ySpeed++;
            }
        }

        /// <summary>
        /// True, если ветчина на экране
        /// </summary>
        private bool hamPresent = false;

        /// <summary>
        /// Интервал от 0 до 10. Чем выше значение,
        /// тем чаще ветчина появляется на экране
        /// </summary>
        private int hamLikelihood = 5;

        /// <summary>
        /// Отчет времени перед исчезновением ветчины.
        /// Устанавливаем случайное число при появлении ветчины.
        /// </summary>
        private int hamTimerCount;

        /// <summary>
        /// Случайное число.
        /// </summary>
        private Random randomNumbers;

        /// <summary>
        /// Вызывается для активизации ветчины
        /// </summary>
        private void startHam()
        {
            // не продолжать, если ветчина уже есть на экране
            if (hamPresent)
            {
                return;
            }
            // решаем, как часто выводить ветчину на экран
            if (randomNumbers.Next(10) > hamLikelihood)
            {
                // не выводить ветчину на экран
                return;
            }
            // позиция ветчины в случайной позиции на экране
            bonusHamRectangle.X =
               randomNumbers.Next(ClientSize.Width - bonusHamRectangle.Width);
            bonusHamRectangle.Y =
               randomNumbers.Next(ClientSize.Height - bonusHamRectangle.Height);
            // как долго держится изображение ветчины на экране
            // (по крайне мере 50 тиков)
            hamTimerCount = 50 + randomNumbers.Next(100);
            // делаем ветчину видимым
            hamPresent = true;
        }

        /// <summary>
        /// Обновляем состояние ветчины
        /// </summary>
        private void hamTick()
        {
            // ничего не делаем, если ветчина невидима
            if (!hamPresent)
            {
                return;
            }
            if (breadRectangle.IntersectsWith(bonusHamRectangle))
            {
                // при касании игроком куска ветчины
                // прибавляем 100 очков
                scoreValue = scoreValue + 100;
                messageString = "Счет: " + scoreValue + "  Жизнь: " + livesLeft;
                // звук касания ветчины
                bonusHamSound.Play();
                // прячем ветчину с экрана
                hamPresent = false;
            }
            else
            {
                // Отчитываем время назад
                hamTimerCount--;
                if (hamTimerCount == 0)
                {
                    // время вышло – удаляем ветчину
                    hamPresent = false;
                }
            }
        }

        /// <summary>
        /// Сохраняем лучший результат в файле.
        /// </summary>
        public void SaveHighScore()
        {
            System.IO.TextWriter writer = null;
            try
            {
                writer = new System.IO.StreamWriter(
                    applicationDirectory + highScoreFile);
                writer.WriteLine(highScorePlayer);
                writer.WriteLine(highScoreValue);
            }
            catch { }
            finally
            {
                if (writer != null)
                {
                    writer.Close();
                }
            }
        }

        /// <summary>
        /// Загружаем лучший результат из файла.
        /// </summary>
        public void LoadHighScore()
        {
            System.IO.TextReader reader = null;
            try
            {
                reader = new System.IO.StreamReader(
                    applicationDirectory + highScoreFile);
                highScorePlayer = reader.ReadLine();
                string highScoreString = reader.ReadLine();
                highScoreValue = int.Parse(highScoreString);
            }
            catch { }
            finally
            {
                if (reader != null)
                {
                    reader.Close();
                }
            }
        }


        protected override void OnPaintBackground(PaintEventArgs pevent)
        {
            // Не разрешаем перерисовывать фон  
        } 

        /// <summary>
        /// картинка-буфер
        /// </summary>
        private Bitmap backBuffer = null;

        private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
        {
            // Создаем новый буфер
            if (backBuffer == null)
            {
                backBuffer = new Bitmap(this.ClientSize.Width, this.ClientSize.Height);
            }

            using (Graphics g = Graphics.FromImage(backBuffer))
            {
                //***Старая версия****
                g.Clear(Color.White);
                //***********************
                g.DrawImage(backgroundImage, 0, 0);

                bool gotTomato = false;
                // Выводим ряд помидоров
                for (int i = 0; i < tomatoes.Length; i++)
                {
                    if (tomatoes[i].visible)
                    {
                        gotTomato = true;

                        //***Старая версия*******************************
                        g.DrawImage(tomatoImage,
                           tomatoes[i].rectangle.X, tomatoes[i].rectangle.Y);
                        //********************************************************

                        g.DrawImage(
                                                tomatoImage,        // Image
                                                tomatoes[i].rectangle,    // Dest. rect.
                                                0,					// srcX
                                                0,					// srcY
                                                tomatoImage.Width,  // srcWidth
                                                tomatoImage.Height, // srcHeight
                                                GraphicsUnit.Pixel, // srcUnit
                                                transparentWhite);  // ImageAttributes
                    }
                }

                if (!gotTomato)
                {
                    newLevel();
                }

                // ***Старая версия***********
                //Текущая позиция сыра
                //g.DrawImage(cheeseImage, cx, cy);
                //Текущая позиция батона
                //g.DrawImage(breadImage, bx, by);
                //***********************************

                // Выводим на экран кусок ветчины
                if (hamPresent)
                {
                    //***Старая версия***
                    //g.DrawImage(bonusHamImage, bonusHamRectangle.X, bonusHamRectangle.Y);
                    //************************************************************

                    g.DrawImage(
						bonusHamImage,        // Image
						bonusHamRectangle,    // Dest. rect.
						0,					// srcX
						0,					// srcY
						bonusHamRectangle.Width,  // srcWidth
						bonusHamRectangle.Height, // srcHeight
						GraphicsUnit.Pixel, // srcUnit
						transparentWhite);  // ImageAttributes
				}

                // Выводим на экран батон хлеба
                //***Старая версия***
                //g.DrawImage(breadImage, breadRectangle.X, breadRectangle.Y);
                //************************************************************

                g.DrawImage(
                    breadImage,        // Image
                    breadRectangle,    // Dest. rect.
                    0,					// srcX
                    0,					// srcY
                    breadRectangle.Width,  // srcWidth
                    breadRectangle.Height, // srcHeight
                    GraphicsUnit.Pixel, // srcUnit
                    transparentWhite);  // ImageAttributes

                
                // Выводим на экран кусочек сыра
                //***Старая версия***
                //g.DrawImage(cheeseImage, cheeseRectangle.X, cheeseRectangle.Y);
                //************************************************************

                g.DrawImage(
                    cheeseImage,        // Image
                    cheeseRectangle,    // Dest. rect.
                    0,                  // srcX
                    0,                  // srcY
                    cheeseRectangle.Width,  // srcWidth
                    cheeseRectangle.Height, // srcHeight
                    GraphicsUnit.Pixel,     // srcUnit
                    transparentWhite);      // ImageAttributes




                g.DrawString(messageString, messageFont, messageBrush, messageRectangle);

            }
            e.Graphics.DrawImage(backBuffer, 0, 0);

            

        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            updatePositions();
            hamTick();
            Invalidate();
        }

        /// <summary>
        /// Используем keyArgs в качестве флага
        /// </summary>
        private System.Windows.Forms.KeyEventArgs keyArgs = null;

        private void Form1_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
        {
            keyArgs = e;
        }

        private void Form1_KeyUp(object sender, System.Windows.Forms.KeyEventArgs e)
        {
            keyArgs = null;
        }

        private void menuItem1_Click(object sender, EventArgs e)
        {
            //changeSpeed(1);
            startGame();
        }

        private void menuItem2_Click(object sender, EventArgs e)
        {
            //changeSpeed(-1);
            Application.Exit();
            

        }

    }
}