using ActionGame.GameResources.Models;
using ActionGame.GameResources.Repository;
using ActionGame.RawResources.Models;
using GameMaker.Models;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;


namespace GameMaker.Logic
{
    public class SessionLoader
    {
        private Session session;


        public SessionLoader()
        {
            session = null;
        }


        public Session Load(String folder)
        {
            session = new Session()
            {
                WorkingDirectory = folder
            };

            LoadRaw("fonts", session.Fonts, "fonts.csv");
            LoadRaw("music", session.Songs, "songs.csv");
            LoadRaw("textures", session.Textures, "textures.csv");
            LoadRaw("soundeffects", session.SoundEffects, "soundeffects.csv");

            LoadTileSets(session.TileSets, "tilesets.csv", session.Textures);
            LoadCharacterSets(session.CharacterSets, "charactersets.csv", session.Textures);
            LoadWorlds(session.Worlds, "worldmaps.csv");
            LoadPlayer("player.csv");
            LoadEnemies(session.Enemies, "enemies.csv");
            LoadItems(session.Items, "items.csv");

            return session;
        }


        private void LoadRaw(String subFolder, IList<RawResource> list, String csvFile)
        {
            //load from csv file first
            Stream stream = File.OpenRead(session.WorkingDirectory + "\\RawResources\\" + csvFile);
            StreamReader reader = new StreamReader(stream);

            reader.ReadLine();

            string line;
            while ((line = reader.ReadLine()) != null)
            {
                string[] lineContents = line.Split(',');

                if (lineContents[0].Equals("") == false)
                {
                    RawResource item = new RawResource()
                    {
                        Key = Int32.Parse(lineContents[0]),
                        FilePath = lineContents[1]
                    };

                    list.Add(item);
                }
            }
            reader.Close();

            //search directory for new files
            IEnumerable<string> files;
            try
            {
                files = Directory.EnumerateFiles(session.WorkingDirectory + "\\RawResources\\Content\\bin\\" + subFolder,"*",SearchOption.AllDirectories);
            }
            catch(Exception)
            {
                return;
            }

            foreach (String file in files)
            {
                FileInfo fileInfo = new FileInfo(file);
                
                if(fileInfo.Extension.Equals(".xnb"))
                {
                    String name = fileInfo.FullName.Replace(".xnb", "").Replace(session.WorkingDirectory + "\\RawResources\\Content\\bin\\", "");

                    //add to list if not exists
                    Int32 maxKey = -1;
                    Boolean found = false;

                    foreach(RawResource rawResource in list)
                    {
                        if (maxKey < rawResource.Key) maxKey = rawResource.Key;

                        if(rawResource.FilePath.Equals(name))
                        {
                            found = true;
                        }
                    }

                    if(found == false)
                    {
                        RawResource newResource = new RawResource()
                        {
                            Key = maxKey + 1,
                            FilePath = name
                        };

                        list.Add(newResource);
                    }
                }
            }
        }


        private void LoadTileSets(IList<TileSetDefinition> list, String csvFile, IList<RawResource> textures)
        {
            //load existing files first
            Stream stream = File.OpenRead(session.WorkingDirectory + "\\GameResources\\" + csvFile);
            StreamReader reader = new StreamReader(stream);

            IList<Int32> textureKeysUsed = new List<Int32>();
            Int32 maxKey = -1;
            reader.ReadLine();

            string line;
            while ((line = reader.ReadLine()) != null)
            {
                string[] lineContents = line.Split(',');

                TileSetDefinition tileSetDefinition = new TileSetDefinition()
                {
                    Key = Int32.Parse(lineContents[0]),
                    TextureKey = Int32.Parse(lineContents[1]),
                    X = Int32.Parse(lineContents[2]),
                    Y = Int32.Parse(lineContents[3]),
                    Width = Int32.Parse(lineContents[4]),
                    Height = Int32.Parse(lineContents[5]),
                    Passable = Boolean.Parse(lineContents[6])
                };

                if (lineContents[7].Equals("") == false) tileSetDefinition.AnimationSequence = new List<Int32>(Array.ConvertAll(lineContents[7].Split('|'), Int32.Parse));
                else tileSetDefinition.AnimationSequence = new List<Int32>();
                
                if (tileSetDefinition.Key > maxKey) maxKey = tileSetDefinition.Key;

                if (textureKeysUsed.Contains(tileSetDefinition.TextureKey) == false) textureKeysUsed.Add(tileSetDefinition.TextureKey);

                list.Add(tileSetDefinition);
            }
            reader.Close();

            //find new tile sets
            Int32 tileWidth = TileSet.DRAW_WIDTH;
            Int32 tileHeight = TileSet.DRAW_HEIGHT;

            foreach(RawResource texture in textures)
            {
                if((textureKeysUsed.Contains(texture.Key) == false) && (texture.FilePath.Contains("textures" + Path.DirectorySeparatorChar + "tileset" + Path.DirectorySeparatorChar)))
                {
                    Image image = Image.FromFile(RawResourceHelper.GetFilePathForTexture(session.WorkingDirectory, texture.FilePath));

                    if((image.Width % tileWidth == 0) && (image.Height % tileHeight == 0))
                    {
                        for(int x = 0; x < image.Width; x += tileWidth)
                        {
                            for (int y = 0; y < image.Height; y += tileHeight)
                            {
                                maxKey++;

                                TileSetDefinition tileSetDefinition = new TileSetDefinition()
                                {
                                    Key = maxKey,
                                    TextureKey = texture.Key,
                                    X = x,
                                    Y = y,
                                    Width = tileWidth,
                                    Height = tileHeight,
                                    Passable = true,
                                    AnimationSequence = new List<Int32>()
                                };

                                list.Add(tileSetDefinition);
                            }
                        }
                    }
                }
            }
        }


