using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Super_Mario_Brothers.Animations;
using Super_Mario_Brothers.Collisions;
using Super_Mario_Brothers.Rooms;
using Super_Mario_Brothers.LevelDataStore.Importers;
using Super_Mario_Brothers.LevelDataStore;
using Super_Mario_Brothers.Behaviors;
using Microsoft.Xna.Framework.Audio;

namespace Super_Mario_Brothers.Entities
{
    public class Block : GameEntity
    {
        static Texture2D spriteSheet;
        static SoundEffect BrickSound;
        static SoundEffect SpawnSound;
        struct SpriteSet
        {
            public Sprite Dirt;
            public Sprite Used;
            public Sprite Bevel;
            public Sprite Question;
            public Sprite BrickTop;
            public Sprite Brick;

            internal Sprite BySpriteKind(ImportBlock.SpriteKind spriteKind)
            {
                switch (spriteKind) {
                    case ImportBlock.SpriteKind.DIRT:     return Dirt;
                    case ImportBlock.SpriteKind.BEVEL:    return Bevel;
                    case ImportBlock.SpriteKind.BLOCK:    return Used;
                    case ImportBlock.SpriteKind.QBLOCK:   return Question;
                    case ImportBlock.SpriteKind.BRICK:    return Brick;
                    case ImportBlock.SpriteKind.BRICKTOP: return BrickTop;
                }
                return null;
            }
        }
        private static SpriteSet[] sprites;
        int[] sprImages = new int[] { 0, 0, 0, 1, 2, 1 };

        GameEntityInstantiator contentInstantiator = null;
        int contentCount = 0;
        bool destructable = false;
        bool contentUseSpawner = false;
        
        Vector2 bumpOffset;

        protected override int initialDepth { get { return 0; } }

        public Block(Room room): base(room) {
            CurrentSprite = sprites[(int)room.TerrainTheme].Dirt;
        }

        override public void Update(GameTime time)
        {
            ImageIndex = sprImages[(int)(time.TotalGameTime.TotalMilliseconds / 125) % sprImages.Length];
            if (CurrentAnimation != null)
                CurrentAnimation.Update(this, time);
            bumpOffset /= 1.5f;
        }

        static Random rand = new Random();
        override public void Bump(GameEntity bumper, CollisionTesting.CollisionSides sides, GameTime time)
        {
            if ((sides & CollisionTesting.CollisionSides.OR_ALLSIDES) == CollisionTesting.CollisionSides.BOTTOM)
            {
                if (bumper is Mario)
                {
                    if (contentInstantiator != null) {
                        var e = MyRoom.Instantiate(contentInstantiator, time);
                        if (e.CurrentSprite != null)
                            e.Position = Position - CurrentSprite.Origin + new Vector2(CurrentSprite.Size.X / 2, CurrentSprite.Size.Y) +
                                new Vector2(e.CurrentSprite.Origin.X - e.CurrentSprite.Size.X / 2, e.CurrentSprite.Origin.Y - e.CurrentSprite.Size.Y);
                        else
                            e.Position = Position - CurrentSprite.Origin + CurrentSprite.Size / 2;
                        if (contentUseSpawner)
                        {
                            SpawnSound.Play();
                            e.CurrentAnimation = new Spawner(e, time, new Vector2(0, -CurrentSprite.Size.Y), 750);
                        }
                        bumpOffset = new Vector2(0, -4);
                        if (--contentCount == 0) {
                            contentInstantiator = null;
                            CurrentSprite = sprites[(int)MyRoom.TerrainTheme].Used;
                            if (!Visible)
                            {
                                Visible = true;
                                SolidSides = CollisionTesting.CollisionSides.EVERYTHING;
                            }
                        }
                    }
                    if (destructable)
                    {
                        if (!((Hero)bumper).IsPoweredUp())
                            bumpOffset = new Vector2(0, -4);
                        else
                        {
                            MyRoom.Destroy(this);
                            Vector2 g = new Vector2(0, .375f);
                            BrickSound.Play();
                            MyRoom.Add(new Particle(MyRoom, CurrentSprite, new Rectangle(0, 0, 8, 8), Position + new Vector2( 4,  4), new Vector2(-rand.Next(3,5), -rand.Next(3,6)), g, (float)(-.1 - .25 * rand.NextDouble())), time);
                            MyRoom.Add(new Particle(MyRoom, CurrentSprite, new Rectangle(8, 0, 8, 8), Position + new Vector2(12,  4), new Vector2(+rand.Next(3,5), -rand.Next(3,6)), g, (float)(-.1 - .25 * rand.NextDouble())), time);
                            MyRoom.Add(new Particle(MyRoom, CurrentSprite, new Rectangle(0, 8, 8, 8), Position + new Vector2( 4, 12), new Vector2(-rand.Next(3,5), -rand.Next(2,5)), g, (float)(-.1 - .25 * rand.NextDouble())), time);
                            MyRoom.Add(new Particle(MyRoom, CurrentSprite, new Rectangle(8, 8, 8, 8), Position + new Vector2(12, 12), new Vector2(+rand.Next(3,5), -rand.Next(2,5)), g, (float)(-.1 - .25 * rand.NextDouble())), time);
                        }
                    }
                }
            }
        }

