package com.eactive.eai.adapter;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.eactive.eai.common.exception.ExceptionUtil;
import com.eactive.eai.common.lifecycle.Lifecycle;
import com.eactive.eai.common.lifecycle.LifecycleException;
import com.eactive.eai.common.lifecycle.LifecycleListener;
import com.eactive.eai.common.lifecycle.LifecycleSupport;
import com.eactive.eai.common.util.ApplicationContextProvider;
import com.eactive.eai.common.util.Logger;

@Component
public class AdapterPropManager implements Lifecycle {

	static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);

	private LifecycleSupport lifecycle = new LifecycleSupport(this);

	private PropertyChangeSupport property = new PropertyChangeSupport(this);

	private Map<String, AdapterPropGroupVO> groups;

	private boolean started;
	
	@Autowired
	private AdapterPropGroupDAO adapterPropGroupDAO;

	public static AdapterPropManager getInstance() {
		return ApplicationContextProvider.getContext().getBean(AdapterPropManager.class);
	}

	public void addPropertyChangeListener(PropertyChangeListener listener) {
		property.addPropertyChangeListener(listener);
	}

	public void removePropertyChangeListener(PropertyChangeListener listener) {
		property.removePropertyChangeListener(listener);
	}

	private PropertyChangeEvent createEvent(AdapterPropGroupVO source, String propertyName, Object oldValue,
			Object newValue) {
		return new PropertyChangeEvent(source, propertyName, oldValue, newValue);
	}

	public boolean isStarted() {
		return this.started;
	}

	public void start() throws LifecycleException {
		if (started)
			throw new LifecycleException("RECEAICPM201");

		lifecycle.fireLifecycleEvent(STARTING_EVENT, this);

		try {
			init();
		} catch (Exception e) {
			throw new LifecycleException(ExceptionUtil.getErrorCode(e, "RECEAICPM201"));
		}

		started = true;
		if (logger.isWarn()) {
			logger.warn("AdapterPropManager] It is started.");
		}
		lifecycle.fireLifecycleEvent(STARTED_EVENT, this);
	}

	private void init() throws Exception {
		this.groups = adapterPropGroupDAO.getAllProperties();
	}

	public synchronized void reload() throws Exception {
		if (logger.isWarn()) {
			logger.warn("AdapterPropManager] reload all Started ...");
		}
		init();
		if (logger.isWarn()) {
			logger.warn("AdapterPropManager] reload all finished ...");
		}
	}

	public synchronized void reload(String keyName) throws Exception {
		AdapterPropGroupVO vo = adapterPropGroupDAO.getProperties(keyName);
		if (vo != null) {
			this.groups.put(keyName, vo);
		} else {
			throw new Exception("AdapterPropManager not found in Database : key[" + keyName + "]");
		}
	}

	public void stop() throws LifecycleException {
		if (!started)
			throw new LifecycleException("RECEAICPM203");

		lifecycle.fireLifecycleEvent(STOPING_EVENT, this);

		started = false;

		if (logger.isWarn()) {
			logger.warn("AdapterPropManager] It is stopped.");
		}
		lifecycle.fireLifecycleEvent(STOPPED_EVENT, this);
	}

	public void addLifecycleListener(LifecycleListener listener) {
		lifecycle.addLifecycleListener(listener);
	}

	public LifecycleListener[] findLifecycleListeners() {
		return lifecycle.findLifecycleListeners();
	}

	public void removeLifecycleListener(LifecycleListener listener) {
		lifecycle.removeLifecycleListener(listener);
	}

	public void addAdapterPropGroupVO(String name, String description) {
		groups.put(name, new AdapterPropGroupVO(name, description));
	}

	public AdapterPropGroupVO getAdapterPropGroupVO(String name) {
		return groups.get(name);
	}

	public String getProperty(String key) {

		return getProperty(com.eactive.eai.common.server.Keys.DEFAULT_SERVER, key);
	}

	public String getProperty(String group, String key) {
		AdapterPropGroupVO vo = groups.get(group);
		if (vo == null)
			return null;
		return vo.getProperty(key);
	}

	public Properties getProperties(String group) {
		AdapterPropGroupVO vo = groups.get(group);
		if (vo == null)
			throw new RuntimeException("Cannot find the Property Group in AdapterPropManager. - " + group);
		if (vo.getProperties() == null) {
			return new Properties();
		}
		return (Properties) vo.getProperties().clone();
	}

	public void setProperty(String group, String key, String value) {
		AdapterPropGroupVO gvo = groups.get(group);
		String oldValue = gvo.getProperty(key);
		gvo.setProperty(key, value);

		if (oldValue != null && !oldValue.equals(value)) {
			property.firePropertyChange(createEvent(gvo, key, oldValue, value));
		}
	}

	public void setAdapterPropGroupVO(String group, AdapterPropGroupVO vo) {
		groups.put(group, vo);
	}

	public void removeAdapterPropGroupVO(String name) {
		groups.remove(name);
	}

	public String[] getAllPropGroupNames() {
		Iterator<String> it = this.groups.keySet().iterator();
		String[] name = new String[this.groups.size()];
		for (int i = 0; it.hasNext(); i++) {
			name[i] = it.next();
		}

		Arrays.sort(name);
		return name;
	}
}