        private void LoadCharacterSets(IList<CharacterSetDefinition> list, String csvFile, IList<RawResource> textures)
        {
            //load existing files first
            Stream stream = File.OpenRead(session.WorkingDirectory + "\\GameResources\\" + csvFile);
            StreamReader reader = new StreamReader(stream);

            IList<Int32> textureKeysUsed = new List<Int32>();
            Int32 maxKey = -1;
            reader.ReadLine();

            string line;
            while ((line = reader.ReadLine()) != null)
            {
                string[] lineContents = line.Split(',');

                CharacterSetDefinition characterSetDefinition = new CharacterSetDefinition()
                {
                    Key = Int32.Parse(lineContents[0]),
                    TextureKey = Int32.Parse(lineContents[1]),
                    Comment = lineContents[2]
                };

                if (characterSetDefinition.Key > maxKey) maxKey = characterSetDefinition.Key;

                if (textureKeysUsed.Contains(characterSetDefinition.TextureKey) == false) textureKeysUsed.Add(characterSetDefinition.TextureKey);

                list.Add(characterSetDefinition);
            }
            reader.Close();

            //find new tile sets
            Int32 imageWidth = CharacterSet.DRAW_WIDTH * 3;
            Int32 imageHeight = CharacterSet.DRAW_HEIGHT * 4;

            foreach (RawResource texture in textures)
            {
                if ((textureKeysUsed.Contains(texture.Key) == false) && (texture.FilePath.Contains("textures" + Path.DirectorySeparatorChar + "characterset" + Path.DirectorySeparatorChar)))
                {
                    Image image = Image.FromFile(RawResourceHelper.GetFilePathForTexture(session.WorkingDirectory, texture.FilePath));

                    if ((image.Width % imageWidth == 0) && (image.Height % imageHeight == 0))
                    {
                        for (int x = 0; x < image.Width; x += imageWidth)
                        {
                            for (int y = 0; y < image.Height; y += imageHeight)
                            {
                                maxKey++;

                                CharacterSetDefinition characterSetDefinition = new CharacterSetDefinition()
                                {
                                    Key = maxKey,
                                    TextureKey = texture.Key,
                                    Comment = "NEW"
                                };

                                list.Add(characterSetDefinition);
                            }
                        }
                    }
                }
            }
        }


        private void LoadWorlds(IList<WorldDefinition> list, String csvFile)
        {
            Stream stream = File.OpenRead(session.WorkingDirectory + "\\GameResources\\" + csvFile);
            StreamReader reader = new StreamReader(stream);

            reader.ReadLine();

            string line;
            while ((line = reader.ReadLine()) != null)
            {
                string[] lineContents = line.Split(',');

                WorldDefinition world = new WorldDefinition()
                {
                    Key = Int32.Parse(lineContents[0]),
                    Name = lineContents[1],
                    Filename = lineContents[2],
                    ShowMiniMap = Boolean.Parse(lineContents[3])
                };

                list.Add(world);
            }
            reader.Close();


            //load individual worlds
            foreach(WorldDefinition world in list)
            {
                LoadWorld(world);
            }
        }


