package com.eactive.eai.env;

import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

import javax.annotation.PostConstruct;

import org.json.simple.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import com.eactive.eai.adapter.AdapterGroupVO;
import com.eactive.eai.adapter.AdapterManager;
import com.eactive.eai.adapter.AdapterPropManager;
import com.eactive.eai.adapter.AdapterVO;
import com.eactive.eai.common.dao.DAOException;
import com.eactive.eai.common.util.ContainerUtil;

@Component
@PropertySource("/WEB-INF/properties/env.common.properties")
public class ElinkConfig implements ConfigKeys {
	// message handling options
	//private static boolean useInternalQueue = true;
	private static boolean useInternalQueue = false;  // weblogic JMS jwhong
	private static boolean useCacheTopic = true;
	private static boolean useCacheStore = true;
	
	// async logging options
	private static boolean useAsyncLogging = true;
	private static boolean asyncInitOnstartup = true;
	private static int asyncPoolMaxSize = 10;
	private static int asyncPoolInitSize = 8;
	private static int asyncQueueSize = 1024;
	private static int asyncWorkers = 16;
	
	private static String waitStrategy = LOGGER_ASYNC_WAITSTRATEGY;
	
	private static ConcurrentHashMap<String, String> asyncDummyData = new ConcurrentHashMap<String, String>();
	private static String asyncDefaultDummyData = "";
	
   private static String httpClientUrlReplaceName ="";
   
	@Autowired
    private Environment env;
	
//	static {
//		reload();
//	}
	
	private ElinkConfig() {
		
	}
	
	
	public static String getConfigLog() {
		StringBuilder sb = new StringBuilder();
		sb.append( "[ElinkConfig]\n");
		sb.append( ">> Async Transaction Configuration\n");
		sb.append( String.format("%s = %s\n", USE_INTERNAL_QUEUE, useInternalQueue) );
		sb.append( String.format("%s = %s\n", USE_INTERNAL_TOPIC, useCacheTopic) );
		sb.append( String.format("%s = %s\n", USE_CACHE_STORE, useCacheStore) );
		sb.append( ">> Async Logging Configuration\n");
		sb.append( String.format("%s = %s\n", LOGGER_ASYNC_ACTIVE, useAsyncLogging) );
		sb.append( String.format("%s = %s\n", LOGGER_ASYNC_POOL_INITONSTARTUP, asyncInitOnstartup) );
		sb.append( String.format("%s = %s\n", LOGGER_ASYNC_MAXPOOLS, asyncPoolMaxSize) );
		sb.append( String.format("%s = %s\n", LOGGER_ASYNC_INITPOOLS, asyncPoolInitSize) );
		sb.append( String.format("%s = %s\n", LOGGER_ASYNC_QUEUES, asyncQueueSize) );
		sb.append( String.format("%s = %s\n", LOGGER_ASYNC_WORKERS, asyncWorkers) );
		sb.append( String.format("%s = %s\n", LOGGER_ASYNC_WAITSTRATEGY, waitStrategy) );
		sb.append(">> Async Dummy Configuration\n");
		sb.append(String.format("%s = %s\n", HTTP_ASYNC_DEFAULT_DUMMY_DATA, asyncDefaultDummyData));
		for (String key : asyncDummyData.keySet()) {
			sb.append(String.format("%s = %s\n", HTTP_ASYNC_DUMMY_DATA_PREFIX + key, asyncDummyData.get(key)));
		}
		return sb.toString();
	
	}
	
