package org.bdware.sc.crdt;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

public class SharableVarState {
    private String myId;

    private SharableVarConfiguration sharableVarConfiguration;

    private Integer myIndex;

    // 是reader
    private boolean readerFlag;

    // 是writer
    private boolean writerFlag;

    // 是reader的根结点
    private boolean readerRootFlag;

    // 是writer的根结点
    private boolean writerRootFlag;

    // 作为writer的话，非根节点具有parent。根结点为null
    private String writerParent;

    // 作为reader的话，非叶子节点具有children，叶子节点为null
    private List<String> readerChildren;

    // reader森林的根结点们,用来给writer根结点同步数据用
    private List<String> readerRoots;

    private Long writeInterval;

    private Long readerInterval;

    public SharableVarState(String myId, SharableVarConfiguration sharableVarConfiguration) {
        this.myId = myId;
        this.sharableVarConfiguration = sharableVarConfiguration;
        parseProperties();
    }

    private void parseProperties() {
        for (int i = 0; i < sharableVarConfiguration.getNodeIds().length; i++) {
            if (Objects.equals(sharableVarConfiguration.getNodeIds()[i], myId)) {
                this.myIndex = i;
                break;
            }
        }
        if (this.myIndex == null) {
            return;
        }
        int writerParentIdx = sharableVarConfiguration.writerParents[this.myIndex];
        if (writerParentIdx == -1) {
            writerFlag = true;
            writerRootFlag = true;
        } else if (writerParentIdx >= 0) {
            writerFlag = true;
            writerParent = sharableVarConfiguration.nodeIds[writerParentIdx];
        }

        int readerParentIdx = sharableVarConfiguration.readerParents[this.myIndex];
        if (readerParentIdx == -1) {
            readerFlag = true;
            readerRootFlag = true;
        } else if (readerParentIdx >= 0) {
            readerFlag = true;
        }
        if (readerFlag) {
            readerChildren = new ArrayList<>();
            for (int i = 0; i < sharableVarConfiguration.readerParents.length; i++) {
                if (sharableVarConfiguration.readerParents[i] == myIndex) {
                    readerChildren.add(sharableVarConfiguration.nodeIds[i]);
                }
            }
            readerInterval = sharableVarConfiguration.readerIntervals[myIndex];
        }
        if (writerFlag) {
            writeInterval = sharableVarConfiguration.writerIntervals[myIndex];
        }
        if (writerRootFlag) {
            readerRoots = new ArrayList<>();
            for (int i = 0; i < sharableVarConfiguration.readerParents.length; i++) {
                if (sharableVarConfiguration.readerParents[i] == -1) {
                    readerRoots.add(sharableVarConfiguration.nodeIds[i]);
                }
            }
        }
    }

    public String getMyId() {
        return myId;
    }

    public void setMyId(String myId) {
        this.myId = myId;
    }

    public SharableVarConfiguration getSharableVarConfiguration() {
        return sharableVarConfiguration;
    }

    public void setSharableVarConfiguration(SharableVarConfiguration sharableVarConfiguration) {
        this.sharableVarConfiguration = sharableVarConfiguration;
    }

    public Integer getMyIndex() {
        return myIndex;
    }

    public void setMyIndex(Integer myIndex) {
        this.myIndex = myIndex;
    }

    public boolean isReaderFlag() {
        return readerFlag;
    }

    public void setReaderFlag(boolean readerFlag) {
        this.readerFlag = readerFlag;
    }

    public boolean isWriterFlag() {
        return writerFlag;
    }

    public void setWriterFlag(boolean writerFlag) {
        this.writerFlag = writerFlag;
    }

    public boolean isReaderRootFlag() {
        return readerRootFlag;
    }

    public void setReaderRootFlag(boolean readerRootFlag) {
        this.readerRootFlag = readerRootFlag;
    }

    public boolean isWriterRootFlag() {
        return writerRootFlag;
    }

    public void setWriterRootFlag(boolean writerRootFlag) {
        this.writerRootFlag = writerRootFlag;
    }

    public String getWriterParent() {
        return writerParent;
    }

    public void setWriterParent(String writerParent) {
        this.writerParent = writerParent;
    }

    public List<String> getReaderChildren() {
        return readerChildren;
    }

    public void setReaderChildren(List<String> readerChildren) {
        this.readerChildren = readerChildren;
    }

    public List<String> getReaderRoots() {
        return readerRoots;
    }

