package com.subgraph.orchid.circuits;

import java.util.Collections;
import java.util.Date;
import java.util.List;

import com.subgraph.orchid.Router;
import com.subgraph.orchid.TorException;
import com.subgraph.orchid.crypto.TorRandom;

public class CircuitStatus {

	enum CircuitState {
		UNCONNECTED("Unconnected"),
		BUILDING("Building"),
		FAILED("Failed"),
		OPEN("Open"),
		DESTROYED("Destroyed");
		String name;
		CircuitState(String name) { this.name = name; }
		public String toString() { return name; }
	}

	private Date timestampCreated;
	private Date timestampDirty;
	private int currentStreamId;
	private Object streamIdLock = new Object();
	private CircuitState state = CircuitState.UNCONNECTED;
	private List<Router> circuitPath = Collections.emptyList();

	CircuitStatus() {
		initializeCurrentStreamId();
	}

	private void initializeCurrentStreamId() {
		final TorRandom random = new TorRandom();
		currentStreamId = random.nextInt(0xFFFF) + 1;
	}

	synchronized void updateCreatedTimestamp() {
		timestampCreated = new Date();
		timestampDirty = null;
	}

	synchronized void updateDirtyTimestamp() {
		if(timestampDirty == null) {
			timestampDirty = new Date();
		}
	}

	synchronized long getMillisecondsElapsedSinceCreated() {
		return millisecondsElapsedSince(timestampCreated);
	}

	synchronized long getMillisecondsDirty() {
		return millisecondsElapsedSince(timestampDirty);
	}

	private static long millisecondsElapsedSince(Date then) {
		if(then == null)
			return 0;
		final Date now = new Date();
		return now.getTime() - then.getTime();
	}

	synchronized boolean isDirty() {
		return timestampDirty != null;
	}

	void setStateBuilding(List<Router> circuitPath) {
		state = CircuitState.BUILDING;
		this.circuitPath = Collections.unmodifiableList(circuitPath);
	}

	Router getFinalRouter() {
		if(state == CircuitState.UNCONNECTED)
			throw new TorException("Cannot retrieve last router from UNCONNECTED circuit");
		if(circuitPath.size() == 0) 
			throw new TorException("No routers on circuit (?!)");
		return circuitPath.get(circuitPath.size() - 1);
	}

	List<Router> getCircuitPath() {
		return circuitPath;
	}

	void setStateFailed() {
		state = CircuitState.FAILED;
	}

	void setStateOpen() {
		state = CircuitState.OPEN;
	}

	void setStateDestroyed() {
		state = CircuitState.DESTROYED;
	}

	boolean isBuilding() {
		return state == CircuitState.BUILDING;
	}

	boolean isConnected() {
		return state == CircuitState.OPEN;
	}

	boolean isUnconnected() {
		return state == CircuitState.UNCONNECTED;
	}

	String getStateAsString() {
		if(state == CircuitState.OPEN) {
			return state.toString() + " ["+ getDirtyString() + "]";
		}
		return state.toString();
	}

	private String getDirtyString() {
		if(!isDirty()) {
			return "Clean";
		} else {
			return "Dirty "+ (getMillisecondsDirty() / 1000) +"s"; 
		}
	}
	int nextStreamId() {
		synchronized(streamIdLock) {
			currentStreamId++;
			if(currentStreamId > 0xFFFF)
				currentStreamId = 1;
			return currentStreamId;
		}
	}

}

@@ -66,31 +66,8 @@
 ns;%0A
-import java.util.Date;%0A
 impo
@@ -489,36 +489,36 @@
  %7D%0A%09%7D%0A%0A%09private 
-Date
+long
  timestampCreate
@@ -529,20 +529,20 @@
 private 
-Date
+long
  timesta
@@ -1004,24 +1004,40 @@
 eated = 
-new Date
+System.currentTimeMillis
 ();%0A%09%09ti
@@ -1051,20 +1051,17 @@
 Dirty = 
-null
+0
 ;%0A%09%7D%0A%0A%09s
@@ -1125,20 +1125,17 @@
 irty == 
-null
+0
 ) %7B%0A%09%09%09t
@@ -1150,24 +1150,40 @@
 Dirty = 
-new Date
+System.currentTimeMillis
 ();%0A%09%09%7D%0A
@@ -1446,20 +1446,20 @@
 edSince(
-Date
+long
  then) %7B
@@ -1476,13 +1476,12 @@
  == 
-null)
+0) %7B
 %0A%09%09%09
@@ -1490,24 +1490,28 @@
 turn 0;%0A
+%09%09%7D%0A
 %09%09final 
 Date now
@@ -1506,70 +1506,66 @@
 nal 
-Date
+long
  now = 
-new Date();%0A%09%09return now.getTime() - then.getTime()
+System.currentTimeMillis();%0A%09%09return now - then
 ;%0A%09%7D
@@ -1631,12 +1631,9 @@
  != 
-null
+0
 ;%0A%09%7D

Use long rather than Date for timestamps