001/*
002 * PermissionsEx
003 * Copyright (C) zml and PermissionsEx contributors
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *    http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package ca.stellardrift.permissionsex.impl.context;
018
019import ca.stellardrift.permissionsex.impl.config.PermissionsExConfiguration;
020import ca.stellardrift.permissionsex.subject.CalculatedSubject;
021import org.checkerframework.checker.nullness.qual.Nullable;
022
023import java.time.ZoneId;
024import java.time.ZonedDateTime;
025import java.time.format.DateTimeFormatter;
026import java.time.temporal.ChronoUnit;
027import java.util.function.BiPredicate;
028import java.util.function.Consumer;
029
030public final class TimeContextDefinition extends PEXContextDefinition<ZonedDateTime>  {
031    public static final TimeContextDefinition BEFORE_TIME = new TimeContextDefinition("before-time", ZonedDateTime::isBefore);
032    public static final TimeContextDefinition AFTER_TIME = new TimeContextDefinition("after-time", ZonedDateTime::isAfter);
033
034    private final ZoneId currentTimeZone = ZoneId.systemDefault();
035    private final TimeContextParser[] timeParsers = TimeContextParser.parsersForZone(currentTimeZone);
036    private final BiPredicate<ZonedDateTime, ZonedDateTime> comparisonFunc;
037
038    private TimeContextDefinition(final String name, final BiPredicate<ZonedDateTime, ZonedDateTime> comparisonFunc) {
039        super(name);
040        this.comparisonFunc = comparisonFunc;
041    }
042
043    // Perform a comparison with second precision
044    static boolean compare(final ZonedDateTime a, final ZonedDateTime b, final BiPredicate<ZonedDateTime, ZonedDateTime> test) {
045        return test.test(a.truncatedTo(ChronoUnit.SECONDS), b.truncatedTo(ChronoUnit.SECONDS));
046    }
047
048    @Override
049    public String serialize(final ZonedDateTime canonicalValue) {
050        return canonicalValue.format(DateTimeFormatter.ISO_DATE_TIME);
051    }
052
053    @Override
054    public @Nullable ZonedDateTime deserialize(final String userValue) {
055        @Nullable ZonedDateTime attempt;
056        for (final TimeContextParser parser : this.timeParsers) {
057            attempt = parser.parse(userValue);
058            if (attempt != null) {
059                return attempt;
060            }
061        }
062
063        return null;
064        // throw new IllegalArgumentException("Could not deserialize time from input " + userValue + " using any known methods.");
065    }
066
067    @Override
068    public boolean matches(final ZonedDateTime ownVal, final ZonedDateTime testVal) {
069        return compare(testVal, ownVal, this.comparisonFunc);
070    }
071
072    @Override
073    public void accumulateCurrentValues(final CalculatedSubject subject, final Consumer<ZonedDateTime> consumer) {
074        consumer.accept(ZonedDateTime.now(this.currentTimeZone).truncatedTo(ChronoUnit.SECONDS));
075    }
076
077    @Override
078    public void update(PermissionsExConfiguration<?> config) {
079        // TODO: Update timezone from configuration
080    }
081}