package com.eactive.eai.transformer.layout;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

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

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.transformer.dao.LayoutTypeDao;
import com.eactive.eai.transformer.util.Logger;
import com.eactive.eai.transformer.util.MemoryLogger;

@Component
public class LayoutTypeManager implements Lifecycle {
    private static Logger logger = Logger.getLogger("transformer");

    private Map<String, LayoutType> layoutTypeMap;
    private LifecycleSupport lifecycleSupport = null;
    private boolean started;
    
    @Autowired
    private LayoutTypeDao layoutTypeDao;

    private LayoutTypeManager() {
        layoutTypeMap = new HashMap<>();
        lifecycleSupport = new LifecycleSupport(this);
    }

    public static LayoutTypeManager getInstance() {
        return ApplicationContextProvider.getContext().getBean(LayoutTypeManager.class);
    }
    
	public synchronized void reload() {
	    init();
	    if(logger.isDebugEnabled()) {
	    	logger.debug("LayoutTypeManager | reloaded...");
	    }
	}
	
	public synchronized void reload(String typeName) {
	    LayoutType layoutType = layoutTypeDao.findLayoutTypeByName(typeName);
	
	    layoutTypeMap.put(typeName, layoutType);
	    if(logger.isDebugEnabled()) {
	    	logger.debug("LayoutTypeManager | reloaded layout type - " + typeName);
	    }
	}
	
	public String[] getAllLayoutTypeName() {
	    Iterator<String> it = layoutTypeMap.keySet().iterator();
	    
	    String[] keys = new String [layoutTypeMap.size()];
	    
	    for (int i=0; i<keys.length; i++) {
	        keys[i] = it.next();   
	    }
	    Arrays.sort(keys);
	    return keys;
	}    
	public void remove(String typeName) {
	    layoutTypeMap.remove(typeName);
	}	

    private void clear() {
        if(layoutTypeMap != null) layoutTypeMap.clear();
    }

    public Map<String, LayoutType> getLayoutTypes() {
    	return layoutTypeMap;    	
    }
    
    public LayoutType getLayoutType(String layoutTypeName) {
    	if ("ASCII".equals(layoutTypeName)) {
    		layoutTypeName = LayoutTypeKey.BYTES;
    	}
    	if ("VASCII".equals(layoutTypeName)) {
    		layoutTypeName = LayoutTypeKey.VBYTES;
    	}
        return layoutTypeMap.get(layoutTypeName);
    }

    private void init() { 	
        layoutTypeMap = layoutTypeDao.load();

		logger.info("LayoutTypeManager | all layout types initialized ...");
        MemoryLogger.txlog("LayoutTypeManager | all layout types initialized ...");
    }
        
    public void init(Map<String, LayoutType> layoutTypeMap) {
    	this.layoutTypeMap = layoutTypeMap;
    }

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

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

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

    public synchronized void start() throws LifecycleException {
        try {
            init();
            this.started = true;
        } catch (Exception e) {
            throw new LifecycleException(e);
        }
    }

    public synchronized void stop() throws LifecycleException {
        try {
            clear();
            this.started = false;
        } catch (Exception e) {
            throw new LifecycleException(e);
        }
    }

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

    public String toString() {
    	StringBuilder sb = new StringBuilder();
        sb.append("[LayoutTypeManager] toString()");

        Object[] keys = layoutTypeMap.keySet().toArray();

        for (int i = 0; i < layoutTypeMap.size(); i++) {
            sb.append("\n    " + keys[i] + " : " + layoutTypeMap.get(keys[i]));
        }

        return sb.toString();
    }
}
