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

package com.hypixel.hytale.common.semver;

import java.util.function.Function;
import com.hypixel.hytale.codec.function.FunctionCodec;
import java.util.Arrays;
import javax.annotation.Nullable;
import java.util.Objects;
import com.hypixel.hytale.common.util.StringUtil;
import javax.annotation.Nonnull;
import com.hypixel.hytale.codec.Codec;

public class Semver implements Comparable<Semver>
{
    public static final Codec<Semver> CODEC;
    private final long major;
    private final long minor;
    private final long patch;
    private final String[] preRelease;
    private final String build;
    
    public Semver(final long major, final long minor, final long patch) {
        this(major, minor, patch, null, null);
    }
    
    public Semver(final long major, final long minor, final long patch, final String[] preRelease, final String build) {
        if (major < 0L) {
            throw new IllegalArgumentException("Major must be a non-negative integers");
        }
        if (minor < 0L) {
            throw new IllegalArgumentException("Major must be a non-negative integers");
        }
        if (patch < 0L) {
            throw new IllegalArgumentException("Major must be a non-negative integers");
        }
        validatePreRelease(preRelease);
        validateBuild(build);
        this.major = major;
        this.minor = minor;
        this.patch = patch;
        this.preRelease = preRelease;
        this.build = build;
    }
    
    public long getMajor() {
        return this.major;
    }
    
    public long getMinor() {
        return this.minor;
    }
    
    public long getPatch() {
        return this.patch;
    }
    
    public String[] getPreRelease() {
        return this.preRelease.clone();
    }
    
    public String getBuild() {
        return this.build;
    }
    
    public boolean satisfies(@Nonnull final SemverRange range) {
        return range.satisfies(this);
    }
    
    @Override
    public int compareTo(@Nonnull final Semver other) {
        if (this.major != other.major) {
            return Long.compare(this.major, other.major);
        }
        if (this.minor != other.minor) {
            return Long.compare(this.minor, other.minor);
        }
        if (this.patch != other.patch) {
            return Long.compare(this.patch, other.patch);
        }
        if (this.preRelease != null && (other.preRelease == null || other.preRelease.length == 0)) {
            return -1;
        }
        if ((this.preRelease == null || this.preRelease.length == 0) && other.preRelease != null) {
            return 1;
        }
        if (this.preRelease == null) {
            return 0;
        }
        int i;
        for (i = 0; i < this.preRelease.length && i < other.preRelease.length; ++i) {
            final String pre = this.preRelease[i];
            final String otherPre = other.preRelease[i];
            if (StringUtil.isNumericString(pre) && StringUtil.isNumericString(otherPre)) {
                final int compare = Integer.compare(Integer.parseInt(pre), Integer.parseInt(otherPre));
                if (compare != 0) {
                    return compare;
                }
            }
            else {
                final int compare = pre.compareTo(otherPre);
                if (compare != 0) {
                    return compare;
                }
            }
        }
        if (this.preRelease.length > i) {
            return 1;
        }
        if (other.preRelease.length > i) {
            return -1;
        }
        return 0;
    }
    
    @Nonnull
    @Override
    public String toString() {
        final StringBuilder ver = new StringBuilder().append(this.major).append('.').append(this.minor).append('.').append(this.patch);
        if (this.preRelease != null && this.preRelease.length > 0) {
            ver.append('-').append(String.join(".", (CharSequence[])this.preRelease));
        }
        if (this.build != null && !this.build.isEmpty()) {
            ver.append('+').append(this.build);
        }
        return ver.toString();
    }
    
    @Nonnull
    public static Semver fromString(final String str) {
        return fromString(str, false);
    }
    
    @Nonnull
    public static Semver fromString(String str, final boolean strict) {
        Objects.requireNonNull(str, "String can't be null!");
        str = str.trim();
        if (str.isEmpty()) {
            throw new IllegalArgumentException("String is empty!");
        }
        if (str.charAt(0) == '=' || str.charAt(0) == 'v') {
            str = str.substring(1);
        }
        if (str.charAt(0) == '=' || str.charAt(0) == 'v') {
            str = str.substring(1);
        }
        str = str.trim();
        if (str.isEmpty()) {
            throw new IllegalArgumentException("String is empty!");
        }
        String build = null;
        if (str.contains("+")) {
            final String[] buildSplit = str.split("\\+", 2);
            str = buildSplit[0];
            build = buildSplit[1];
            validateBuild(build);
        }
        String[] preRelease = null;
        if (str.contains("-")) {
            final String[] preReleaseSplit = str.split("-", 2);
            str = preReleaseSplit[0];
            preRelease = preReleaseSplit[1].split("\\.");
            validatePreRelease(preRelease);
        }
        if (!str.isEmpty() && (str.charAt(0) == '.' || str.charAt(str.length() - 1) == '.')) {
            throw new IllegalArgumentException("Failed to parse digits (" + str);
        }
        final String[] split = str.split("\\.");
        if (split.length < 1) {
            throw new IllegalArgumentException("String doesn't match <major>.<minor>.<patch> (" + str);
        }
        final long major = Long.parseLong(split[0]);
        if (major < 0L) {
            throw new IllegalArgumentException("Major must be a non-negative integers (" + str);
        }
        if (!strict && split.length == 1) {
            return new Semver(major, 0L, 0L, preRelease, build);
        }
        if (split.length < 2) {
            throw new IllegalArgumentException("String doesn't match <major>.<minor>.<patch> (" + str);
        }
        final long minor = Long.parseLong(split[1]);
        if (minor < 0L) {
            throw new IllegalArgumentException("Minor must be a non-negative integers (" + str);
        }
        if (!strict && split.length == 2) {
            return new Semver(major, minor, 0L, preRelease, build);
        }
        if (split.length != 3) {
            throw new IllegalArgumentException("String doesn't match <major>.<minor>.<patch> (" + str);
        }
        String patchStr = split[2];
        if (!strict && preRelease == null) {
            String pre = "";
            final StringBuilder s = new StringBuilder();
            for (int i = 0; i < patchStr.length(); ++i) {
                final char c = patchStr.charAt(i);
                if (!Character.isDigit(c)) {
                    pre = patchStr.substring(i);
                    patchStr = s.toString();
                    break;
                }
                s.append(c);
            }
            if (!pre.trim().isEmpty()) {
                preRelease = pre.split("\\.");
                validatePreRelease(preRelease);
            }
        }
        final long patch = Long.parseLong(patchStr);
        if (patch < 0L) {
            throw new IllegalArgumentException("Patch must be a non-negative integers (" + str);
        }
        return new Semver(major, minor, patch, preRelease, build);
    }
    
    private static void validateBuild(@Nullable final String build) {
        if (build == null) {
            return;
        }
        if (build.isEmpty() || !StringUtil.isAlphaNumericHyphenString(build)) {
            throw new IllegalArgumentException("Build must only be alphanumeric (" + build);
        }
    }
    
    private static void validatePreRelease(@Nullable final String[] preRelease) {
        if (preRelease == null) {
            return;
        }
        for (final String preReleasePart : preRelease) {
            if (preReleasePart.isEmpty() || !StringUtil.isAlphaNumericHyphenString(preReleasePart)) {
                throw new IllegalArgumentException("Pre-release must only be alphanumeric (" + Arrays.toString(preRelease));
            }
        }
    }
    
    static {
        CODEC = new FunctionCodec<Object, Semver>(Codec.STRING, Semver::fromString, Semver::toString);
    }
}