	@PostConstruct
	public void reload() {
		String sBoolean = null;
		String sCount = null;
		
		try {
			sBoolean = env.getProperty(USE_INTERNAL_QUEUE);
			useInternalQueue = Boolean.valueOf(sBoolean);
		} catch (Exception ex) {
			useInternalQueue = true;
		}
		
		try {
			sBoolean = env.getProperty(USE_INTERNAL_TOPIC, "true");
			useCacheTopic = Boolean.valueOf(sBoolean);
		} catch (Exception ex) {
			useCacheTopic = true;
		}
		
		try {
			sBoolean = env.getProperty(USE_CACHE_STORE, "true");
			useCacheStore = Boolean.valueOf(sBoolean);
		} catch (Exception ex) {
			useCacheStore = true;
		}
		
		try {
			sBoolean = env.getProperty(LOGGER_ASYNC_ACTIVE, LOGGER_ASYNC_ACTIVE_DEFAULT);
			useAsyncLogging = Boolean.valueOf(sBoolean);
		} catch (Exception ex) {
			useAsyncLogging = true;
		}
		
		try {
			sBoolean = env.getProperty(LOGGER_ASYNC_POOL_INITONSTARTUP, "true");
			asyncInitOnstartup = Boolean.valueOf(sBoolean);
		} catch (Exception ex) {
			asyncInitOnstartup = true;
		}
		
		try {
			sCount = env.getProperty(LOGGER_ASYNC_MAXPOOLS, "10");
			asyncPoolMaxSize = Integer.parseInt(sCount);
			if(asyncPoolMaxSize < 1) {
				asyncPoolMaxSize = 1;
			}
		} catch (Exception ex) {
			asyncPoolMaxSize = 10;
		}
		
		try {
			sCount = env.getProperty(LOGGER_ASYNC_INITPOOLS, "8");
			asyncPoolInitSize = Integer.parseInt(sCount);
			if(asyncPoolInitSize < 1) {
				asyncPoolInitSize = 1;
			}
		} catch (Exception ex) {
			asyncPoolInitSize = 8;
		}
		
		if(asyncPoolInitSize > asyncPoolMaxSize) {
			asyncPoolInitSize = asyncPoolMaxSize;
		}
		
		try {
			sCount = env.getProperty(LOGGER_ASYNC_QUEUES, "1024");
			asyncQueueSize = Integer.parseInt(sCount);
			if (asyncQueueSize < 2) {
				asyncQueueSize = 2;
			}
			if (Integer.bitCount(asyncQueueSize) != 1) {
				asyncQueueSize = (int)Math.pow(2, Math.getExponent(asyncQueueSize));
			}
		} catch (Exception ex) {
			asyncQueueSize = 1024;
		}
		
		
		try {
			sCount = env.getProperty(LOGGER_ASYNC_WORKERS, "16");
			asyncWorkers = Integer.parseInt(sCount);
			if (asyncWorkers < 1) {
				asyncWorkers = 1;
			}
		} catch (Exception ex) {
			asyncWorkers = 16;
		}
		
		try {
			waitStrategy = env.getProperty(LOGGER_ASYNC_WAITSTRATEGY, LOGGER_ASYNC_WAITSTRATEGY_TIME);
		} catch (Exception ex) {
			waitStrategy = LOGGER_ASYNC_WAITSTRATEGY_TIME;
		}
		try {
			asyncDefaultDummyData = System.getProperty(HTTP_ASYNC_DEFAULT_DUMMY_DATA, "");
		} catch (Exception ex) {
			asyncDefaultDummyData = "";
		}
		
		// TODO : check usage & replace other config
		Properties sysProps = System.getProperties();
		for (Enumeration e = sysProps.keys(); e.hasMoreElements();) {
			String key = (String) e.nextElement();
			if (key != null && key.startsWith(HTTP_ASYNC_DUMMY_DATA_PREFIX)) {
				String data = (String) sysProps.get(key);
				if (data == null)
					data = "";
				asyncDummyData.put(key.replace(HTTP_ASYNC_DUMMY_DATA_PREFIX, ""), data);
			}
		}
      try {
         httpClientUrlReplaceName = env.getProperty(HTTP_CLIENT_URL_REPLACE_NAME, "TRAN_CODE");
      } catch (Exception ex) {
         httpClientUrlReplaceName = "TRAN_CODE";
      }
	       
	}
	
	public static boolean isUseInternalQueue() {
		return (ContainerUtil.get() == ContainerUtil.TOMCAT || useInternalQueue);
	}

	public static void setUseInternalQueue(boolean useInternalQueue) {
		ElinkConfig.useInternalQueue = useInternalQueue;
	}

	public static boolean isUseCacheTopic() {
		return (ContainerUtil.get() == ContainerUtil.TOMCAT || useCacheTopic);
	}

	public static void setUseCacheTopic(boolean useCacheTopic) {
		ElinkConfig.useCacheTopic = useCacheTopic;
	}

