public class DrinkMutex extends Process implements Lock {
    private static final int tranquil = 0, thirsty = 1, drinking = 2;
    boolean bottle[] = null,  requestBottle[] = null, needBottle[] = null;
    DinMutex din;
    int myState = tranquil;
    boolean eating = false;
    public DrinkMutex(Linker initComm) {
        super(initComm);
        din = new DinMutex(initComm); /* create diner instance for each drinker */
        bottle = new boolean[N];
        requestBottle = new boolean[N];
        needBottle = new boolean[N];
        for (int i = 0; i < N; i++) {
            if ((myId > i) && (isNeighbor(i))) {
                bottle[i] = false; requestBottle[i] = true;
            } else {
                bottle[i] = true; requestBottle[i] = false;
            }
        }
    }
    public synchronized void requestCS() {
        myState = thirsty;
        /* following for testing only - pass in required resources array instead */
        needBottle[myId] = true;
        if (haveBottles()) myState = drinking;
        else {
            din.requestCS();            /* force diner to hungry state */
            eating = true;
            for (int i = 0; i < N; i++)
                if (needBottle[i] && requestBottle[i] && !bottle[i]) {
                    sendMsg(i, "Request");
                    requestBottle[i] = false;
                }
                }
        while (myState != drinking) myWait();
    }
    public synchronized void releaseCS() {
        myState = tranquil;
        if (eating) {
                eating = false;
                din.releaseCS();  /* force diner to thinking state */
         }

        for (int i = 0; i < N; i++) {
            needBottle[i] = false;      /* clear required resources array */
            if (requestBottle[i]) {
                                sendMsg(i, "Bottle");
                                bottle[i] = false;
                        }
        }
    }
    boolean haveBottles() {
        for (int i = 0; i < N; i++)
            if (needBottle[i] && !bottle[i]) return false;
        return true;
    }
    public synchronized void handleMsg(Msg m, int source, String tag) {
        if (tag.equals("Request")) {
            requestBottle[source] = true;
            if (!needBottle[source]) {
                                sendMsg(source, "Bottle");
                                bottle[source] = false;
                        }
            else if ((myState != drinking) && !din.fork[source]) {
                                sendMsg(source, "Bottle");
                                bottle[source] = false;
                                if (needBottle[source]){
                    sendMsg(source, "Request");
                    requestBottle[source] = false;
                }
            }
        }
        else if (tag.equals("Bottle")) {
            bottle[source] = true;
            if (haveBottles()) {
                myState = drinking;
                notify();
            }
        }
    }
}