        private void LoadWorld(WorldDefinition world)
        {
            Stream stream = File.OpenRead(session.WorkingDirectory + "\\GameResources\\" + world.GetFileName());
            StreamReader reader = new StreamReader(stream);
            
            WorldCellDefinition cell = null;
            Int32 mx = 0;
            Int32 my = 0;

            string line;
            while ((line = reader.ReadLine()) != null)
            {
                if(line.StartsWith("Cell|"))
                {
                    cell = new WorldCellDefinition();
                    world.Cells.Add(cell);

                    String[] lineSplit = line.Split('|');
                    cell.WorldX = Int32.Parse(lineSplit[1]);
                    cell.WorldY = Int32.Parse(lineSplit[2]);
                    cell.SongKey = Int32.Parse(lineSplit[3]);

                    mx = 0;
                    my = 0;
                }
                else if (line.StartsWith("NPC|"))
                {
                    String[] lineSplit = line.Split('|');

                    NonPlayerCharacterDefinition npc = new NonPlayerCharacterDefinition();
                    cell.NPCs.Add(npc);

                    npc.TileX = Int32.Parse(lineSplit[1]);
                    npc.TileY = Int32.Parse(lineSplit[2]);
                    npc.CharacterSetKey = Int32.Parse(lineSplit[3]);
                    npc.ActivationKey = Int32.Parse(lineSplit[4]);
                    npc.MovementKey = Int32.Parse(lineSplit[5]);
                    npc.HideIfVariableTrue = lineSplit[6];
                    npc.ShowIfVariableTrue = lineSplit[7];
                    npc.PlotScriptText = lineSplit[8];
                }
                else if (line.StartsWith("Door|"))
                {
                    String[] lineSplit = line.Split('|');

                    DoorDefinition door = new DoorDefinition();
                    cell.Doors.Add(door);

                    door.X = Int32.Parse(lineSplit[1]);
                    door.Y = Int32.Parse(lineSplit[2]);
                    door.DestinationMapKey = Int32.Parse(lineSplit[3]);
                    door.DestinationCellX = Int32.Parse(lineSplit[4]);
                    door.DestinationCellY = Int32.Parse(lineSplit[5]);
                    door.DestinationTileX = Int32.Parse(lineSplit[6]);
                    door.DestinationTileY = Int32.Parse(lineSplit[7]);
                }
                else if (line.StartsWith("Enemy|"))
                {
                    String[] lineSplit = line.Split('|');

                    EnemyDefinitionPlacement enemyDefinitionPlacement = new EnemyDefinitionPlacement()
                    {
                        Key = Int32.Parse(lineSplit[1]),
                        TileX = Int32.Parse(lineSplit[2]),
                        TileY = Int32.Parse(lineSplit[3])
                    };

                    cell.EnemyDefinitionPlacements.Add(enemyDefinitionPlacement);
                }
                else
                {
                    String[] lineSplit = line.Split(',');

                    mx = 0;
                    foreach(String lineSplitContent in lineSplit)
                    {
                        if(lineSplitContent.Contains("|"))
                        {
                            String[] tiles = lineSplitContent.Split('|');
                            cell.AddTile(mx, my, Int32.Parse(tiles[0]), Int32.Parse(tiles[1]));
                        }
                        else
                        {
                            cell.AddTile(mx, my, Int32.Parse(lineSplitContent), null);
                        }

                        mx++;
                    }

                    my++;
                }
            }
            reader.Close();
        }


        private void LoadPlayer(String csvFile)
        {
            FilePlayerDefinitionRepository repo = new FilePlayerDefinitionRepository(session.WorkingDirectory + "\\GameResources\\" + csvFile);

            session.Player = repo.GetContent(0);
        }


        private void LoadEnemies(IList<EnemyDefinition> list, String csvFile) 
        {
            FileEnemyDefinitionRepository repo = new FileEnemyDefinitionRepository(session.WorkingDirectory + "\\GameResources\\" + csvFile);

            IList<Int32> keys = repo.GetKeys();
            foreach(Int32 key in keys)
            {
                list.Add(repo.GetContent(key));
            }
        }


        private void LoadItems(IList<ItemDefinition> list, String csvFile)
        {
            FileItemDefinitionRepository repo = new FileItemDefinitionRepository(session.WorkingDirectory + "\\GameResources\\" + csvFile);

            IList<Int32> keys = repo.GetKeys();
            foreach (Int32 key in keys)
            {
                list.Add(repo.GetContent(key));
            }
        }


    }
}