        public override void Draw(GraphicsDevice graphics, SpriteBatch spriteBatch, GameTime time)
        {
            if (Visible)
                CurrentSprite.Draw(spriteBatch, (int)ImageIndex, Position + bumpOffset);
        }

        public class Instantiator : GameEntityInstantiator
        {
            override public GameEntity Instantiate(Room room) {
                return new Block(room);
            }

            protected override GameEntity ReadIn(Room room, EntityPlacementData e)
            {
                var res = new Block(room);
                ImportBlock ib = (ImportBlock)e.EntityImporter;
                res.CurrentSprite = sprites[(int)room.TerrainTheme].BySpriteKind(ib.Sprite);
                if (ib.Contains != null)
                {
                    res.contentInstantiator = Room.InstantiableEntities.LookUp(ib.Contains);
                    res.contentCount = ib.ContainsQuantity;
                    res.contentUseSpawner = ib.ContainsUseSpawner;
                }
                res.destructable = ib.Destructable;
                if (!(res.Visible = ib.Visible))
                    res.SolidSides = CollisionTesting.CollisionSides.BOTTOM;
                return res;
            }

            override public void LoadContent(ContentManager contentManager)
            {
                spriteSheet = contentManager.Load<Texture2D>("tileset");
                sprites = new SpriteSet[3];
                Point offset = new Point(0, 0);
                BrickSound = contentManager.Load<SoundEffect>("smb_breakblock");
                SpawnSound = contentManager.Load<SoundEffect>("smb_powerup_appears");
                for (int i = 0; i < sprites.Length; ++i) {
                    sprites[i].Dirt     = new Sprite(spriteSheet, new Rectangle(0   + offset.X,  0 + offset.Y, 16, 16), Vector2.Zero);
                    sprites[i].Used     = new Sprite(spriteSheet, new Rectangle(48  + offset.X,  0 + offset.Y, 16, 16), Vector2.Zero);
                    sprites[i].Bevel    = new Sprite(spriteSheet, new Rectangle(0   + offset.X, 16 + offset.Y, 16, 16), Vector2.Zero);
                    sprites[i].Question = new Sprite(spriteSheet, new Rectangle(384 + offset.X,  0 + offset.Y, 16, 16), Vector2.Zero, 3, new Vector2(16, 0));
                    sprites[i].BrickTop = new Sprite(spriteSheet, new Rectangle(16  + offset.X,  0 + offset.Y, 16, 16), Vector2.Zero);
                    sprites[i].Brick    = new Sprite(spriteSheet, new Rectangle(32  + offset.X,  0 + offset.Y, 16, 16), Vector2.Zero);
                    offset.Y += 32;
                }
            }
        }
    }
}