package mcjty.rftools;

import mcjty.rftools.blocks.endergen.EnderMonitorTileEntity;
import mcjty.rftools.blocks.endergen.EndergenicTileEntity;
import mcjty.rftools.blocks.endergen.PearlInjectorTileEntity;
import mcjty.rftools.blocks.logic.sequencer.SequencerTileEntity;
import mcjty.rftools.blocks.logic.timer.TimerTileEntity;

import java.util.ArrayList;
import java.util.List;

public class TickOrderHandler {
    public interface ICheckStateServer {
        void checkStateServer();
        int getDimension();
    }

    private static List<PearlInjectorTileEntity> pearlInjectors = new ArrayList<>();

    private static List<EndergenicTileEntity> connectedEndergenics = new ArrayList<>();
    private static List<EndergenicTileEntity> endergenics = new ArrayList<>();

    private static List<SequencerTileEntity> sequencers = new ArrayList<>();
    private static List<TimerTileEntity> timers = new ArrayList<>();
    private static List<EnderMonitorTileEntity> enderMonitors = new ArrayList<>();

    private TickOrderHandler() {
    }

    public static void queuePearlInjector(PearlInjectorTileEntity pearlInjector) {
        pearlInjectors.add(pearlInjector);

        // Find all connected endergenics in order
        EndergenicTileEntity endergenic = pearlInjector.findEndergenicTileEntity();
        while (endergenic != null && !connectedEndergenics.contains(endergenic)) {
            connectedEndergenics.add(endergenic);
            endergenic = endergenic.getDestinationTE();
        }

    }

    public static void queueEndergenic(EndergenicTileEntity endergenic) {
        endergenics.add(endergenic);
    }

    public static void queueSequencer(SequencerTileEntity sequencer) {
        sequencers.add(sequencer);
    }

    public static void queueTimer(TimerTileEntity timer) {
        timers.add(timer);
    }

    public static void queueEnderMonitor(EnderMonitorTileEntity enderMonitor) {
        enderMonitors.add(enderMonitor);
    }

    private static <T extends ICheckStateServer> List<T> checkStateServer(int dimension, List<T> tileEntities) {
        List<T> remainingTes = new ArrayList<>();
        for (T tileEntity : tileEntities) {
            if (tileEntity.getDimension() == dimension) {
                tileEntity.checkStateServer();
            } else {
                remainingTes.add(tileEntity);
            }
        }
        return remainingTes;
    }

    static void postWorldTick(int dimension) {
        /*
            There is *no* pearl delay between:
            * Pearl Injector -> Endergenic (connected)
            * Endergenic -> Endergenic (connected) *except* for last one to first one (one tick)

            It is possible to have a consistent pearl delay of one tick by reversing the tick order of the
            endergenics, however this slows down the cycle a lot.

            At this point everything else has ticked already, including redstone. If a redstone source entity is now
            ticked *before* its destination entity the delay depends on if there is a direct connection or a redstone
            connection between the blocks. If an redstone source entity is ticked *before* its destination entity the
            delay is always exactly one tick. The tick order was chosen in order for the most common and useful
            combinations to have consistent delay, i.e. one tick.

            There is exactly *one tick* delay between both w/ and w/o redstone between:
            * Ender Monitor -> Pearl Injector, Endergenic, Sequencer, Timer
            * Timer -> Pearl Injector, Endergenic, Sequencer
            * Sequencer -> Pearl Injector, Endergenic

            There is *no* delay w/o redstone and *one tick* delay w/ redstone between:
            * Sequencer -> Timer

            There is *no* delay or *one tick* delay (placement/load order/redstone dependent) between:
            * Sequencer -> Sequencer
            * Timer -> Timer
         */
        pearlInjectors = checkStateServer(dimension, pearlInjectors);

        endergenics.removeAll(connectedEndergenics);

        connectedEndergenics = checkStateServer(dimension, connectedEndergenics); // In order of connection
        endergenics = checkStateServer(dimension, endergenics); // Unconnected

        sequencers = checkStateServer(dimension, sequencers);
        timers = checkStateServer(dimension, timers);
        enderMonitors = checkStateServer(dimension, enderMonitors);
    }
}

@@ -3233,140 +3233,8 @@
 ick.
- The tick order was chosen in order for the most common and useful%0A            combinations to have consistent delay, i.e. one tick.
 %0A%0A  
@@ -3380,26 +3380,8 @@
 enic
-, Sequencer, Timer
 %0A   
@@ -3430,19 +3430,8 @@
 enic
-, Sequencer
 %0A   
@@ -3480,16 +3480,23 @@
 dergenic
+, Timer
 %0A%0A      
@@ -3594,24 +3594,72 @@
   * 
-Sequencer -%3E Tim
+Ender Monitor -%3E Sequencer, Timer%0A            * Timer -%3E Sequenc
 er%0A%0A
@@ -4160,24 +4160,27 @@
         
-sequence
+enderMonito
 rs = che
@@ -4204,24 +4204,27 @@
 ension, 
-sequence
+enderMonito
 rs);%0A   
@@ -4278,35 +4278,32 @@
 s);%0A        
-enderMonito
+sequence
 rs = checkSt
@@ -4319,35 +4319,32 @@
 (dimension, 
-enderMonito
+sequence
 rs);%0A    %7D%0A%7D

Change endergenic tick order to make common setups work