/*
 * Copyright (c) 2012 Philipp Meinen <philipp@bind.ch>
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the Software
 * is furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
 * THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

package ch.bind.philib.lang;

/**
 * @author Philipp Meinen
 */
public final class ServiceState {

	private static final int STATE_UNINITIALIZED = 0;

	private static final int STATE_OPEN = 1;

	private static final int STATE_CLOSING = 2;

	private static final int STATE_CLOSED = 3;

	private volatile int state;

	public boolean isUninitialized() {
		return state == STATE_UNINITIALIZED;
	}

	public boolean isOpen() {
		return state == STATE_OPEN;
	}

	public boolean isClosing() {
		return state == STATE_CLOSING;
	}

	public boolean isClosed() {
		return state == STATE_CLOSED;
	}

	public boolean isClosingOrClosed() {
		return state >= STATE_CLOSING;
	}

	public synchronized void setOpen() {
		switchState(STATE_OPEN);
		notifyAll();
	}

	public synchronized void setClosing() {
		switchState(STATE_CLOSING);
		notifyAll();
	}

	public synchronized void setClosed() {
		switchState(STATE_CLOSED);
		notifyAll();
	}

	public void awaitOpen() throws InterruptedException {
		await(STATE_OPEN);
	}

	public void awaitClosing() throws InterruptedException {
		await(STATE_CLOSING);
	}

	public void awaitClosed() throws InterruptedException {
		await(STATE_CLOSED);
	}

	private synchronized void await(int waitForState) throws InterruptedException {
		while (state < waitForState) {
			wait();
		}
	}

	private void switchState(int newState) {
		if (newState < state) {
			throw new IllegalStateException("service-states can only be moved forward");
		}
		state = newState;
	}
}

@@ -1419,16 +1419,60 @@
 D = 3;%0A%0A
+%09private final Object lock = new Object();%0A%0A
 %09private
@@ -1844,37 +1844,24 @@
 %09%7D%0A%0A%09public 
-synchronized 
 void setOpen
@@ -1897,46 +1897,18 @@
 );%0A%09
-%09notifyAll();%0A%09%7D%0A%0A%09public synchronized
+%7D%0A%0A%09public
  voi
@@ -1959,46 +1959,18 @@
 );%0A%09
-%09notifyAll();%0A%09%7D%0A%0A%09public synchronized
+%7D%0A%0A%09public
  voi
@@ -2018,23 +2018,8 @@
 D);%0A
-%09%09notifyAll();%0A
 %09%7D%0A%0A
@@ -2281,21 +2281,8 @@
 ate 
-synchronized 
 void
@@ -2336,16 +2336,41 @@
 ption %7B%0A
+%09%09synchronized (lock) %7B%0A%09
 %09%09while 
@@ -2401,16 +2401,22 @@
 %0A%09%09%09
+%09
+lock.
 wait();%0A
 %09%09%7D%0A
@@ -2411,16 +2411,21 @@
 wait();%0A
+%09%09%09%7D%0A
 %09%09%7D%0A%09%7D%0A%0A
@@ -2466,16 +2466,41 @@
 tate) %7B%0A
+%09%09synchronized (lock) %7B%0A%09
 %09%09if (ne
@@ -2517,16 +2517,17 @@
 tate) %7B%0A
+%09
 %09%09%09throw
@@ -2600,18 +2600,20 @@
 rd%22);%0A%09%09
+%09
 %7D%0A
+%09
 %09%09state 
@@ -2624,13 +2624,38 @@
 wState;%0A
+%09%09%09lock.notifyAll();%0A%09%09%7D%0A
 %09%7D%0A%7D%0A

use internal locking object