package com.eactive.eai.common.state;

import java.util.concurrent.atomic.AtomicInteger;

import com.eactive.eai.common.util.DatetimeUtil;
import com.eactive.eai.common.util.Logger;

public class ElinkStateManager {
	private static ElinkStateManager instance;
	private volatile ElinkState currentState = ElinkState.STOPPED;
	private AtomicInteger transactionsInProgress = new AtomicInteger(0);
	private long waitMaxMs = 60000;
	private long sleepIntervalMs = 500;

	private static final String LOG_PREFIX = "ElinkStateManager] ";

	private void log(String message) {
		Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
		if (logger != null) {
			logger.warn(message);
		}
		// System.out.println(DatetimeUtil.getCurrentTime() + " " + LOG_PREFIX + message);
	}

	public static synchronized ElinkStateManager getInstance() {
		if (instance == null) {
			instance = new ElinkStateManager();
		}
		return instance;
	}

	public int getTransactionsInProgress() {
		return transactionsInProgress.get();
	}

	public long getWaitMaxMs() {
		return waitMaxMs;
	}

	public void setWaitMaxMs(long waitMaxMs) {
		this.waitMaxMs = waitMaxMs;
	}
	
	public long getSleepIntervalMs() {
		return sleepIntervalMs;
	}

	public void setSleepIntervalMs(long sleepIntervalMs) {
		this.sleepIntervalMs = sleepIntervalMs;
	}

	public void starting() {
		synchronized (this) {
			if (currentState == ElinkState.STOPPED) {
				currentState = ElinkState.STARTING;
				log("Elink starting successfully.");
			} else {
				log("Elink is already started or in the process of starting.");
			}
		}
	}

	public void started() {
		synchronized (this) {
			if (currentState == ElinkState.STARTING) {
				currentState = ElinkState.STARTED;
				log("Elink started successfully.");
			} else {
				log("Elink is already started or in the process of started.");
			}
		}
	}

	public void stop() {
		if (this.waitMaxMs <= 0) {
			log("Elink stopping - transactionsInProgress : " + transactionsInProgress.get() + " waitMaxMs : "
					+ this.waitMaxMs + " sleepIntervalMs : " + this.sleepIntervalMs);
			currentState = ElinkState.STOPPED;
			log("Elink stopped forcely.");
			return;
		}

		log("Elink stopping - transactionsInProgress : " + transactionsInProgress.get() + " waitMaxMs : "
				+ this.waitMaxMs);

		if (currentState == ElinkState.STARTED || currentState == ElinkState.STARTING) {
			currentState = ElinkState.STOPPING;
			long startTime = System.currentTimeMillis();
			while (transactionsInProgress.get() > 0) {
				long elapsedTime = System.currentTimeMillis() - startTime;
				if (elapsedTime >= waitMaxMs) {
					log("Timeout! Unable to stop. Transactions are still in progress. transactionsInProgress: "
							+ transactionsInProgress.get());
					break;
				}
				try {
					log("Elink wait in procress transaction, sleep " + sleepIntervalMs
							+ " msecs. transactionsInProgress : " + transactionsInProgress.get());
					Thread.sleep(sleepIntervalMs);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			currentState = ElinkState.STOPPED;
			log("Elink stopped successfully.");
		} else {
			log("Elink is already stopped or in the process of stopping.");
		}
	}

	public void startRequest() {
		transactionsInProgress.incrementAndGet();
	}

	public void completeRequest() {
		transactionsInProgress.decrementAndGet();
	}

	public ElinkState getState() {
		return currentState;
	}
}
