package de.miaurizius.jgame2d.data;

import de.miaurizius.jgame2d.core.GamePanel;
import de.miaurizius.jgame2d.core.enums.Map;
import de.miaurizius.jgame2d.entity.Entity;

import java.io.*;
import java.lang.reflect.InvocationTargetException;

public class SaveLoad {

    GamePanel panel;

    public SaveLoad(GamePanel panel) {
        this.panel = panel;
    }

    public Entity getObject(String itemName) {
        Entity obj;
        try {
            obj = (Entity) Class.forName(itemName).getDeclaredConstructor(GamePanel.class).newInstance(panel);
        } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException |
                 InvocationTargetException e) {
            throw new RuntimeException(e);
        }
        return obj;
    }

    public void save() throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("gamedata/save/savegame.dat"));
        DataStorage ds = new DataStorage();

        // PLAYER STATS
        ds.level = panel.player.level;
        ds.maxLife = panel.player.maxLife;
        ds.life = panel.player.life;
        ds.maxMana = panel.player.maxMana;
        ds.strength = panel.player.strength;
        ds.dexterity = panel.player.dexterity;
        ds.attack = panel.player.attack;
        ds.defense = panel.player.defense;
        ds.exp = panel.player.exp;
        ds.nextLevelExp = panel.player.nextLevelExp;
        ds.coins = panel.player.coins;
        ds.worldX = panel.player.worldX;
        ds.worldY = panel.player.worldY;

        // PLAYER INVENTORY
        for(int i = 0; i < panel.player.inventory.size(); i++) {
            ds.itemNames.add(panel.player.inventory.get(i).getClass().getName());
            ds.itemAmounts.add(panel.player.inventory.get(i).amt);
        }

        // PLAYER EQUIPMENT
        ds.currentWeaponSlot = panel.player.getCurrentWeaponSlot();
        ds.currentShieldSlot = panel.player.getCurrentShieldSlot();

        // MAP OBJECTS
        ds.mapObjectNames = new String[Map.values().length][panel.obj[1].length];
        ds.mapObjectWorldX = new int[Map.values().length][panel.obj[1].length];
        ds.mapObjectWorldY = new int[Map.values().length][panel.obj[1].length];
        ds.mapObjectLootNames = new String[Map.values().length][panel.obj[1].length];
        ds.mapObjectOpened = new boolean[Map.values().length][panel.obj[1].length];

        for(int mapNum = 0; mapNum < Map.values().length; mapNum++) {
            for(int i = 0; i < panel.obj[mapNum].length; i++) {
                if(panel.obj[mapNum][i] != null) {
                    ds.mapObjectNames[mapNum][i] = panel.obj[mapNum][i].getClass().getName();
                    ds.mapObjectWorldX[mapNum][i] = panel.obj[mapNum][i].worldX;
                    ds.mapObjectWorldY[mapNum][i] = panel.obj[mapNum][i].worldY;
                    if(panel.obj[mapNum][i].loot != null) ds.mapObjectLootNames[mapNum][i] = panel.obj[mapNum][i].loot.getClass().getName();
                    ds.mapObjectOpened[mapNum][i] = panel.obj[mapNum][i].opened;
                } else ds.mapObjectNames[mapNum][i] = "NA";
            }
        }

        // WRITE
        oos.writeObject(ds);
    }

    public void load() throws ClassNotFoundException, IOException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("gamedata/save/savegame.dat"));
        DataStorage ds = (DataStorage) ois.readObject();

        panel.player.level = ds.level;
        panel.player.maxLife = ds.maxLife;
        panel.player.life = ds.life;
        panel.player.maxMana = ds.maxMana;
        panel.player.strength = ds.strength;
        panel.player.dexterity = ds.dexterity;
        panel.player.attack = ds.attack;
        panel.player.defense = ds.defense;
        panel.player.exp = ds.exp;
        panel.player.nextLevelExp = ds.nextLevelExp;
        panel.player.coins = ds.coins;
        panel.player.worldX = ds.worldX;
        panel.player.worldY = ds.worldY;


        // PLAYER INVENTORY
        panel.player.inventory.clear();
        for(int i = 0; i < ds.itemNames.size(); i++) {
            panel.player.inventory.add(getObject(ds.itemNames.get(i)));
            panel.player.inventory.get(i).amt = ds.itemAmounts.get(i);
        }

        // PLAYER EQUIPMENT
        panel.player.currentWeapon = panel.player.inventory.get(ds.currentWeaponSlot);
        panel.player.currentShield = panel.player.inventory.get(ds.currentShieldSlot);
        panel.player.getAttack();
        panel.player.getDefense();
        panel.player.getPlayerAttackImage();

        // MAP OBJECTS
        for(int mapNum = 0; mapNum < Map.values().length; mapNum++) {
            for (int i = 0; i < ds.mapObjectNames[mapNum].length; i++) {
                if (!ds.mapObjectNames[mapNum][i].equals("NA")) {
                    panel.obj[mapNum][i] = getObject(ds.mapObjectNames[mapNum][i]);
                    panel.obj[mapNum][i].worldX = ds.mapObjectWorldX[mapNum][i];
                    panel.obj[mapNum][i].worldY = ds.mapObjectWorldY[mapNum][i];
                    if (ds.mapObjectLootNames[mapNum][i] != null) panel.obj[mapNum][i].loot = getObject(ds.mapObjectLootNames[mapNum][i]);
                    panel.obj[mapNum][i].opened = ds.mapObjectOpened[mapNum][i];
                    if(panel.obj[mapNum][i].opened) panel.obj[mapNum][i].down1 = panel.obj[mapNum][i].image2;
                } else panel.obj[mapNum][i] = null;
            }
        }
    }

}
