package org.egordorichev.lasttry.world.chunk.gc;

import org.egordorichev.lasttry.Globals;
import org.egordorichev.lasttry.LastTry;
import org.egordorichev.lasttry.util.Log;
import org.egordorichev.lasttry.world.chunk.Chunk;

import java.lang.reflect.Array;
import java.util.*;

//Logic responsible for carrying out chunk gc
public class ChunkGc {

    private ChunkGcCalc.ChunkGCLevel currentChunkGcLevel;

    ChunkGc(ChunkGcCalc.ChunkGCLevel levelToRunChunkGcAt) {
        this.currentChunkGcLevel = levelToRunChunkGcAt;
    }

    public void performChunkGC() {

        Log.debug("Received request to perform Chunk GC");

        assert Globals.world.chunks.getImmutableLoadedChunks().size()<=ChunkGcCalc.MINIMUMLOADEDCHUNKS : "Chunks currently loaded is less than or equal to minimum loaded chunks";

        //Set flag in gc manager, signalling a chunk gc is in progress
        setChunkGcInProgressFlag(true);

        List<Chunk> loadedChunks = Globals.world.chunks.getImmutableLoadedChunks();
        Log.debug("Amount of loaded chunks is: "+loadedChunks.size());

        ArrayList<UUID> uniqueIdsOfChunksToBeFreed = this.getUniqueIdsOfChunksToBeFreed(loadedChunks);

        freeChunks(uniqueIdsOfChunksToBeFreed);

        finish();

    }

    private void setChunkGcInProgressFlag(boolean Flag) {
        Globals.chunkGcManager.setChunkGcInProgress(true);
    }

    private ArrayList<UUID> getUniqueIdsOfChunksToBeFreed(List<Chunk> loadedChunks) {
        // Sort by local date, most recent date is last and oldest date is first.
        Collections.sort(loadedChunks, new Comparator<Chunk>() {
            public int compare(Chunk one, Chunk other) {
                return one.getLastAccessedTime().compareTo(other.getLastAccessedTime());
            }
        });

        int amountOfChunksToFree = currentChunkGcLevel.getChunksToFree();
        Log.debug("Amount of loaded chunks to free is: "+amountOfChunksToFree);

        ArrayList<UUID> uniqueIdsOfChunksToBeFreed = new ArrayList<>();

        //We remove the oldest chunk, which will be the first chunks.
        for(int i=0; i<amountOfChunksToFree; i++){
            Chunk chunkToBeFreed = loadedChunks.get(i);
            uniqueIdsOfChunksToBeFreed.add(chunkToBeFreed.getUniqueChunkId());
        }

        return uniqueIdsOfChunksToBeFreed;
    }

    private void freeChunks(List<UUID> idsOfChunksToBeFreed) {
        //free chunks
        idsOfChunksToBeFreed.stream().forEach(uniqueIdOfChunkToBeFreed -> {
            Globals.world.chunks.removeChunk(uniqueIdOfChunkToBeFreed);
        });
    }

    private void finish() {
        setChunkGcInProgressFlag(true);

        //Schedule next chunk gc
        Globals.chunkGcManager.requestFutureChunkGc();
    }

}

@@ -632,288 +632,21 @@
     
-assert Globals.world.chunks.getImmutableLoadedChunks().size()%3C=ChunkGcCalc.MINIMUMLOADEDCHUNKS : %22Chunks currently loaded is less than or equal to minimum loaded chunks%22;%0A%0A        //Set flag in gc manager, signalling a chunk gc is in progress%0A        setChunkGcInProgressFlag(true
+this.startUp(
 );%0A%0A
@@ -1194,324 +1194,50 @@
 ) %7B%0A
-        // Sort by local date, most recent date is last and oldest date is first.%0A        Collections.sort(loadedChunks, new Comparator%3CChunk%3E() %7B%0A            public int compare(Chunk one, Chunk other) %7B%0A                return one.getLastAccessedTime().compareTo(other.getLastAccessedTime());%0A            %7D%0A        %7D
+%0A        this.sortBasedOnDate(loadedChunks
 );%0A%0A
@@ -1459,24 +1459,32 @@
 ayList%3C%3E();%0A
+        
 %0A        //W
@@ -2062,145 +2062,861 @@
 oid 
-finish() %7B%0A        setChunkGcInProgressFlag(true);%0A%0A        //Schedule next chunk gc%0A        Globals.chunkGcManager.requestFutureChunkGc(
+startUp() %7B%0A%0A        assert Globals.world.chunks.getImmutableLoadedChunks().size()%3C=ChunkGcCalc.MINIMUMLOADEDCHUNKS : %22Chunks currently loaded is less than or equal to minimum loaded chunks%22;%0A%0A        //Set flag in gc manager, signalling a chunk gc is in progress%0A        setChunkGcInProgressFlag(true);%0A%0A    %7D%0A%0A    private void finish() %7B%0A        setChunkGcInProgressFlag(true);%0A%0A        //Schedule next chunk gc%0A        Globals.chunkGcManager.requestFutureChunkGc();%0A    %7D%0A%0A    private void sortBasedOnDate(List%3CChunk%3E loadedChunks) %7B%0A        // Sort by local date, most recent date is last and oldest date is first.%0A        Collections.sort(loadedChunks, new Comparator%3CChunk%3E() %7B%0A            public int compare(Chunk one, Chunk other) %7B%0A                return one.getLastAccessedTime().compareTo(other.getLastAccessedTime());%0A            %7D%0A        %7D
 );%0A 

Splitting into smaller methods