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.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace PArena
{
    public struct ShakeParam
    {
        public Vector2 dir;
        public float ampl;
        public float maxtime;
        public float curtime;
    };

    public enum GameStates
    {
        GS_Menu,
        GS_Level,
        GS_ChangeLevel,
        GS_GameOver
    }
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        

        public GraphicsDeviceManager graphics;
        public static SpriteBatch spriteBatch;
        KeyboardState oldkstate;
        MouseState oldmstate;
        public static Texture2D linetex;
        public SpriteFont font;
        public SpriteFont fontVerdana;
        public SpriteFont fontVerdanaLarge;
        public static Random rnd = new Random(222111);
        public GameStates gameState = GameStates.GS_Menu;

        public List<Spot> spots=new List<Spot>();
        Texture2D spotTextures;
        public Texture2D tooltipTex;
        List<ToolTip> tooltips;
        public int spotCount { get { return spotTextures.Width/80; } }

        public static int screenWidth = 1024;
        public static int screenHeight = 768;

        public Player CurrentPlayer { get { return player; } set { player = value; } }
        Player player;
        Level currentLevel;
        public Level CurrentLevel { get { return currentLevel; } set { currentLevel = value; } }

        public List<Texture2D> playerTextures=new List<Texture2D>();
        public List<Enemy> EnemyList { get { return enemyList; } }
        List<Enemy> enemyList = new List<Enemy>();
        public Dictionary<string, Texture2D> EnemyTextures;
        public List<Bullet> Bullets { get { return bullets; } }
        List<Bullet> bullets=new List<Bullet>();
        public List<Bullet> EnemyBullets { get { return enemyBullets; } }
        List<Bullet> enemyBullets = new List<Bullet>();
        public List<Bonus> BonusList { get { return bonusList; } }
        List<Bonus> bonusList = new List<Bonus>();

        public Texture2D bulletTex;
        public Texture2D tailTexCommon;
        public Texture2D bonusesTex;
        Texture2D menuTex;
        Texture2D deadScreenTex;
        Texture2D cursorTex;
        
        HUD hud;

        RenderTarget2D mainScene;
        //RenderTarget2D postMainScene;
        RenderTarget2D shakeScene;
        RenderTarget2D currentTarget;
        RenderTarget2D distortRT;
        RenderTarget2D distortedRT;

        Effect shakeEffect;
        Effect distortEffect;
        public Effect glowEffect;

        delegate Vector2 ShakeDelegate(ShakeParam sh);
        ShakeDelegate ShakeFunction;
        ShakeParam shakeParam;


        //Sounds
        Song titleTheme;
        Song levelTheme;
        public Song bossTheme;
        AudioEngine audioEngine;
        WaveBank waveBank;
        public SoundBank soundBank;


        //gameplay
        float LoadBonus=1;


        // TMP
        Texture2D distort;
        bool test1 = true;
        int currentLevelSelect=0;

        public Game1()
        {            
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            graphics.PreferredBackBufferWidth = screenWidth;
            graphics.PreferredBackBufferHeight = screenHeight;
            //IsMouseVisible = true;
            //IsFixedTimeStep = false;
            //graphics.SynchronizeWithVerticalRetrace = false;
            //TargetElapsedTime = new TimeSpan(0, 0, 0, 0, 5);
           
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {           
            PresentationParameters pp = GraphicsDevice.PresentationParameters;
            mainScene = new RenderTarget2D(GraphicsDevice, pp.BackBufferWidth, pp.BackBufferHeight, false, graphics.GraphicsDevice.DisplayMode.Format, DepthFormat.Depth24);
            shakeScene = new RenderTarget2D(GraphicsDevice, pp.BackBufferWidth, pp.BackBufferHeight, false, graphics.GraphicsDevice.DisplayMode.Format, DepthFormat.Depth24);
            currentTarget = new RenderTarget2D(GraphicsDevice, pp.BackBufferWidth, pp.BackBufferHeight, false, graphics.GraphicsDevice.DisplayMode.Format, DepthFormat.Depth24);
            //postMainScene = new RenderTarget2D(GraphicsDevice, pp.BackBufferWidth, pp.BackBufferHeight, false, graphics.GraphicsDevice.DisplayMode.Format, DepthFormat.Depth24);
            distortRT = new RenderTarget2D(GraphicsDevice, pp.BackBufferWidth, pp.BackBufferHeight, false, graphics.GraphicsDevice.DisplayMode.Format, DepthFormat.Depth24);
            distortedRT = new RenderTarget2D(GraphicsDevice, pp.BackBufferWidth, pp.BackBufferHeight, false, graphics.GraphicsDevice.DisplayMode.Format, DepthFormat.Depth24);

            
            linetex = new Texture2D(graphics.GraphicsDevice, 1, 1, false, SurfaceFormat.Color);
            linetex.SetData<Color>(new Color[1] { Color.White });
            Cnt.game = this;
            EnemyTextures = new Dictionary<string, Texture2D>();

            ShakeFunction = RandomShake;
            hud = new HUD();

            audioEngine = new AudioEngine("Content\\Audio\\audio.xgs");
            waveBank = new WaveBank(audioEngine, "Content\\Audio\\Wave Bank.xwb");
            soundBank = new SoundBank(audioEngine, "Content\\Audio\\Sound Bank.xsb");
            Cue cyd = soundBank.GetCue("CYD");
            cyd.Play();
            
            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            font = Content.Load<SpriteFont>("Font1");
            fontVerdana = Content.Load<SpriteFont>("Font2");
            fontVerdanaLarge = Content.Load<SpriteFont>("Font3");
            Components.Add(new FPSCounter(this, font, spriteBatch));            

            bulletTex = Content.Load<Texture2D>("b1");
            //background = Content.Load<Texture2D>("bg_parena");        
            shakeEffect = Content.Load<Effect>("transparent");
            glowEffect = Content.Load<Effect>("glow");
            distortEffect = Content.Load<Effect>("distort");
            EnemyTextures.Add("Fast", Content.Load<Texture2D>("enemy_fast"));
            EnemyTextures.Add("Normal", Content.Load<Texture2D>("enemy_normal"));
            EnemyTextures.Add("Slow", Content.Load<Texture2D>("enemy_slow"));
            EnemyTextures.Add("Stable", Content.Load<Texture2D>("enemy_stable"));
            playerTextures.Add(Content.Load<Texture2D>("pony\\aj"));//0
            playerTextures.Add(Content.Load<Texture2D>("pony\\flutty"));//1
            playerTextures.Add(Content.Load<Texture2D>("pony\\p"));//2
            playerTextures.Add(Content.Load<Texture2D>("pony\\rar"));//3
            playerTextures.Add(Content.Load<Texture2D>("pony\\rd"));//4
            playerTextures.Add(Content.Load<Texture2D>("pony\\tw"));//5

            spotTextures=Content.Load<Texture2D>("spotsTex");
            cursorTex = Content.Load<Texture2D>("cursor");
            menuTex = Content.Load<Texture2D>("menu");
            tooltipTex = Content.Load<Texture2D>("toolTip");
            tooltips = new List<ToolTip>();
            tooltips.Add(new ToolTip(new Rectangle(117, 137, 114, 105), new Rectangle(37, 380, 270, 90), "Twilight Sparkle: Element of Magic\n\nWeapon: Guided Shot", Color.MediumOrchid, Pony.Twily));
            tooltips.Add(new ToolTip(new Rectangle(248, 137, 114, 105), new Rectangle(167, 380, 270, 90), "Rarity: Element of Generosity\n\nWeapon: Rifle Shot", Color.MediumPurple, Pony.Rarity));
            tooltips.Add(new ToolTip(new Rectangle(379, 137, 114, 105), new Rectangle(297, 380, 270, 90), "Rainbow Dash: Element of Loyalty\n\nWeapon: RailGun\n+20% coolness", Color.CornflowerBlue, Pony.RD));
            tooltips.Add(new ToolTip(new Rectangle(510, 137, 114, 105), new Rectangle(427, 380, 270, 90), "Fluttershy: Element of Kindness\n\nWeapon: MachineGun", Color.Khaki, Pony.Flutty));
            tooltips.Add(new ToolTip(new Rectangle(641, 137, 114, 105), new Rectangle(557, 380, 270, 90), "AppleJack: Element of Honesty\n\nWeapon: ShotGun", Color.DarkOrange, Pony.AJ));
            tooltips.Add(new ToolTip(new Rectangle(772, 137, 114, 105), new Rectangle(687, 380, 270, 90), "Pinie Pie:Element of Laughter\n\nWeapon: FlameThrower\nin DLC for $19.99", Color.Magenta, Pony.Pinkie));


            distort = Content.Load<Texture2D>("distortMap");
            deadScreenTex = Content.Load<Texture2D>("deadscreen");
            tailTexCommon = Cnt.game.Content.Load<Texture2D>("t2");
            bonusesTex = Cnt.game.Content.Load<Texture2D>("bonusesTex");

            titleTheme = Content.Load<Song>("Audio\\Song\\rest");
            levelTheme = Content.Load<Song>("Audio\\Song\\L.S.D");
            bossTheme = Content.Load<Song>("Audio\\Song\\toxic");

            
           
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }


        protected override void Update(GameTime gameTime)
        {
            
            switch (gameState)
            {
                case GameStates.GS_Menu:
                    Update_Menu(gameTime);
                    break;
                case GameStates.GS_Level:
                    Update_Level(gameTime);
                    break;
                case GameStates.GS_ChangeLevel:
                    Update_ChangeLevel(gameTime);
                    break;
                case GameStates.GS_GameOver:
                    Update_GameOver(gameTime);
                    break;
                default:
                    break;
            }
            base.Update(gameTime);   
        }

        private void Update_GameOver(GameTime gameTime)
        {
            KeyboardState kstate = Keyboard.GetState();
            MouseState mstate = Mouse.GetState();

            if (kstate.IsKeyDown(Keys.Space) && !oldkstate.IsKeyDown(Keys.Space))
            {
                gameState = GameStates.GS_Menu;
                MediaPlayer.Stop();
                Cue cyd = soundBank.GetCue("CYD");
                cyd.Play();
                
            }
            player.Update(gameTime, kstate);
            oldkstate = kstate;
            oldmstate = mstate;

        }

        void Update_Menu(GameTime gt)
        {
            
            KeyboardState kstate = Keyboard.GetState();
            MouseState mstate = Mouse.GetState();

            if (MediaPlayer.State == MediaState.Stopped)
            {
                MediaPlayer.Volume = 0.2f;
                MediaPlayer.Play(titleTheme);
            }

            if (kstate.IsKeyDown(Keys.Escape)) this.Exit();
            /*
            if (kstate.IsKeyDown(Keys.Space) && !oldkstate.IsKeyDown(Keys.Space))
            {
                gameState = GameStates.GS_Level;
                CurrentLevel = new Level_3();
            }*/
            foreach (ToolTip tt in tooltips)
            {
                tt.Update(mstate, gt);
            }

            if (mstate.LeftButton == ButtonState.Pressed && oldmstate.LeftButton != ButtonState.Pressed)
            {
                foreach (ToolTip tt in tooltips)
                {
                    if (tt.Active && tt.playerType != Pony.Pinkie)
                    {
                        enemyList.Clear();
                        enemyBullets.Clear();
                        bullets.Clear();
                        player = new Player(new Vector2(screenWidth / 2, screenHeight / 2), Vector2.Zero, tt.playerType);
                       // player = new Player(new Vector2(screenWidth / 2, screenHeight / 2), Vector2.Zero, Pony.AJ);
                        //CurrentLevel = new Level_1();                       
                        CurrentLevel= (Level)Activator.CreateInstance(Type.GetType("PArena.Level_"+(currentLevelSelect+1).ToString()));

                        gameState = GameStates.GS_Level;
                        MediaPlayer.Stop();
                    }
                }

                for (int i = 0; i < 5; i++)
                {
                    Rectangle rect = new Rectangle(155 + i * 146, 580, 120, 70);
                    if (rect.Contains(new Point(mstate.X,mstate.Y))) {currentLevelSelect=i;}
                }
            }

            oldkstate = kstate;
            oldmstate = mstate;
        }

        void Update_ChangeLevel(GameTime gt)
        {
           
            KeyboardState kstate = Keyboard.GetState();
            MouseState mstate = Mouse.GetState();
            if (kstate.IsKeyDown(Keys.Escape)) this.Exit();

            player.Update(gt, Keyboard.GetState());
            CurrentLevel.LevelBoss.Update(gt);
            if (kstate.IsKeyDown(Keys.Space) && !oldkstate.IsKeyDown(Keys.Space))
            {
                gameState = GameStates.GS_Level;
                CurrentLevel = CurrentLevel.nextLevel;
                enemyList.Clear();
                bullets.Clear();
                EnemyBullets.Clear();
                player.hitpoints = player.maxHitpoints;
                MediaPlayer.Stop();
                MediaPlayer.Play(levelTheme);
            }
           
            oldkstate = kstate;
            oldmstate = mstate;
        }
        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        void Update_Level(GameTime gameTime)
        {
            if (rnd.NextDouble()  < 0.01&&LoadBonus<0) { Bonus.LoadRandomBonus(this); LoadBonus = 20; }
            LoadBonus -= (float)gameTime.ElapsedGameTime.TotalSeconds;

            HandleInput();
            if (MediaPlayer.State == MediaState.Stopped)
            {
                MediaPlayer.Volume = 0.3f;
                if (CurrentLevel.LevelBoss != null)
                    MediaPlayer.Play(bossTheme);
                else
                    MediaPlayer.Play(levelTheme);
            }                      

            player.Update(gameTime, Keyboard.GetState());

            for (int i = 0; i < enemyList.Count; i++)
            {
                enemyList[i].Update(gameTime);
                if (enemyList[i].toRemove) enemyList.RemoveAt(i); 
            }

            for (int i = 0; i < bonusList.Count; i++)
            {
                bonusList[i].Update(gameTime);
                if (bonusList[i].toRemove) bonusList.RemoveAt(i);
            }
            
            for (int i = 0; i < Bullets.Count; i++)
            {
                Bullets[i].Update(gameTime);
                if (Bullets[i].toRemove) Bullets.RemoveAt(i);                
            }
            for (int i = 0; i < EnemyBullets.Count; i++)
            {
                EnemyBullets[i].Update(gameTime);
                if (EnemyBullets[i].toRemove) EnemyBullets.RemoveAt(i);
            }
            //if (boss1 != null) boss1.Update(gameTime);
            if (currentLevel != null) currentLevel.Update(gameTime);

            CheckCollision(gameTime);
            if (player.isDead)
            {                
                MediaPlayer.Stop();
                soundBank.GetCue("death").Play();
                gameState = GameStates.GS_GameOver;
            }

            shakeParam.curtime = MathHelper.Clamp(shakeParam.curtime - (float)gameTime.ElapsedGameTime.TotalSeconds, 0, shakeParam.maxtime);                                
        }

        void HandleInput()
        {
            KeyboardState kstate = Keyboard.GetState();
            MouseState mstate = Mouse.GetState();
            if (kstate.IsKeyDown(Keys.Escape)) this.Exit();

            if (kstate.IsKeyDown(Keys.D4) && !oldkstate.IsKeyDown(Keys.D4))
            {
                Bonus.LoadRandomBonus(this);
            }

            if (kstate.IsKeyDown(Keys.Q) && !oldkstate.IsKeyDown(Keys.Q))
            {
                test1 ^= true;
            }

            if (kstate.IsKeyDown(Keys.D1))
            {
                shakeParam.ampl = 15;
                shakeParam.maxtime = 2;
                shakeParam.curtime = 2;
                ShakeFunction = RandomShake;
            }
            if (kstate.IsKeyDown(Keys.D2) && !oldkstate.IsKeyDown(Keys.D2))
            {
                shakeParam.ampl = 20;
                shakeParam.dir = Vector2.UnitX;
                shakeParam.maxtime = 5.15f;
                shakeParam.curtime = 5.15f;
                ShakeFunction = VectorShake;
            }
            if (kstate.IsKeyDown(Keys.Z) && !oldkstate.IsKeyDown(Keys.Z))
            {
                //enemyList.Add(new Enemy(new Vector2(100, 100), EnemyType.Fast));
                //level.Wave_T1();
            }           
            

            if (mstate.LeftButton == ButtonState.Pressed &&CurrentLevel.levelTime>0.1f /*&& oldmstate.LeftButton != ButtonState.Pressed*/)
            {
                if (player.canFire)
                {
                    shakeParam = player.Shoot(mstate.X, mstate.Y);                    
                    Vector2 dir = player.Pos - new Vector2(mstate.X, mstate.Y);
                    dir.Normalize();
                    shakeParam.dir = dir;                   
                    ShakeFunction = VectorShake;
                }
            }
            oldkstate = kstate;
            oldmstate = mstate;
        }

        void CheckCollision(GameTime gt)
        {            
            foreach (Enemy e in EnemyList)
            {                
                foreach (Bullet b in Bullets)
                {                   
                    if (b.prepareToRemove) continue;
                    if (!b.isOnScreen) continue;
                    int start = b.positions.IndexOf(b.prevPos) == -1 ? 0 : b.positions.IndexOf(b.prevPos);
                    for (int i = start; i < b.positions.Count; i++)
                    {
                        if (b.prepareToRemove) { b.positions.RemoveAt(i--); continue; }
                        if (e.toDie) {i=b.positions.Count;continue;}

                        Rectangle nextRect = new Rectangle((int)Math.Round(b.positions[i].v.X), (int)Math.Round(b.positions[i].v.Y), b.sprite.Width, b.sprite.Height);
                        if (nextRect.Intersects(e.rect))
                        {
                            Color[] first = new Color[b.sprite.Width * b.sprite.Height];
                            Color[] second = new Color[e.sprite.Width * e.sprite.Height];
                            b.sprite.GetData<Color>(first);
                            e.sprite.GetData<Color>(second);
                            if (Game1.Collision(nextRect, first, e.rect, second))
                            {
                                float hp = e.hitpoints;
                                e.hitpoints -= b.damage;
                                b.damage -= hp;
                                if (e.hitpoints <= 0) e.Die();
                                if (b.damage <= 0) b.prepareToRemove = true;
                                //break;
                            }
                        }
                    }
                }
                if (e.toDie) continue;

                if (player.rect.Intersects(e.rect))
                {
                    Color[] first = new Color[player.sprite.Width * player.sprite.Height];
                    Color[] second = new Color[e.sprite.Width * e.sprite.Height];
                    player.sprite.GetData<Color>(first);
                    e.sprite.GetData<Color>(second);
                    if (Game1.Collision(player.rect, first, e.rect, second))
                    {
                        player.hitpoints -= 20* (float)gt.ElapsedGameTime.TotalSeconds;
                        e.hitpoints -= 20 * (float)gt.ElapsedGameTime.TotalSeconds;
                        if (e.hitpoints <= 0) e.Die();
                        if (player.hitpoints <= 0) player.Die();
                    }
                }
            }

            foreach (Bullet bullet in EnemyBullets)
            {
                if (bullet.prepareToRemove) continue;
                int start = bullet.positions.IndexOf(bullet.prevPos) == -1 ? 0 : bullet.positions.IndexOf(bullet.prevPos);
                for (int i = start; i < bullet.positions.Count; i++)
                {
                    if (bullet.prepareToRemove) { bullet.positions.RemoveAt(i--); continue; }
                    Rectangle nextRect = new Rectangle((int)(Math.Round(bullet.positions[i].v.X) - bullet.Origin.X), (int)(Math.Round(bullet.positions[i].v.Y)-bullet.Origin.Y), bullet.sprite.Width, bullet.sprite.Height);
                    if (nextRect.Intersects(player.rect))
                    {
                        Color[] first = new Color[bullet.sprite.Width * bullet.sprite.Height];
                        Color[] second = new Color[player.sprite.Width * player.sprite.Height];
                        bullet.sprite.GetData<Color>(first);
                        player.sprite.GetData<Color>(second);
                        if (Game1.Collision(nextRect, first, player.rect, second))
                        {
                            player.hitpoints -= bullet.damage;
                            if (player.hitpoints <= 0)  player.Die();
                            bullet.prepareToRemove = true;
                            //break;
                        }
                    }
                }
            }

            foreach (Bonus bonus in bonusList)
            {
                if (bonus.rect.Intersects(player.rect))
                {
                    bonus.Interact(player);
                }
            }
             
        }

        protected override void Draw(GameTime gameTime)
        {
            switch (gameState)
            {
                case GameStates.GS_Menu:
                    Draw_Menu(gameTime);
                    break;
                case GameStates.GS_Level:
                    Draw_Level(gameTime);
                    break;
                case GameStates.GS_ChangeLevel:
                    Draw_ChangeLevel(gameTime);
                    break;
                case GameStates.GS_GameOver:
                    Draw_GameOver(gameTime);
                    break;
                default:
                    break;
            }
            MouseState mstate = Mouse.GetState();
            spriteBatch.Begin();
            spriteBatch.Draw(cursorTex,new Vector2(mstate.X,mstate.Y)-new Vector2(10,10),Color.White);
            spriteBatch.End();

            base.Draw(gameTime);
        }

        private void Draw_GameOver(GameTime gameTime)
        {
            
            Draw_Level(gameTime);
            spriteBatch.Begin();
            spriteBatch.Draw(deadScreenTex, Vector2.Zero, Color.White);
            spriteBatch.End();
        }

        void Draw_Menu(GameTime gt)
        {
            spriteBatch.Begin();
            spriteBatch.Draw(menuTex, new Rectangle(0,0,screenWidth,screenHeight), Color.White);
            spriteBatch.Draw(tooltipTex, new Vector2(109, 129), new Rectangle(0, 0, 786, 122), Color.White);
            foreach (ToolTip tt in tooltips)
            {
                if (tt.Visible) tt.Draw(spriteBatch);
            }
            
            spriteBatch.DrawString(fontVerdanaLarge, "Select Level", new Vector2(450, 500), Color.White);

            spriteBatch.Draw(tooltipTex, new Rectangle(155+currentLevelSelect*146, 580, 120, 70), new Rectangle(0, 122, 270, 90), Color.White);
            spriteBatch.DrawString(fontVerdanaLarge, "Level 1           Level 2           Level 3           Level 4           Level 5", new Vector2(180, 600), Color.White);
           

            spriteBatch.End();
        }

        void Draw_ChangeLevel(GameTime gt)
        {
            Rectangle rect = new Rectangle(-50, -50, Game1.screenWidth + 100, Game1.screenHeight + 100);
            Rectangle rect2 = new Rectangle(0, 0, CurrentLevel.mainBackground.Width, CurrentLevel.mainBackground.Height);
           

            if (spots.Count > 0)
            {
                RenderTarget2D mainrender = new RenderTarget2D(GraphicsDevice, CurrentLevel.mainBackground.Width, CurrentLevel.mainBackground.Height);
                GraphicsDevice.SetRenderTarget(mainrender);
                spriteBatch.Begin();
                spriteBatch.Draw(CurrentLevel.mainBackground, rect2, Color.White);
                //spriteBatch.Draw(CurrentLevel.levelBackground, rect2, Color.White);
                foreach (var spot in spots)
                {
                    spriteBatch.Draw(spotTextures, spot.pos  - spot.origin + new Vector2(25, 25), spot.rect, spot.color);
                }
                spriteBatch.End();
                spots.Clear();
                CurrentLevel.mainBackground.Dispose();
                CurrentLevel.mainBackground = (Texture2D)mainrender;
            }
            GraphicsDevice.SetRenderTarget(null);
            spriteBatch.Begin();            
            CurrentLevel.Draw(spriteBatch, rect);
            CurrentLevel.LevelBoss.Draw(spriteBatch);
            player.Draw(spriteBatch);
            spriteBatch.End();
        }


        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        void Draw_Level(GameTime gameTime)
        {
            Vector2 shakeVector = ShakeFunction(shakeParam);
            Rectangle rect = new Rectangle(-50, -50, Game1.screenWidth + 100, Game1.screenHeight + 100);
            Rectangle rect2 = new Rectangle(0, 0, CurrentLevel.mainBackground.Width, CurrentLevel.mainBackground.Height);

            if (spots.Count > 0)
            {
                RenderTarget2D spotRender = new RenderTarget2D(GraphicsDevice, CurrentLevel.mainBackground.Width, CurrentLevel.mainBackground.Height);
                GraphicsDevice.SetRenderTarget(spotRender);
                spriteBatch.Begin();
                spriteBatch.Draw(CurrentLevel.mainBackground, rect2, Color.White);
                foreach (var spot in spots)
                {
                    //spriteBatch.Draw(spot.texture, spot.pos + spot.origin-new Vector2(50,50), null, Color.White, 0, spot.origin, 1, SpriteEffects.None, 1);
                    //spriteBatch.Draw(spot.texture, spot.pos / 2 - spot.origin  + new Vector2(25, 25), Color.White);
                    spriteBatch.Draw(spotTextures, spot.pos  - spot.origin + new Vector2(50, 50), spot.rect, spot.color);
                }
                spriteBatch.End();
                spots.Clear();
                CurrentLevel.mainBackground.Dispose();
                CurrentLevel.mainBackground = (Texture2D)spotRender;
                //Cnt.game.GraphicsDevice.SetRenderTarget(null);

            }

            GraphicsDevice.SetRenderTarget(mainScene);
            GraphicsDevice.Clear(new Color(0, 0, 0, 0));
            spriteBatch.Begin();

            rect.Offset((int)shakeVector.X, (int)shakeVector.Y);
            CurrentLevel.Draw(spriteBatch, rect);


            foreach (var bullet in Bullets)
            {
                bullet.Draw(spriteBatch);
            }
            foreach (var bullet in EnemyBullets)
            {
                bullet.Draw(spriteBatch);
            }

            for (int i = 0; i < bonusList.Count; i++)
            {
                bonusList[i].Draw(spriteBatch);                
            }
            

            //if (boss1 != null) boss1.Draw(spriteBatch);

            player.Draw(spriteBatch);
            foreach (var e in enemyList)
            {
                if (!e.isDistorted) { e.Draw(spriteBatch); }
                
            }

            spriteBatch.End();
            currentTarget = mainScene;

            if (CurrentLevel.LevelBoss != null && CurrentLevel.LevelBoss.isDistorted&&test1)
            {
                GraphicsDevice.SetRenderTarget(distortRT);
                GraphicsDevice.Clear(new Color(127, 127, 127, 127));
                spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend);
                spriteBatch.Draw(distort, CurrentLevel.LevelBoss.Pos - CurrentLevel.LevelBoss.Origin, Color.White);
                spriteBatch.End();
                GraphicsDevice.SetRenderTarget(distortedRT);                
                GraphicsDevice.Textures[1] = (Texture2D)currentTarget;
                spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, distortEffect);
                spriteBatch.Draw((Texture2D)distortRT, Vector2.Zero, Color.White);
                spriteBatch.End();
                currentTarget = distortedRT;
            }

            //
            /*
            bool flag = false;
            GraphicsDevice.SetRenderTarget(distortRT);
            GraphicsDevice.Clear(new Color(128, 128, 128, 128));
           
            foreach (Enemy e in EnemyList)
            {
                if (!e.toDie) continue;
                flag = true;
                spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque);
                spriteBatch.Draw(distort, e.Pos - e.Origin-new Vector2(100,100), Color.White);
                //spriteBatch.Draw(distort, e.rect, null, Color.White);
                spriteBatch.End();
            }
            
            foreach (Enemy e in EnemyList)
            {
                
                //GraphicsDevice.SetRenderTarget(rt);
                float strength = (float)Math.Sin(MathHelper.Pi* e.killTime / e.deadAnimationTime);//MathHelper.Lerp(0.05, 0.15, e.killTime / e.deadAnimationTime);
                if (!e.toDie) continue;
                RenderTarget2D rt = new RenderTarget2D(GraphicsDevice, 1024, 768, false, graphics.GraphicsDevice.DisplayMode.Format, DepthFormat.Depth24);
                strength = MathHelper.Lerp(0.05f, 0.15f, strength);
                GraphicsDevice.SetRenderTarget(rt);
                GraphicsDevice.Textures[1] = (Texture2D)currentTarget;
                distortEffect.Parameters["strength"].SetValue(strength);
                distortEffect.Parameters["pos"].SetValue(e.Pos);
                spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, distortEffect);
                spriteBatch.Draw((Texture2D)distortRT, Vector2.Zero, Color.White);
                spriteBatch.End();
                //currentTarget.Dispose();  
                currentTarget = rt;
            }
           //if (flag) currentTarget = distortedRT;
            //
            //currentTarget = distortRT;
            */
            if (shakeParam.curtime > 0)
            {
                GraphicsDevice.SetRenderTarget(shakeScene);
                //GraphicsDevice.Clear(new Color(0, 0, 0, 0));                
                spriteBatch.Begin();
                spriteBatch.Draw((Texture2D)currentTarget, Vector2.Zero, Color.White);
                spriteBatch.End();
                
                spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, null, null, null, shakeEffect);

                foreach (var bullet in Bullets)
                {
                    bullet.Draw(spriteBatch, shakeVector);
                }

                player.Draw(spriteBatch, shakeVector);
                foreach (var e in enemyList)
                {
                    e.Draw(spriteBatch, shakeVector);
                }

                for (int i = 0; i < bonusList.Count; i++)
                {
                    bonusList[i].Draw(spriteBatch, shakeVector);
                }

                spriteBatch.End();
                
                currentTarget = shakeScene;
            }
           
            GraphicsDevice.SetRenderTarget(null);
            spriteBatch.Begin();
            spriteBatch.Draw((Texture2D)currentTarget, Vector2.Zero, Color.White);
            foreach (var e in enemyList)
            {
              if (e.isDistorted) e.Draw(spriteBatch, shakeVector);
            }
            hud.Draw(spriteBatch);

          
            spriteBatch.DrawString(font, "lb: " + LoadBonus, new Vector2(10, 5 * 12), Color.White);
            spriteBatch.DrawString(font, "HP: " + player.hitpoints, new Vector2(10, 6 * 12), Color.White);
            spriteBatch.DrawString(font, "time: " + CurrentLevel.Time, new Vector2(10, 7 * 12), Color.White);
            //spriteBatch.DrawString(font, "BossHP: " + boss1.Speed, new Vector2(10, 4 * 12), Color.White);


            spriteBatch.End();
        }


        public static void DrawLine(Vector2 v1, Vector2 v2, Color c, int width)
        {           
            float rot = (float)Math.Atan2(v2.Y - v1.Y, v2.X - v1.X);
            spriteBatch.Draw(linetex, new Rectangle((int)v1.X, (int)v1.Y, (int)(v2 - v1).Length(), width), null, c, rot, Vector2.Zero, SpriteEffects.None, 0);
        }


        public static bool Collision(Rectangle firstRect, Color[] first, Rectangle secondRect, Color[] second)
        {
            int top = Math.Max(firstRect.Top, secondRect.Top);
            int bottom = Math.Min(firstRect.Bottom, secondRect.Bottom);
            int left = Math.Max(firstRect.Left, secondRect.Left);
            int right = Math.Min(firstRect.Right, secondRect.Right);

            for (int y = top; y < bottom; y++)
            {
                for (int x = left; x < right; x++)
                {
                    Color color1 = first[(x - firstRect.Left) + (y - firstRect.Top) * firstRect.Width];
                    Color color2 = second[(x - secondRect.Left) + (y - secondRect.Top) * secondRect.Width];
                    int sum1 = color1.R + color1.G + color1.B + color1.A;
                    int sum2 = color2.R + color2.G + color2.B + color2.A; 
                    if (sum1 > 300 && sum2 > 300) return true;                    
                }
            }
            return false;

        }

        public int BulletsCount()
        {
            int n=0;
            Bullets.ForEach(delegate(Bullet b) { if (!b.prepareToRemove) { n++; } });
            return n;
        }

       
        
        Vector2 VectorShake(ShakeParam sh)
        {
            if (sh.curtime == 0) return Vector2.Zero;
            float time = sh.curtime / sh.maxtime;
            return sh.dir*sh.ampl*(float)Math.Sin(Math.PI*time);            
        }

        Vector2 RandomShake(ShakeParam sh)
        {
            if (sh.curtime == 0) return Vector2.Zero;
            return new Vector2(rnd.Next(2*(int)sh.ampl) - sh.ampl, rnd.Next(2*(int)sh.ampl) - sh.ampl);
        }
      
    }
}
