using ActionGame.GameResources.Manager;
using ActionGame.GameResources.Models;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;


namespace ActionGame.GameResources.Repository
{
    public class FileWorldMapRepository : IGameContentRepository<WorldMap>
    {
        private IDictionary<Int32, WorldMap> ContentByKey { get; set; }
        private IGameContentManager gameContentManager;
        private IList<Int32> Keys { get; set; }


        public FileWorldMapRepository(IGameContentManager gameContentManager, String filename)
        {
            this.gameContentManager = gameContentManager;

            this.ContentByKey = new Dictionary<Int32, WorldMap>();
            this.Keys = new List<Int32>();

            Load(filename);
        }


        public WorldMap GetContent(Int32 key)
        {
            WorldMap content = null;

            if (this.ContentByKey.ContainsKey(key))
            {
                content = this.ContentByKey[key];
            }

            return content;
        }


        public IList<Int32> GetKeys()
        {
            return this.Keys;
        }


        private void Load(String filename)
        {
            Stream stream = null;
            StreamReader reader = null;
            String line = null;
            String[] lineContents = null;

            stream = File.OpenRead(filename);
            reader = new StreamReader(stream);

            //skip first line
            reader.ReadLine();

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

                if (lineContents[0].Equals("") == false)
                {
                    LoadContent(lineContents);
                }
            }

            reader.Close();
        }


        private void LoadContent(String[] lineContents)
        {
            WorldMap worldMap = null;

            worldMap = new WorldMap()
            {
                Key = Int32.Parse(lineContents[0]),
                Name = lineContents[1],
                ShowMiniMap = Boolean.Parse(lineContents[3])
            };

            //load cells in world map
            String cellsFilename = lineContents[2];
            LoadWorldMapCells(worldMap, cellsFilename);

            this.ContentByKey.Add(worldMap.Key, worldMap);
            this.Keys.Add(worldMap.Key);
        }


        private void LoadWorldMapCells(WorldMap worldMap, String filename)
        {
            WorldMapCell cell = null;
            TileSet tile1 = null;
            TileSet tile2 = null;
            NonPlayerCharacterDefinition npcDef = null;
            DoorDefinition door = null;
            EnemyDefinitionPlacement enemyDefinitionPlacement = null;

            Stream stream = null;
            StreamReader reader = null;
            String line = null;
            String[] lineContents = null;
            String[] layerSplit = null;
            Int32 tileX = 0;
            Int32 tileY = 0;

            stream = File.OpenRead(filename);
            reader = new StreamReader(stream);

            while ((line = reader.ReadLine()) != null)
            {
                if(line.StartsWith("Cell"))
                {
                    lineContents = line.Split('|');

                    cell = new WorldMapCell();
                    cell.WorldMapX = Int32.Parse(lineContents[1]);
                    cell.WorldMapY = Int32.Parse(lineContents[2]);
                    cell.SongKey = Int32.Parse(lineContents[3]);

                    worldMap.AddCell(cell);

                    tileX = 0;
                    tileY = 0;
                }
                else if (line.StartsWith("Door")) 
                {
                    lineContents = line.Split('|');

                    door = new DoorDefinition() {
                        X = Int32.Parse(lineContents[1]),
                        Y = Int32.Parse(lineContents[2]),
                        DestinationMapKey = Int32.Parse(lineContents[3]),
                        DestinationCellX = Int32.Parse(lineContents[4]),
                        DestinationCellY = Int32.Parse(lineContents[5]),
                        DestinationTileX = Int32.Parse(lineContents[6]),
                        DestinationTileY = Int32.Parse(lineContents[7])
                    };

                    cell.DoorDefinitions.Add(door);
                }
                else if (line.StartsWith("NPC"))
                {
                    lineContents = line.Split('|');

                    npcDef = new NonPlayerCharacterDefinition()
                    {
                        TileX = Int32.Parse(lineContents[1]),
                        TileY = Int32.Parse(lineContents[2]),
                        CharacterSetKey = Int32.Parse(lineContents[3]),
                        ActivationKey = Int32.Parse(lineContents[4]),
                        MovementKey = Int32.Parse(lineContents[5]),
                        HideIfVariableTrue = lineContents[6],
                        ShowIfVariableTrue = lineContents[7],
                        PlotScriptText = lineContents[8]
                    };

                    //HACK: Cache plot deserialization (solves map loading lag on first appearance of NPC)
                    JsonConvert.DeserializeObject<List<object>>(lineContents[8]);

                    cell.NonPlayerCharacterDefinitions.Add(npcDef);
                }
                else if (line.StartsWith("Enemy"))
                {
                    lineContents = line.Split('|');

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

                    cell.EnemyDefinitionPlacements.Add(enemyDefinitionPlacement);
                }
                else
                {
                    lineContents = line.Split(',');

                    for(Int32 i = 0; i < lineContents.Length; i++)
                    {
                        if(lineContents[i].Contains("|"))
                        {
                            layerSplit = lineContents[i].Split('|');
                            tile1 = this.gameContentManager.TileSetRepository.GetContent(Int32.Parse(layerSplit[0]));
                            tile2 = this.gameContentManager.TileSetRepository.GetContent(Int32.Parse(layerSplit[1]));
                        }
                        else
                        {
                            tile1 = this.gameContentManager.TileSetRepository.GetContent(Int32.Parse(lineContents[i]));
                            tile2 = null;
                        }

                        cell.AddTile(tileX, tileY, tile1, tile2);

                        tileX++;
                    }

                    tileX = 0;
                    tileY++;
                }
            }

            reader.Close();
        }

    }
}
