/*
 *
 * AttributeMgr
 *
 * Central point for the attribute skill system in the mod
 *
 *
*/

package jesse.keeblarcraft.AttributeMgr;

import java.util.HashMap;
import java.util.Set;

import jesse.keeblarcraft.Keeblarcraft;
import jesse.keeblarcraft.AttributeMgr.AttributeNodes.AbstractNode;
import jesse.keeblarcraft.AttributeMgr.AttributeNodes.AttributeMetalJacket;
import jesse.keeblarcraft.AttributeMgr.AttributeNodes.FactionNodes.FactionBeacon;
import jesse.keeblarcraft.AttributeMgr.AttributeNodes.FactionNodes.FactionFlight;
import jesse.keeblarcraft.AttributeMgr.AttributeNodes.FactionNodes.FactionItemRepair;
import jesse.keeblarcraft.ConfigMgr.ConfigManager;

public class AttributeMgr {
    ConfigManager config;

    // Global list of attributes
    // Key: node title
    // Val: The node class itself
    public static final HashMap<String, Class<? extends AbstractNode>> attributes = new HashMap<String, Class<? extends AbstractNode>>();

    // This is a list of all logged in player tree's. These are kept in memory until either the mod is torn down or
    // players log out for optimization reasons
    public static final HashMap<String, AttributeTree> activeTrees = new HashMap<String, AttributeTree>();

    /////////////////////////////////////////////////////////////////////////////
    /// @fn         RegisterAttributeClass
    ///
    /// @brief      All generic class objects for attributes should be
    ///             registered via this function
    /////////////////////////////////////////////////////////////////////////////
    @SuppressWarnings("deprecation")
    public static void RegisterAttributeClass(Class<? extends AbstractNode> classObj) {
        AbstractNode verifyNode = null;
        try {
            // We spin up an instance of this node; but it will be dead after this function. We need this for name
            verifyNode = classObj.newInstance();
        } catch (Exception e) {
            Keeblarcraft.LOGGER.error("Attempted to assign AbstractNode class type when registering object but could not call .newInstance()! Constructs must be empty");
            e.printStackTrace();
        }

        try {
            if (attributes.containsKey(verifyNode.GetNodeTitle())) {
                Keeblarcraft.LOGGER.warn("Could not register attribute with duplicate name '" + verifyNode.GetNodeTitle() + "'");
            } else {
                Keeblarcraft.LOGGER.debug("REGISTERING ATTRIBUTE: " + verifyNode.GetNodeTitle());
                attributes.put(verifyNode.GetNodeTitle(), classObj);
            }
        } catch (Exception e) {} // Left empty since previous try-catch will throw error-message
    }

    /////////////////////////////////////////////////////////////////////////////
    /// @fn         ApplyAttribute
    ///
    /// @arg[in]    uuid is the players uuid
    ///
    /// @arg[in]    attributeName is the node title of the attribute class object
    ///
    /// @brief      Used to apply an attribute to a player's attribute tree
    /////////////////////////////////////////////////////////////////////////////
    @SuppressWarnings("deprecation")
    public static String ApplyAttribute(String uuid, String attributeName) {
        String msg = "";
        // System.out.println("ApplyAttribute debug. UUID - NAME: " + uuid + " - " + attributeName);

        // Set<String> keys = attributes.keySet();
        // for (String key : keys) {
        //     System.out.println("ATTRI: " + key);
        // }

        // System.out.println("ACTIVE TREES: ");
        // Set<String> names = activeTrees.keySet();
        // for (String name : names) {
        //     System.out.println("N: " + name);
        // }

        if (attributes.containsKey(attributeName)) {
            AttributeTree playerTree = activeTrees.get(uuid);
            AbstractNode node = null;
            try {
                node = attributes.get(attributeName).newInstance();
            } catch (Exception e) {
                Keeblarcraft.LOGGER.error("Could not successfully apply attribute. String of attribute name could not be successfully cast to actual java object");
            }

            // System.out.println("Is player tree null: " + (playerTree == null ? "YES" : "NO"));
            // System.out.println("Is player node null: " + (node == null ? "YES" : "NO"));

            // if (playerTree != null) {
            //     System.out.println("Does player have skill: " + (playerTree.ContainsAttribute(attributeName) ? "YES" : "NO"));
            // }

            // Ensure player tree isn't null; node isn't null; and the player doesn't already have this attribute
            if (playerTree != null && node != null && !playerTree.ContainsAttribute(attributeName)) {
                ///////////
                // debug testing
                String isNull = (node == null ? "NULL" : "NOT NULL");
                System.out.println("Node is " + isNull);
                if (isNull.equals("NOT NULL")) { System.out.println("Node name: " + node.GetNodeTitle()); }
                // end debug testing
                ///////////

                playerTree.AddNewNode(node, 1, null, null);
                msg = "Applied attribute '" + attributeName + "' successfully";
            } else {
                msg = "Player tree not found!";
                // String debug = "PlayerTree is null";
                // if (playerTree != null) {
                //     debug = playerTree.ContainsAttribute(attributeName) ? "YES":"NO";
                // }
                // System.out.println("APPLY ATTRIBUTE FAIL: TREE NULL, NODE NULL, OR PLAYER ALREADY HAS THIS ATTRIBUTE (DO THEY? " + debug + ")");
            }
        } else {
            msg = "Could not apply attribute, attribute name does not exist!";
            System.out.println("Attribute does not exist!");
        }
        return msg;
    }

    // Deletes an attribute from the node tree
    public static void DisableAttribute(String uuid, String attributeName) {
        if (activeTrees.containsKey(uuid) && activeTrees.get(uuid).ContainsAttribute(attributeName)) {
            activeTrees.get(uuid).DeleteNode(attributeName);
        }
    }

    /////////////////////////////////////////////////////////////////////////////
    /// @fn         RegisterAttributes
    ///
    /// @brief      This registers all attribute classes to the global attribute
    ///             class. Individual classes can be added here that call the
    ///             more braod "RegisterAttributeClass"
    ///             @see RegisterAttributeClass
    /////////////////////////////////////////////////////////////////////////////
    public static void RegisterAttributes() {
        // Manually register all attribute node classes here
        /// TODO: Find a better way to do this more dynamically in the future
        /// hint: make it an API for other modders to add to

        RegisterAttributeClass(AttributeMetalJacket.class);
        RegisterAttributeClass(FactionBeacon.class);
        RegisterAttributeClass(FactionFlight.class);
        RegisterAttributeClass(FactionItemRepair.class);
    }
}
