/*
 * Copyright (c) 2017, Terrence Ezrol (ezterry)
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 *
 *  Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

package com.ezrol.terry.minecraft.jsonRecipeEdit.virtualcommandblock;

import com.ezrol.terry.minecraft.jsonRecipeEdit.JSONRecipeEdit;
import net.minecraft.command.ICommandManager;
import net.minecraft.world.World;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.PlayerEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import org.apache.logging.log4j.Level;

import java.util.HashMap;
import java.util.LinkedList;

/**
 * Simulates virtual command block chains
 *
 * Created by ezterry on 2/16/17.
 */
@SuppressWarnings({"WeakerAccess"})
public class VCommandLogic {
    private boolean worldLoaded;
    private ICommandManager cmdManager;
    HashMap<String,LinkedList<VCommandSet>> commandTable; //commands trigger -> list of command sets
    boolean loaded;
    private VCommandTagData tags;

    public VCommandLogic(){
        loaded=false;
        worldLoaded = false;
        commandTable = new HashMap<>();
        tags=new VCommandTagData();
        cmdManager=null;
    }

    public boolean addCommand(VCommandSet c){
        if(c.isValid()){
            if(!loaded){
                loaded = true;
                JSONRecipeEdit.log(Level.INFO,"Registering Tick Event for Virtual Command Chains");
                MinecraftForge.EVENT_BUS.register(this);
            }
            String trigger = c.getTrigger();
            if(!commandTable.containsKey(trigger)){
                commandTable.put(trigger,new LinkedList<VCommandSet>());
            }
            commandTable.get(trigger).addLast(c);
            return true;
        }
        return false;
    }


    public void runTrigger(String t,World w){
        if(cmdManager == null){
            //noinspection ConstantConditions
            cmdManager = w.getMinecraftServer().getCommandManager();
        }
        if(worldLoaded && commandTable.containsKey(t)) {
            int d = w.provider.getDimension();
            for (VCommandSet s : commandTable.get(t)) {
                s.evaluate(cmdManager,w,d);
            }
        }
    }

    public void initTags(World w){
        VCommandTagData data = (VCommandTagData)w.getPerWorldStorage().getOrLoadData(VCommandTagData.class, JSONRecipeEdit.MODID);
        if(data == null) {
            tags=new VCommandTagData();
            w.getPerWorldStorage().setData(JSONRecipeEdit.MODID, tags);
        }
        else
        {
            tags = data;
        }

    }

    public VCommandTagData getTags(){
        return tags;
    }

    private void runServerLoad(World overworld){
        JSONRecipeEdit.log(Level.INFO,"Trigger Server Load Virtual Command Chains");
        runTrigger("ServerStart",overworld);
    }

    public void runServerUnload() {
        this.worldLoaded = false;
        JSONRecipeEdit.log(Level.INFO,"World Unload");
    }

    @SubscribeEvent
    @SuppressWarnings("unused")
    public void onServerWorldTick(TickEvent.WorldTickEvent event){
        if(event.phase == TickEvent.Phase.END){
            return;
        }
        if(event.type != TickEvent.Type.WORLD){
            return;
        }
        int dim = event.world.provider.getDimension();

        //first run of overworld is the world load event
        if(!worldLoaded && dim == 0){
            this.worldLoaded = true;
            runServerLoad(event.world);
        }
        else{
            runTrigger("Always",event.world);
        }
    }

    @SubscribeEvent
    @SuppressWarnings("unused")
    public void onPlayerLoggedIn(PlayerEvent.PlayerLoggedInEvent event){
        World w = event.player.getEntityWorld();
        runTrigger("PlayerJoin",w);
    }
}

@@ -1555,16 +1555,65 @@
 anager;%0A
+import net.minecraft.entity.player.EntityPlayer;%0A
 import n
@@ -2346,16 +2346,61 @@
 ta tags;
+%0A    LinkedList%3CEntityPlayer%3E newPlayerEvent;
 %0A%0A    pu
@@ -2573,16 +2573,59 @@
 r=null;%0A
+        newPlayerEvent=new LinkedList%3C%3E();%0A
     %7D%0A%0A 
@@ -4353,32 +4353,89 @@
 Loaded = false;%0A
+        cmdManager=null;%0A        newPlayerEvent.clear();%0A
         JSONReci
@@ -4622,17 +4622,17 @@
 t.phase 
-=
+!
 = TickEv
@@ -5007,16 +5007,302 @@
   else%7B%0A
+            if(newPlayerEvent.size() %3E 0)%7B%0A                EntityPlayer p = newPlayerEvent.getFirst();%0A%0A                if(p.dimension == dim) %7B%0A                    newPlayerEvent.removeFirst();%0A                    runTrigger(%22PlayerJoin%22, event.world);%0A                %7D%0A            %7D%0A
         
@@ -5493,82 +5493,190 @@
     
-World w = event.player.getEntityWorld();%0A        runTrigger(%22PlayerJoin%22,w
+JSONRecipeEdit.log(Level.INFO,String.format(%22Player %25s Joined in dim %25d%22,%0A                event.player.getName(),event.player.dimension));%0A        newPlayerEvent.addLast(event.player
 );%0A 

Fix Command Chain Caching issue on Loading a second world (ie exiting the game and making a new world) - was due to using a stale command manager from the first instance