    public void setReaderRoots(List<String> readerRoots) {
        this.readerRoots = readerRoots;
    }

    public Long getWriteInterval() {
        return writeInterval;
    }

    public void setWriteInterval(Long writeInterval) {
        this.writeInterval = writeInterval;
    }

    public Long getReaderInterval() {
        return readerInterval;
    }

    public void setReaderInterval(Long readerInterval) {
        this.readerInterval = readerInterval;
    }

    public static class SharableVarConfiguration {
        // ["/bdrepo1/var/0", "/bdrepo1/var/1", "/bdrepo1/var/2", "/bdrepo1/var/3"]
        // 0(w) -> 2(w) -> 1(r) -> 3(r)
        // |
        // 1(w) -

        // ["/bdrepo1/var/0", "/bdrepo1/var/1", "/bdrepo1/var/2", "/bdrepo1/var/3"]
        String[] nodeIds;
        long maxDelay;
        int[] writerIndexes;
        int[] readerIndexes;

        // [2, 2, -1, -2] -2表示该节点为非writer节点，-1表示该结点为writer根结点
        int[] writerParents;
        // [-2, -1, -2, 1] -2表示该节点为非reader节点，-1表示该结点为reader根结点
        int[] readerParents;
        // [5, 5, 6, -1] -1为无需同步
        long[] writerIntervals;
        // [-1, 4, -1, -1]
        long[] readerIntervals;

        public String[] getNodeIds() {
            return nodeIds;
        }

        public void setNodeIds(String[] nodeIds) {
            this.nodeIds = nodeIds;
        }

        public long getMaxDelay() {
            return maxDelay;
        }

        public void setMaxDelay(long maxDelay) {
            this.maxDelay = maxDelay;
        }

        public int[] getWriterIndexes() {
            return writerIndexes;
        }

        public void setWriterIndexes(int[] writerIndexes) {
            this.writerIndexes = writerIndexes;
        }

        public int[] getReaderIndexes() {
            return readerIndexes;
        }

        public void setReaderIndexes(int[] readerIndexes) {
            this.readerIndexes = readerIndexes;
        }

        public int[] getWriterParents() {
            return writerParents;
        }

        public void setWriterParents(int[] writerParents) {
            this.writerParents = writerParents;
        }

        public int[] getReaderParents() {
            return readerParents;
        }

        public void setReaderParents(int[] readerParents) {
            this.readerParents = readerParents;
        }

        public long[] getWriterIntervals() {
            return writerIntervals;
        }

        public void setWriterIntervals(long[] writerIntervals) {
            this.writerIntervals = writerIntervals;
        }

        public long[] getReaderIntervals() {
            return readerIntervals;
        }

        public void setReaderIntervals(long[] readerIntervals) {
            this.readerIntervals = readerIntervals;
        }
    }

    public static void main(String[] args) {
        // ["/bdrepo1/var/0", "/bdrepo1/var/1", "/bdrepo1/var/2", "/bdrepo1/var/3"]
        // 0(w) -> 2(w) -> 1(r) -> 3(r)
        // |
        // 1(w) -


        SharableVarConfiguration sharableVarConfiguration = new SharableVarConfiguration();
        sharableVarConfiguration.setNodeIds(new String[] {"/bdrepo1/var/0", "/bdrepo1/var/1",
                "/bdrepo1/var/2", "/bdrepo1/var/3"});
        sharableVarConfiguration.setWriterParents(new int[] {2, 2, -1, -2});
        sharableVarConfiguration.setReaderParents(new int[] {-2, -1, -2, 1});
        sharableVarConfiguration.setWriterIntervals(new long[] {5, 5, 6, -1});
        sharableVarConfiguration.setReaderIntervals(new long[] {-1, 4, -1, -1});


        SharableVarState sharableVarState0 =
                new SharableVarState("/bdrepo1/var/0", sharableVarConfiguration);
        SharableVarState sharableVarState1 =
                new SharableVarState("/bdrepo1/var/1", sharableVarConfiguration);
        SharableVarState sharableVarState2 =
                new SharableVarState("/bdrepo1/var/2", sharableVarConfiguration);
        SharableVarState sharableVarState3 =
                new SharableVarState("/bdrepo1/var/3", sharableVarConfiguration);
        System.out.println(sharableVarState0);
        System.out.println(sharableVarState1);
        System.out.println(sharableVarState2);
        System.out.println(sharableVarState3);
    }
}