	public static boolean isUseCacheStore() {
		return useCacheStore;
	}

	public static void setUseCacheStore(boolean useCacheStore) {
		ElinkConfig.useCacheStore = useCacheStore;
	}

	public static boolean isUseAsyncLogging() {
		return useAsyncLogging;
	}

	public static void setUseAsyncLogging(boolean useAsyncLogging) {
		ElinkConfig.useAsyncLogging = useAsyncLogging;
	}

	public static int getAsyncPoolMaxSize() {
		return asyncPoolMaxSize;
	}

	public static boolean isAsyncInitOnstartup() {
		return asyncInitOnstartup;
	}

	public static void setAsyncInitOnstartup(boolean asyncInitOnstartup) {
		ElinkConfig.asyncInitOnstartup = asyncInitOnstartup;
	}

	public static void setAsyncPoolMaxSize(int asyncPoolMaxSize) {
		ElinkConfig.asyncPoolMaxSize = asyncPoolMaxSize;
	}
	
	public static int getAsyncPoolInitSize() {
		return asyncPoolInitSize;
	}

	public static void setAsyncPoolInitSize(int asyncPoolInitSize) {
		ElinkConfig.asyncPoolInitSize = asyncPoolInitSize;
	}
	
	public static int getAsyncQueueSize() {
		return asyncQueueSize;
	}

	public static void setAsyncQueueSize(int asyncQueueSize) {
		ElinkConfig.asyncQueueSize = asyncQueueSize;
	}

	public static int getAsyncWorkers() {
		return asyncWorkers;
	}

	public static void setAsyncWorkers(int asyncWorkers) {
		ElinkConfig.asyncWorkers = asyncWorkers;
	}

	public static String getWaitStrategy() {
		return waitStrategy;
	}

	public static void setWaitStrategy(String waitStrategy) {
		ElinkConfig.waitStrategy = waitStrategy;
	}

	public static String getAsyncDummyData(String type) {
		if (type == null)
			return asyncDefaultDummyData;
		String d = asyncDummyData.get(type);
		if (d == null)
			return asyncDefaultDummyData;
		return asyncDummyData.get(type);
	}

	public static String getAsyncDummyDataForAdapterGroup(String adapterGroupName) {
		AdapterManager adapterManager = AdapterManager.getInstance();
		AdapterGroupVO agvo = null;
		try {
			agvo = adapterManager.getAdapterGroup(adapterGroupName);
		} catch (DAOException e) {
			return getAsyncDummyData(null);
		}
		String adptrMsgPtrnCd = null;
		if (agvo != null) {
			adptrMsgPtrnCd = agvo.getAdptrMsgPtrnCd();
		}
		return getAsyncDummyData(adptrMsgPtrnCd);
	}
	
	public static String getAsyncDummyDataForAdapterGroup(String adapterGroupName, String adapterName) {

		Properties httpProp = null;
		try {

			
			AdapterVO adapterVO = AdapterManager.getInstance().getAdapterVO(adapterGroupName, adapterName);
			
			httpProp = AdapterPropManager.getInstance().getProperties(adapterVO.getPropGroupName());
		} catch (Exception e) {
			return makeResponseBodyMsg();
		}
		
		String asyncMsgStyle =  httpProp.getProperty("ASYNC_RTNMSG_TYPE", "").toUpperCase();
    	String responseBody ="";
    	if (asyncMsgStyle == null || asyncMsgStyle.trim().isEmpty()) {
    		responseBody = makeResponseBodyMsg();
    	} else {
        	responseBody = asyncMsgStyle;	
    	} 
		
    	return responseBody;
	}
	
	static private String makeResponseBodyMsg() {
    	
    	Map<String, Object> dataMap = new HashMap<>();
    	dataMap.put("result", 1);
		Map<String, Object> map = new HashMap<>();
		
		map.put("code", "200");
        map.put("data", dataMap);
        map.put("message",  "정상 처리 되었습니다.");
	  
        JSONObject json = new JSONObject();
        json.putAll(map);
        
		return json.toJSONString(); 
    }

   public static String getHttpClientUrlReplaceName() {
      return httpClientUrlReplaceName;
   }
	
	
}
