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

package com.hypixel.hytale.server.core.modules.time.commands;

import com.hypixel.hytale.server.core.command.system.basecommands.AbstractCommandCollection;
import com.hypixel.hytale.component.ComponentAccessor;
import com.hypixel.hytale.codec.validation.Validator;
import com.hypixel.hytale.codec.validation.Validators;
import com.hypixel.hytale.server.core.command.system.arguments.types.ArgumentType;
import com.hypixel.hytale.server.core.command.system.arguments.types.ArgTypes;
import com.hypixel.hytale.server.core.command.system.arguments.system.RequiredArg;
import com.hypixel.hytale.server.core.universe.world.commands.worldconfig.WorldConfigPauseTimeCommand;
import it.unimi.dsi.fastutil.floats.Float2FloatFunction;
import java.time.LocalDateTime;
import com.hypixel.hytale.common.util.FormatUtil;
import java.time.temporal.TemporalField;
import java.time.temporal.ChronoField;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.modules.time.WorldTimeResource;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.server.core.universe.world.World;
import javax.annotation.Nonnull;
import com.hypixel.hytale.server.core.command.system.CommandContext;
import com.hypixel.hytale.server.core.command.system.AbstractCommand;
import com.hypixel.hytale.protocol.GameMode;
import com.hypixel.hytale.server.core.command.system.basecommands.AbstractWorldCommand;

public class TimeCommand extends AbstractWorldCommand
{
    public TimeCommand() {
        super("time", "server.commands.time.get.desc");
        this.setPermissionGroup(GameMode.Creative);
        this.addAliases("daytime");
        this.addUsageVariant(new SetTimeHourCommand());
        for (final TimeOfDay value : TimeOfDay.values()) {
            this.addSubCommand(new SetTimePeriodCommand(value));
        }
        this.addSubCommand(new TimeSetSubCommand());
        this.addSubCommand(new TimePauseCommand());
        this.addSubCommand(new TimeDilationCommand());
    }
    
    public void execute(@Nonnull final CommandContext context, @Nonnull final World world, @Nonnull final Store<EntityStore> store) {
        final WorldTimeResource worldTimeResource = store.getResource(WorldTimeResource.getResourceType());
        final LocalDateTime gameDateTime = worldTimeResource.getGameDateTime();
        final Message pausedMessage = Message.translation(world.getWorldConfig().isGameTimePaused() ? "server.commands.time.paused" : "server.commands.time.unpaused");
        final Message message = Message.translation("server.commands.time.info").param("worldName", world.getName()).param("timePaused", pausedMessage);
        context.sendMessage(message.param("time", worldTimeResource.getGameTime().toString()).param("dayOfWeek", FormatUtil.addNumberSuffix(gameDateTime.get(ChronoField.DAY_OF_WEEK))).param("weekOfMonth", FormatUtil.addNumberSuffix(gameDateTime.get(ChronoField.ALIGNED_WEEK_OF_MONTH))).param("weekOfYear", FormatUtil.addNumberSuffix(gameDateTime.get(ChronoField.ALIGNED_WEEK_OF_YEAR))).param("dayOfYear", FormatUtil.addNumberSuffix(gameDateTime.getDayOfYear())).param("moonPhase", FormatUtil.addNumberSuffix(worldTimeResource.getMoonPhase() + 1)));
    }
    
    public enum TimeOfDay
    {
        Dawn(hoursOfDaylight -> (WorldTimeResource.HOURS_PER_DAY - hoursOfDaylight) / 2.0f, new String[] { "day", "morning" }), 
        Midday(hoursOfDaylight -> WorldTimeResource.HOURS_PER_DAY / 2.0f, new String[] { "noon" }), 
        Dusk(hoursOfDaylight -> (WorldTimeResource.HOURS_PER_DAY - hoursOfDaylight) / 2.0f + hoursOfDaylight, new String[] { "night" }), 
        Midnight(hoursOfDaylight -> 0.0f, new String[0]);
        
        @Nonnull
        private final Float2FloatFunction periodFunc;
        private final String[] aliases;
        
        private TimeOfDay(final Float2FloatFunction periodFunc, final String[] aliases) {
            this.periodFunc = periodFunc;
            this.aliases = aliases;
        }
    }
    
