// 
// Decompiled by Procyon v0.6.0
// 

package com.hypixel.hytale.server.core.modules.entity.system;

import com.hypixel.hytale.server.core.modules.entity.EntityModule;
import com.hypixel.hytale.component.ResourceType;
import com.hypixel.hytale.component.Resource;
import com.hypixel.hytale.component.dependency.OrderPriority;
import com.hypixel.hytale.component.system.ISystem;
import com.hypixel.hytale.component.dependency.SystemDependency;
import com.hypixel.hytale.component.dependency.Order;
import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent;
import com.hypixel.hytale.component.RemoveReason;
import com.hypixel.hytale.component.AddReason;
import com.hypixel.hytale.component.Holder;
import com.hypixel.hytale.component.system.HolderSystem;
import com.hypixel.hytale.component.CommandBuffer;
import com.hypixel.hytale.component.ArchetypeChunk;
import com.hypixel.hytale.server.core.modules.entity.component.SnapshotBuffer;
import com.hypixel.hytale.component.query.Query;
import com.hypixel.hytale.server.core.universe.world.World;
import com.hypixel.hytale.component.Store;
import javax.annotation.Nonnull;
import com.hypixel.hytale.component.dependency.RootDependency;
import com.hypixel.hytale.component.dependency.Dependency;
import java.util.Set;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.component.system.tick.EntityTickingSystem;
import java.util.concurrent.TimeUnit;
import com.hypixel.hytale.logger.HytaleLogger;

public class SnapshotSystems
{
    public static long HISTORY_LENGTH_NS;
    private static final HytaleLogger LOGGER;
    
    static {
        SnapshotSystems.HISTORY_LENGTH_NS = TimeUnit.MILLISECONDS.toNanos(500L);
        LOGGER = HytaleLogger.getLogger();
    }
    
    public static class Resize extends EntityTickingSystem<EntityStore>
    {
        @Nonnull
        @Override
        public Set<Dependency<EntityStore>> getDependencies() {
            return RootDependency.firstSet();
        }
        
        @Override
        public void tick(final float dt, final int systemIndex, @Nonnull final Store<EntityStore> store) {
            final World world = store.getExternalData().getWorld();
            final int tickLength = world.getTickStepNanos();
            final SnapshotWorldInfo info = store.getResource(SnapshotWorldInfo.getResourceType());
            if (tickLength == info.tickLengthNanos && SnapshotSystems.HISTORY_LENGTH_NS == info.historyLength) {
                return;
            }
            info.historyLength = SnapshotSystems.HISTORY_LENGTH_NS;
            info.tickLengthNanos = tickLength;
            final int previousHistorySize = info.historySize;
            info.historySize = Math.max(1, (int)((info.historyLength + tickLength - 1L) / tickLength));
            super.tick(dt, systemIndex, store);
        }
        
        @Override
        public Query<EntityStore> getQuery() {
            return SnapshotBuffer.getComponentType();
        }
        
        @Override
        public void tick(final float dt, final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
            final SnapshotWorldInfo info = store.getResource(SnapshotWorldInfo.getResourceType());
            archetypeChunk.getComponent(index, SnapshotBuffer.getComponentType()).resize(info.historySize);
        }
        
        @Override
        public boolean isParallel(final int archetypeChunkSize, final int taskCount) {
            return EntityTickingSystem.maybeUseParallel(archetypeChunkSize, taskCount);
        }
    }
    
    public static class Add extends HolderSystem<EntityStore>
    {
        @Override
        public void onEntityAdd(@Nonnull final Holder<EntityStore> holder, @Nonnull final AddReason reason, @Nonnull final Store<EntityStore> store) {
            final SnapshotBuffer buffer = holder.ensureAndGetComponent(SnapshotBuffer.getComponentType());
            buffer.resize(store.getResource(SnapshotWorldInfo.getResourceType()).historySize);
        }
        
        @Override
        public void onEntityRemoved(@Nonnull final Holder<EntityStore> holder, @Nonnull final RemoveReason reason, @Nonnull final Store<EntityStore> store) {
        }
        
        @Override
        public Query<EntityStore> getQuery() {
            return TransformComponent.getComponentType();
        }
    }
    
    public static class Capture extends EntityTickingSystem<EntityStore>
    {
        private static final Set<Dependency<EntityStore>> DEPENDENCIES;
        @Nonnull
        private final Query<EntityStore> query;
        
        public Capture() {
            this.query = (Query<EntityStore>)Query.and(TransformComponent.getComponentType(), SnapshotBuffer.getComponentType());
        }
        
        @Override
        public void tick(final float dt, final int systemIndex, @Nonnull final Store<EntityStore> store) {
            final SnapshotWorldInfo snapshotWorldInfo;
            final SnapshotWorldInfo info = snapshotWorldInfo = store.getResource(SnapshotWorldInfo.getResourceType());
            ++snapshotWorldInfo.currentTick;
            super.tick(dt, systemIndex, store);
        }
        
        @Override
        public void tick(final float dt, final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
            final SnapshotBuffer buffer = archetypeChunk.getComponent(index, SnapshotBuffer.getComponentType());
            final TransformComponent transform = archetypeChunk.getComponent(index, TransformComponent.getComponentType());
            final SnapshotWorldInfo info = store.getResource(SnapshotWorldInfo.getResourceType());
            buffer.storeSnapshot(info.currentTick, transform.getPosition(), transform.getRotation());
        }
        
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return this.query;
        }
        
        @Nonnull
        @Override
        public Set<Dependency<EntityStore>> getDependencies() {
            return Capture.DEPENDENCIES;
        }
        
        @Override
        public boolean isParallel(final int archetypeChunkSize, final int taskCount) {
            return EntityTickingSystem.maybeUseParallel(archetypeChunkSize, taskCount);
        }
        
        static {
            DEPENDENCIES = Set.of(new SystemDependency(Order.AFTER, (Class<ISystem>)Resize.class), new RootDependency<EntityStore>(OrderPriority.CLOSEST));
        }
    }
    
    public static class SnapshotWorldInfo implements Resource<EntityStore>
    {
        private int tickLengthNanos;
        private long historyLength;
        private int historySize;
        private int currentTick;
        
        public static ResourceType<EntityStore, SnapshotWorldInfo> getResourceType() {
            return EntityModule.get().getSnapshotWorldInfoResourceType();
        }
        
        public SnapshotWorldInfo() {
            this.tickLengthNanos = -1;
            this.historyLength = -1L;
            this.historySize = 1;
            this.currentTick = -1;
        }
        
        public SnapshotWorldInfo(final int tickLengthNanos, final long historyLength, final int historySize, final int currentTick) {
            this.tickLengthNanos = -1;
            this.historyLength = -1L;
            this.historySize = 1;
            this.currentTick = -1;
            this.tickLengthNanos = tickLengthNanos;
            this.historyLength = historyLength;
            this.historySize = historySize;
            this.currentTick = currentTick;
        }
        
        @Nonnull
        @Override
        public Resource<EntityStore> clone() {
            return new SnapshotWorldInfo(this.tickLengthNanos, this.historyLength, this.historySize, this.currentTick);
        }
    }
}
