package be.iminds.ilabt.jfed.highlevel.stitcher;

import java.util.*;

/**
 * StitchingTestSetupConfig
 */
public class StitchingTestSetupConfig {
    public final List<StitchingTestSetupAmConfig> amConfigs;
    public final Set<SpecialCase> specialCases = new HashSet<>();

    public StitchingTestSetupConfig(List<StitchingTestSetupAmConfig> amConfigs, Collection<SpecialCase> specialCases) {
        this.amConfigs = new ArrayList<>(amConfigs);
        this.specialCases.addAll(specialCases);
    }

    public enum SpecialCase { am2DependsOnAm1, hasFakeAm3, am1NoMatchingVlansAm2, scsFailure}

    public enum SpecialReply { ERROR_NO_VLANS, ERROR_ONETIME_GENERIC_ALLOCATE, ERROR_ALLOCATE_ONE_TIMEOUT, ERROR_ALLOCATE_TWO_TIMEOUT, ERROR_ALWAYS_TIMEOUT, FAIL_ONCE_SECOND_STATUS_BANDWIDTH, FAIL_ONCE_SECOND_STATUS_VLAN_UNAVAILABLE, FAIL_ONCE_SECOND_STATUS_GENERICCAUSE, FAIL_ALLWAYS_SECOND_STATUS_VLAN_UNAVAILABLE}

    public static class StitchingTestSetupAmConfig {
        public final int amIndex;

        public final boolean hasV2;
        public final boolean hasV3;
        public final boolean supportsAny;
        public final boolean noStitching; //this AM is in the rspec, but not involved in stitching

        public final Set<SpecialReply> specialReplies;
        /**
         * if true, this AM has an advertisement that contains the actual available VLANs.
         * Note: This only gets added to the Server SpecialCase, which the StitchingDirector uses to determine if it want to use this option. */
        public final boolean advUpToDate;

        public StitchingTestSetupAmConfig(int amIndex,
                                          boolean hasV2, boolean hasV3,
                                          boolean supportsAny,
                                          boolean noStitching,
                                          boolean advUpToDate,
                                          Collection<SpecialReply> specialReplies) {
            this.amIndex = amIndex;
            this.hasV2 = hasV2;
            this.hasV3 = hasV3;
            this.supportsAny = supportsAny;
            this.noStitching = noStitching;
            this.advUpToDate = advUpToDate;
            this.specialReplies = new HashSet<>(specialReplies);
        }

        public boolean hasSpecialReply(SpecialReply specialReply) {
            return specialReplies.contains(specialReply);
        }
    }

    /**
     * @param amIndex index, STARTING FROM 1
     * @return
     */
    public StitchingTestSetupAmConfig am(int amIndex) {
        return amConfigs.get(amIndex-1);
    }

    public int amCount() {
        return amConfigs.size();
    }

    public boolean hasSpecialCase(SpecialCase specialCase) {
        return specialCases.contains(specialCase);
    }

    public boolean hasSpecialReply(int amIndex, StitchingTestSetupConfig.SpecialReply specialReply) {
        assert amIndex > 0;
        assert amIndex <= amConfigs.size();
        return amConfigs.get(amIndex-1).hasSpecialReply(specialReply);
    }

    @Override
    public String toString() {
        String res = "";

        int i = 0;
        for (StitchingTestSetupAmConfig c : amConfigs) {
            res += "am"+(i+1)+" v"+(c.hasV2?"2":"")+(c.hasV3?"3":"")+" "+(c.noStitching?"nostitch":(c.supportsAny?"any":"noany"));
            res += "| ";
            i++;
        }

        int j = 0;
        for (SpecialCase specialCase : specialCases) {
            if (j++ > 0)
                res += " | ";
            switch (specialCase) {
                case am2DependsOnAm1: {
                    res += "dependency: AM2->AM1";
                    break;
                }
                case am1NoMatchingVlansAm2: {
                    res += "AM1 and AM2 have no matching VLANs";
                    break;
                }
                case hasFakeAm3: {
                    res += "fake AM3";
                    break;
                }
                default: {
                    res += specialCase;
                    break;
                }
            }
        }


        return res;
    }
}
