package rpgEngine.Logic.Game;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

import rpgEngine.Data.Abstract.Game;
import rpgEngine.Data.Abstract.Item;
import rpgEngine.Data.Abstract.Party.HumanPlayer;
import rpgEngine.Data.Abstract.Party.Inventory;
import rpgEngine.Data.Abstract.Party.InventoryItem;
import rpgEngine.Data.Abstract.Party.Skill;
import rpgEngine.Data.Abstract.World.Map;
import rpgEngine.Resources.GameConfigPool;
import rpgEngine.Resources.HeroPool;
import rpgEngine.Resources.ItemPool;
import rpgEngine.Resources.MapPool;
import rpgEngine.Resources.SkillPool;


public class GameFactory {
	public static final String savePath = ".rpgEngine";
	public static final String saveFileBase = "rpg";
	public static final String saveFileExt = ".sav";
	
	
	public static Game CreateNewGame() {
		Integer key = 0;
		Integer x = 0;
		Integer y = 0;
		HumanPlayer p = null;
		Map m = null;
		Game g = null;
		MusicPlayer mp = null;
		
		//Create Game
		g = new Game();
		
		//Get Player
		key = GameConfigPool.getInstance().getPoolItem(GameConfigPool.ID_STARTING_HERO_ID);
		p = HeroPool.getInstance().getCopyOfItem(key);
		g.getParty().add(p);
				
		//Get Starting Map
		key = GameConfigPool.getInstance().getPoolItem(GameConfigPool.ID_STARTING_MAP_ID);
		m = MapPool.getInstance().getPoolItem(key);
		g.setActiveMap(m);
		
		//Starting Position
		x = GameConfigPool.getInstance().getPoolItem(GameConfigPool.ID_STARTING_MAP_X);
		y = GameConfigPool.getInstance().getPoolItem(GameConfigPool.ID_STARTING_MAP_Y);
		m.getRows().get(y).get(x).setCharacter(p);
		
		//Starting Gold
		key = GameConfigPool.getInstance().getPoolItem(GameConfigPool.ID_STARTING_GOLD);
		g.setGold(key);
						
		//Play Music
		mp = MusicPlayer.getInstance();
		mp.playSound(m.getBackgroundMusic());
		
		return g;
	}
	
	
	public static Boolean doesSaveGameExist(Integer i) {
		String path = "";
		Boolean result = false;
		File file = null;
		
		path = getFilename(i);
		
		try {
			file = new File(path);
			result = file.exists();
		}
		catch(Exception e) {
			result = false;
		}
		
		return result;
	}
	
	
	private static String getFilename(Integer i) {
		String filename = saveFileBase + i.toString() + saveFileExt;
		String homeDir = System.getProperty("user.home");
		String path = "";
		
		path = homeDir + File.separator + savePath + File.separator + filename;
		
		return path;
	}
	
	
	private static String getFolder() {
		String homeDir = System.getProperty("user.home");
		String path = "";
		
		path = homeDir + File.separator + savePath;
		
		return path;
	}
	
	
	public static void saveGame(Integer i, Game g) {
		String filename = "";
		String path = "";
		File file = null;
		FileWriter writer = null;
		File folder = null;
		
		filename = getFilename(i);
		path = getFolder();
		
		try {
			folder = new File(path);
			
			if(folder.exists() == false) {
				folder.mkdir();
			}
			
			file = new File(filename);
			
			if(file.exists()) {
				file.delete();
			}
			
			file.createNewFile();
			
			writer = new FileWriter(file);
			
			//Write Characters
			for(Integer c = 0; c < g.getParty().size(); c++) {
				saveCharacter(writer, g, c);
			}
			
			//Write Inventory
			saveInventory(writer, g);
			
			//Write Game Positions
			saveGameInfo(writer, g);
			
			//Write Variables
			saveVariables(writer, g);
			
			writer.close();
		}
		catch(Exception e) {
			System.err.println("Cannot save file: " + path);
			System.err.println(e.getMessage());
		}
	}
		
	
	private static void saveCharacter(FileWriter w, Game g, Integer c) throws IOException {
		HumanPlayer p = null;
		Skill s = null;
		
		p = g.getParty().get(c);
		
		w.write("-CHARACTER-\n");
		
		w.write("HeroID:" + p.getHeroID() + "\n");
		w.write("Level:" + p.getLevel() + "\n");
		w.write("Name:" + p.getName() + "\n");
		w.write("CurExp:" + p.getExperience() + "\n");
		w.write("ExpToNext:" + p.getExperienceToNextLevel() + "\n");
		w.write("Position:" + p.getCharacterPosition() + "\n");
		
		if(p.getWeapon() != null) {
			w.write("Weapon:" + p.getWeapon().getID() + "\n");
		}
		
		if(p.getHelmet() != null) {
			w.write("Helmet:" + p.getHelmet().getID() + "\n");
		}
		
		if(p.getArmor() != null) {
			w.write("Armor:" + p.getArmor().getID() + "\n");
		}
		
		if(p.getAccessory() != null) {
			w.write("Accessory:" + p.getAccessory().getID() + "\n");
		}
				
		w.write("MaxHP:" + p.getBaseMaxHP() + "\n");
		w.write("HP:" + p.getBaseHP() + "\n");
		w.write("MaxMP:" + p.getBaseMaxMP() + "\n");
		w.write("MP:" + p.getBaseMP() + "\n");
		w.write("Atk:" + p.getBaseAttack() + "\n");
		w.write("Def:" + p.getBaseDefense() + "\n");
		w.write("Mag:" + p.getBaseSkill() + "\n");
		w.write("Bar:" + p.getBaseBarrier() + "\n");
		
		for(Integer i = 0; i < p.getSkills().size(); i++) {
			s = p.getSkills().get(i);
			
			w.write("Skill:" + s.getID() + "\n");
		}
				
		w.write("-END-\n");
	}
	
	
	private static void saveInventory(FileWriter w, Game g) throws IOException  {
		InventoryItem ii = null;
		Inventory inv = null;
		
		w.write("-INVENTORY-\n");
		
		inv = g.getInventory();
		
		for(Integer i = 0; i < inv.getItems().size(); i++) {
			ii = inv.getItems().get(i);
			
			w.write(ii.getItem().getID().toString() + ":" + ii.getQuantity().toString() + "\n");
		}
		
		w.write("-END-\n");
	}

	
	private static void saveGameInfo(FileWriter w, Game g) throws IOException {
		w.write("-INFO-\n");
		
		w.write("ActiveMap:" + g.getActiveMap().getID() + "\n");
		w.write("PosX:" + g.getActiveMap().findCharacter(g.getParty().get(0)).getX() + "\n");
		w.write("PosY:" + g.getActiveMap().findCharacter(g.getParty().get(0)).getY() + "\n");
		w.write("Gold:" + g.getGold() + "\n");
		
		w.write("-END-\n");
	}
	
	
	private static void saveVariables(FileWriter w, Game g) throws IOException {
		w.write("-VARIABLES-\n");
	
		for(Integer i = 0; i < Game.VARIABLE_LIMIT; i++) {
			w.write(i.toString() + ":" + g.getVariable(i).toString() + "\n");
		}
		
		w.write("-END-\n");
	}
	
	
	public static Game loadGame(Integer i) {
		Game g = new Game();
		String path = "";
		File file = null;
		BufferedReader reader = null;
		String line = "";
		
		path = getFilename(i);
		
		try {
			file = new File(path);
			
			reader = new BufferedReader(new FileReader(file));

			while(reader.ready()) {
				line = reader.readLine();
				
				if(line.startsWith("-CHARACTER-")) {
					loadCharacter(reader, g);
				}
				else if(line.startsWith("-INVENTORY-")) {
					loadInventory(reader, g);
				}
				else if(line.startsWith("-INFO-")) {
					loadGameInfo(reader, g);
				}
				else if(line.startsWith("-VARIABLES-")) {
					loadVariables(reader, g);
				}
			}
			
			reader.close();
		}
		catch(Exception e) {
			System.err.println("Cannot load file: " + path);
			System.err.println(e.getMessage());
			
			return GameFactory.CreateNewGame();
		}
		
		//Play Music
		MusicPlayer.getInstance().playSound(g.getActiveMap().getBackgroundMusic());
		
		return g;
	}
	
	
	private static void loadCharacter(BufferedReader r, Game g) throws IOException {
		String line = "";
		String[] columns = null;
				
		Integer intVal = -1;
		HumanPlayer p = null;
		Skill s = null;
		Item item = null;
		
		while(r.ready()) {			
			line = r.readLine();
			
			if(line.equals("-END-")) {
				return;
			}
			else if(line.startsWith("HeroID:")) {
				columns = line.split(":");
				intVal = Integer.valueOf(columns[1]);
				
				p = HeroPool.getInstance().getCopyOfItem(intVal);
				g.getParty().add(p);
			}
			else if(line.startsWith("MaxHP:")) {
				columns = line.split(":");
				intVal = Integer.valueOf(columns[1]);
				p.setMaxHP(intVal);
			}
			else if(line.startsWith("HP:")) {
				columns = line.split(":");
				intVal = Integer.valueOf(columns[1]);
				p.setHP(intVal);
			}
			else if(line.startsWith("MaxMP:")) {
				columns = line.split(":");
				intVal = Integer.valueOf(columns[1]);
				p.setMaxMP(intVal);
			}
			else if(line.startsWith("MP:")) {
				columns = line.split(":");
				intVal = Integer.valueOf(columns[1]);
				p.setMP(intVal);
			}
			else if(line.startsWith("Name")) {
				columns = line.split(":");
				p.setName(columns[1]);
			}
			else if(line.startsWith("Level:")) {
				columns = line.split(":");
				intVal = Integer.valueOf(columns[1]);
				p.setLevel(intVal);
			}
			else if(line.startsWith("CurExp:")) {
				columns = line.split(":");
				intVal = Integer.valueOf(columns[1]);
				p.setExperience(intVal);
			}
			else if(line.startsWith("ExpToNext:")) {
				columns = line.split(":");
				intVal = Integer.valueOf(columns[1]);
				p.setExperienceToNextLevel(intVal);
			}
			else if(line.startsWith("Position:")) {
				columns = line.split(":");
				intVal = Integer.valueOf(columns[1]);
				p.setCharacterPosition(intVal);
			}
			else if(line.startsWith("Skill:")) {
				columns = line.split(":");
				intVal = Integer.valueOf(columns[1]);
				
				s = SkillPool.getInstance().getPoolItem(intVal);
				p.getSkills().add(s);
			}
			else if(line.startsWith("Atk:")) {
				columns = line.split(":");
				intVal = Integer.valueOf(columns[1]);
				p.setAttack(intVal);
			}
			else if(line.startsWith("Def:")) {
				columns = line.split(":");
				intVal = Integer.valueOf(columns[1]);
				p.setDefense(intVal);
			}
			else if(line.startsWith("Mag:")) {
				columns = line.split(":");
				intVal = Integer.valueOf(columns[1]);
				p.setSkill(intVal);
			}
			else if(line.startsWith("Bar:")) {
				columns = line.split(":");
				intVal = Integer.valueOf(columns[1]);
				p.setBarrier(intVal);
			}
			
			else if(line.startsWith("Weapon:")) {
				columns = line.split(":");
				intVal = Integer.valueOf(columns[1]);
				
				item = ItemPool.getInstance().getPoolItem(intVal);
				p.setWeapon(item);
			}
			else if(line.startsWith("Helmet:")) {
				columns = line.split(":");
				intVal = Integer.valueOf(columns[1]);
				
				item = ItemPool.getInstance().getPoolItem(intVal);
				p.setHelmet(item);
			}
			else if(line.startsWith("Armor:")) {
				columns = line.split(":");
				intVal = Integer.valueOf(columns[1]);
				
				item = ItemPool.getInstance().getPoolItem(intVal);
				p.setArmor(item);
			}
			else if(line.startsWith("Accessory:")) {
				columns = line.split(":");
				intVal = Integer.valueOf(columns[1]);
				
				item = ItemPool.getInstance().getPoolItem(intVal);
				p.setAccessory(item);
			}
			
		}
	}
	
	
	private static void loadInventory(BufferedReader r, Game g) throws IOException {
		Item item = null;
		Inventory inv = null;
		String line = "";
		Integer ID = -1;
		Integer qty = 0;
		String[] columns = null;
		
		inv = g.getInventory();
		
		while(r.ready()) {			
			line = r.readLine();
			
			if(line.equals("-END-")) {
				return;
			}
			else {
				columns = line.split(":");
				
				ID = Integer.valueOf(columns[0]);
				qty = Integer.valueOf(columns[1]);
				
				item = ItemPool.getInstance().getPoolItem(ID);
				
				for(Integer i = 0; i < qty; i++) {
					inv.addItemToInventory(item);
				}
			}
		}
	}
	
	
	private static void loadGameInfo(BufferedReader r, Game g) throws IOException {
		String line = "";
		String[] columns = null;
		
		Map m = null;
		HumanPlayer p = null;
		Integer activeMapID = -1;
		Integer posX = -1;
		Integer posY = -1;
		Integer gold = 0;
		
		while(r.ready()) {			
			line = r.readLine();
			
			if(line.equals("-END-")) {
				return;
			}
			else if(line.startsWith("ActiveMap:")) {
				columns = line.split(":");
				
				activeMapID = Integer.valueOf(columns[1]);
				
				g.setActiveMap(MapPool.getInstance().getPoolItem(activeMapID));
			}
			else if(line.startsWith("PosX:")) {
				columns = line.split(":");
				
				posX = Integer.valueOf(columns[1]);
			}
			else if(line.startsWith("PosY:")) {
				columns = line.split(":");
				
				posY = Integer.valueOf(columns[1]);
			}
			else if(line.startsWith("Gold:")) {
				columns = line.split(":");
				
				gold = Integer.valueOf(columns[1]);
				
				g.setGold(gold);
			}
		
			
			if((posX != -1) && (posY != -1)) {
				m = g.getActiveMap();
				p = g.getParty().get(0);
				
				m.getRows().get(posY).get(posX).setCharacter(p);
			}
			
		}
	}
	
	
	private static void loadVariables(BufferedReader r, Game g) throws IOException {
		String line = "";
		Integer ID = -1;
		Boolean value = false;
		String[] columns = null;
		
		
		while(r.ready()) {			
			line = r.readLine();
			
			if(line.equals("-END-")) {
				return;
			}
			else {
				columns = line.split(":");
				
				ID = Integer.valueOf(columns[0]);
				value = Boolean.valueOf(columns[1]);
				
				g.setVariable(ID, value);
			}
		}
	}
	
}