    private static class TimePauseCommand extends AbstractWorldCommand
    {
        public TimePauseCommand() {
            super("pause", "server.commands.pausetime.desc");
            this.setPermissionGroup(null);
            this.addAliases("stop");
        }
        
        @Override
        protected void execute(@Nonnull final CommandContext context, @Nonnull final World world, @Nonnull final Store<EntityStore> store) {
            WorldConfigPauseTimeCommand.pauseTime(context.sender(), world, store);
        }
    }
    
    private static class TimeDilationCommand extends AbstractWorldCommand
    {
        private static final float TIME_DILATION_MIN = 0.01f;
        private static final float TIME_DILATION_MAX = 4.0f;
        @Nonnull
        private final RequiredArg<Float> timeDilationArg;
        
        public TimeDilationCommand() {
            super("dilation", "server.commands.time.dilation.desc");
            this.timeDilationArg = (RequiredArg)this.withRequiredArg("timeDilation", "server.commands.time.dilation.timeDilation.desc", ArgTypes.FLOAT).addValidator((Validator<Float>)Validators.greaterThan((DataType)0.01f)).addValidator(Validators.max(4.0f));
            this.setPermissionGroup(null);
        }
        
        @Override
        protected void execute(@Nonnull final CommandContext context, @Nonnull final World world, @Nonnull final Store<EntityStore> store) {
            final float timeDilation = this.timeDilationArg.get(context);
            World.setTimeDilation(timeDilation, store);
            context.sendMessage(Message.translation("server.commands.time.dilation.set.success").param("timeDilation", timeDilation));
        }
    }
    
    private static class TimeSetSubCommand extends AbstractCommandCollection
    {
        public TimeSetSubCommand() {
            super("set", "server.commands.time.set.desc");
            this.setPermissionGroup(null);
            this.addUsageVariant(new SetTimeHourCommand());
            for (final TimeOfDay value : TimeOfDay.values()) {
                this.addSubCommand(new SetTimePeriodCommand(value));
            }
        }
    }
    
    private static class SetTimeHourCommand extends AbstractWorldCommand
    {
        @Nonnull
        private final RequiredArg<Float> timeArg;
        
        public SetTimeHourCommand() {
            super("server.commands.time.set.desc");
            this.timeArg = this.withRequiredArg("time", "server.commands.time.set.timeArg.desc", ArgTypes.FLOAT).addValidator((Validator<Float>)Validators.range(0.0f, (DataType)WorldTimeResource.HOURS_PER_DAY));
            this.setPermissionGroup(null);
        }
        
        @Override
        protected void execute(@Nonnull final CommandContext context, @Nonnull final World world, @Nonnull final Store<EntityStore> store) {
            final float time = this.timeArg.get(context);
            final WorldTimeResource worldTimeResource = store.getResource(WorldTimeResource.getResourceType());
            worldTimeResource.setDayTime(time / WorldTimeResource.HOURS_PER_DAY, world, store);
            context.sendMessage(Message.translation("server.commands.time.set").param("worldName", world.getName()).param("time", worldTimeResource.getGameTime().toString()));
        }
    }
    
    private static class SetTimePeriodCommand extends AbstractWorldCommand
    {
        @Nonnull
        private final TimeOfDay timeOfDay;
        
        public SetTimePeriodCommand(@Nonnull final TimeOfDay timeOfDay) {
            super(timeOfDay.name(), "server.commands.time.period." + timeOfDay.name().toLowerCase() + ".desc");
            this.setPermissionGroup(null);
            this.timeOfDay = timeOfDay;
            this.addAliases(timeOfDay.aliases);
        }
        
        @Override
        protected void execute(@Nonnull final CommandContext context, @Nonnull final World world, @Nonnull final Store<EntityStore> store) {
            final float daylightHours = WorldTimeResource.HOURS_PER_DAY * 0.6f;
            final float periodTime = Math.max(0.0f, this.timeOfDay.periodFunc.apply(daylightHours));
            final WorldTimeResource worldTimeResource = store.getResource(WorldTimeResource.getResourceType());
            worldTimeResource.setDayTime(periodTime / WorldTimeResource.HOURS_PER_DAY, world, store);
            context.sendMessage(Message.translation("server.commands.time.set").param("worldName", world.getName()).param("time", String.format("%s (%s)", worldTimeResource.getGameTime().toString(), this.timeOfDay.name())));
        }
    }
}
