package com.eactive.eai.adapter;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.eactive.eai.common.dao.DAOException;
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 AdapterManager implements Lifecycle {

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

	private boolean started;

	private HashMap<String, AdapterGroupVO> adapterGroups = new HashMap<>();

	private LifecycleSupport lifecycle = new LifecycleSupport(this);
	
	@Autowired
	private AdapterDAO adapterDAO;

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

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

		lifecycle.fireLifecycleEvent(STARTING_EVENT, this);

		this.adapterGroups.clear();

		List<AdapterGroupVO> groups = null;
		try {
			adapterDAO = ApplicationContextProvider.getContext().getBean(AdapterDAO.class);
			groups = adapterDAO.getAllAdapterGroups();
		} catch (Exception e) {
			throw new LifecycleException(ExceptionUtil.getErrorCode(e, "RECEAIAAC016"));
		}

		for (AdapterGroupVO gvo : groups) {
			List<AdapterVO> adapterVos = null;
			try {
				adapterVos = adapterDAO.getAllAdapters(gvo.getName());
				for (AdapterVO vo : adapterVos) {
					gvo.addAdapterVO(vo);
				}
			} catch (DAOException e) {
				if (logger.isError())
					logger.error(ExceptionUtil.getErrorCode(e, "RECEAIAAC017"));
				continue;
			}

			if (logger.isDebug()) {
				String[] msgArgs = new String[1];
				msgArgs[0] = gvo.toString();
				logger.debug(ExceptionUtil.make("RDCEAIAAC018", msgArgs));
			}
			addAdapterGroupVO(gvo);

			try {
				LifecycleListener[] listeners = this.lifecycle.findLifecycleListeners();
				if (listeners != null) {
					for (int j = 0; j < listeners.length; j++) {
						gvo.addLifecycleListener(listeners[j]);
					}
				}

				if (!gvo.isUsedFlag()) {
					if (logger.isDebug())
						logger.debug("Not Used Adapter>> " + gvo);
					continue;
				}
				gvo.start();
			} catch (Exception e) {
				if (logger.isError())
					logger.error(ExceptionUtil.getErrorCode(e, "RECEAIAAC019"));
			}
		}
		started = true;
		lifecycle.fireLifecycleEvent(STARTED_EVENT, this);
	}

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

		lifecycle.fireLifecycleEvent(STOPING_EVENT, this);

		logger.warn("Stop Inbound Adapters ...");
		for (Iterator<AdapterGroupVO> it = this.adapterGroups.values().iterator(); it.hasNext();) {
			AdapterGroupVO vo = it.next();
			if ("I".equals(vo.getGubun())) {
				try {
					if (!vo.isStarted()) {
						logger.warn("AdapterGroup not started skip stop. - " + vo);
						continue;
					}
					if (vo instanceof Lifecycle) {
						vo.stop();
					}
				} catch (LifecycleException e) {
					String[] msgArgs = { vo.toString() };
					String errText = ExceptionUtil.make("RECEAIAAC021", msgArgs);
					if (logger.isError())
						logger.error(errText);
				}
			}
		}

		logger.warn("Stop Outbound Adapters ...");
		for (Iterator<AdapterGroupVO> it = this.adapterGroups.values().iterator(); it.hasNext();) {
			AdapterGroupVO vo = it.next();
			if (!"I".equals(vo.getGubun())) {
				try {
					if (!vo.isStarted())
						continue;
					if (vo instanceof Lifecycle) {
						vo.stop();
					}
				} catch (LifecycleException e) {
					String[] msgArgs = new String[1];
					msgArgs[0] = vo.toString();
					String errText = ExceptionUtil.make("RECEAIAAC021", msgArgs);
					if (logger.isError())
						logger.error(errText);
				}
			}
		}

		started = false;
		lifecycle.fireLifecycleEvent(STOPPED_EVENT, this);
	}

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

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

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

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

	public AdapterVO getAdapterVO(String adapterGroupName, String adapterName) {
		if(StringUtils.isAnyBlank(adapterGroupName, adapterName))
			return null;
			
		AdapterGroupVO gvo = adapterGroups.get(adapterGroupName);
		if (gvo == null)
			return null;
		return gvo.getAdapterVO(adapterName);
	}

	public AdapterGroupVO getAdapterGroupVO(String adapterGroupName) {
		return adapterGroups.get(adapterGroupName);
	}
	
	public AdapterGroupVO getAdapterGroup(String adapterGroupName) throws DAOException {
		return adapterGroups.get(adapterGroupName);
	}
	
	public AdapterGroupVO loadAdapterGroup(String adapterGroupName) throws DAOException {
		return adapterDAO.getAdapterGroup(adapterGroupName);
	}

	public void addAdapterGroupVO(AdapterGroupVO vo) {
		if (vo != null) {
			adapterGroups.put(vo.getName(), vo);
		}
	}

	public HashMap<String, AdapterGroupVO> getAllAdapterGroupVO() {
		return adapterGroups;
	}

	public List<String> getAllAdapterGroupNames() {
		ArrayList<String> al = new ArrayList<>();
		Iterator<String> it = this.adapterGroups.keySet().iterator();
		while (it.hasNext()) {
			al.add(it.next());
		}
		Collections.sort(al);
		return al;
	}

	public void updateAdapterGroupVO(AdapterGroupVO vo) {
		if (vo != null)
			adapterGroups.put(vo.getName(), vo);
	}

	public void removeAdapterGroupVO(String name) {
		adapterGroups.remove(name);
	}

	public void print() {
		if (logger.isDebug())
			logger.debug("AdapterManager] All Adapter List>> " + this.adapterGroups);
	}
}
