import java.io.*;
public class SynchLinker extends Linker {
    final static int passive = 0, active = 1;
    int state = active;
    private boolean granted;
    public SynchLinker(String basename, int id, int numProc)
    throws Exception {
        super(basename, id, numProc);
    }
    public synchronized void sendMsg(int destId, String tag,String msg) {
        if (destId < myId) { // big message
            waitForActive();
            super.sendMsg(destId, "app", " ");
            super.sendMsg(destId, tag, msg);
            state = passive;
        } else { // small message
            granted = false;
            super.sendMsg(destId, "request", " ");
            while (!granted) Util.myWait(this);// wait for permission
            super.sendMsg(destId, "app", " ");
            super.sendMsg(destId, tag, msg);
        }
    }
    synchronized void turnActive(){
        state = active; notifyAll();
    }
    synchronized void waitForActive(){
        while (state != active) Util.myWait(this);
    }
    synchronized void grant(){
        granted = true; notifyAll();
    }
    public Msg receiveMsg(int fromId) throws IOException {
        boolean done = false;
        Msg m = null;
        while (!done) { // app msg received
            m = super.receiveMsg(fromId);
            String tag = m.getTag();
            if (tag.equals("app")) {
                if (m.getSrcId() > myId) { // big message
                    waitForActive();
                    m = super.receiveMsg(fromId);
                    super.sendMsg(fromId, "ack", " ");
                } else { // small message
                    m = super.receiveMsg(fromId);
                    turnActive();
                }
                done = true;
            } else if (tag.equals("ack")) turnActive();
            else if (tag.equals("request")) {
                waitForActive();
                super.sendMsg(fromId, "permission", " ");
            } else if (tag.equals("permission")) grant();
        }
        return m;
    }
}