package com.eactive.eai.adapter.db.sql;

import com.eactive.eai.adapter.db.DBAdapterKeys;
import com.eactive.eai.adapter.listener.AdapterException;
import com.eactive.eai.adapter.listener.AdapterListenerSupport;
import com.eactive.eai.common.exception.ExceptionUtil;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;

import java.util.Date;
import java.util.Properties;

import static org.quartz.CronScheduleBuilder.cronSchedule;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;

public class DBInboudSqlAdapterListener  extends AdapterListenerSupport {
	
	String className = this.getClass().getName();
	Scheduler scheduler = null;
	private static boolean isLocalTest = false;
	private String SCHE_GROUP_NAME = "DBQ_GROUP";
	
	public boolean startScheduler(Properties prop) {
    	boolean isStart = false;
    	try {
    		debug(className + " Scheduler start");
    		logger.warn(className + " Scheduler start");
    		if(scheduler != null) {
    			logger.warn("Scheduler shutdown previous RUN !");
    			scheduler.shutdown();
    		}
    		String adapterName = prop.getProperty("adapterName");
    		scheduler = new StdSchedulerFactory().getScheduler();
    		String jobName = "DBInboudSqlAdapterJob";
    		String jobClassName = "com.eactive.eai.adapter.db.sql.DBInboudSqlAdapterJob";
    		String cronExp = prop.getProperty( DBAdapterKeys.RUN_CRONEXP ); // "0/10 * * * * ?";
		    registJob(jobName, jobClassName, cronExp,  prop);
	    	scheduler.start();
	    	isStart = true;
    	}
    	catch(SchedulerException se) {
    		logger.error("Scheduler start failed", se);
    	}
    	catch(Exception e) {
    		logger.error("Scheduler start failed", e);
    	}
		return isStart;
    }
    
    private String getTriggerName(String jobName) {
        return jobName + "-trigger";
    }
    
	public boolean registJob(String jobName, String jobClassName, String cronExp, Properties p) {
    	try {
	    	//configure the scheduler time
    		Class jobClass = Class.forName(jobClassName);
    		
    		JobBuilder jobBuilder = newJob(jobClass);
    		
    		jobBuilder = jobBuilder.withIdentity(jobName, Scheduler.DEFAULT_GROUP);
    		
	    	// pass adapter name : not used this time
            jobBuilder.usingJobData(DBAdapterKeys.ADAPTER_NAME, p.getProperty(DBAdapterKeys.ADAPTER_NAME));
            jobBuilder.usingJobData(DBAdapterKeys.ADAPTER_PROPGN, p.getProperty(DBAdapterKeys.ADAPTER_PROPGN));
            
            JobDetail job = jobBuilder.build();

            CronTrigger trigger = newTrigger().withIdentity( getTriggerName(jobName), SCHE_GROUP_NAME )
                    .withSchedule(cronSchedule(cronExp))
                    .build();

            Date ft = scheduler.scheduleJob(job, trigger);
            logger.warn(String.format("%s has been scheduled to run at: %s and repeat based on expression: %s", job.getKey(), ft,
                    trigger.getCronExpression()) );
            
	    	return true;
    	}
    	catch(Exception e) {
    		logger.warn("registJob failed", e);
    		return false;
    	}
    }
	
	private void printProperties(Properties prop) throws Exception  {
		if(prop == null) {
			debug("printProperties - Properties is null");
			return; 
		}
		for (Object key: prop.keySet()) {
            debug(key + ": " + prop.getProperty(key.toString()));
        }
//		prop.forEach((key, value) -> debug("Key : " + key + ", Value : " + value));		
	}
	
    private void init(Properties prop) throws Exception  {
		debug("Start init");
    	printProperties(prop);
    	startScheduler(prop);
    }
    
	public void start() throws AdapterException {
		Properties prop = null;
		String adapterName = null;
		if(info != null) {
			String propGroupName = info.getPropGroupName();
			prop = AdapterUtils.getAdapterProerties(propGroupName);
			adapterName = info.getName();
			prop.setProperty(DBAdapterKeys.ADAPTER_PROPGN, propGroupName);
		}
		// TODO : Application Test Code.
		// in real system,  remove this block  
//		else {
//			prop = new Properties();
//
//			prop.setProperty(DBAdapterKeys.RUN_CRONEXP, "0/10 * * * * ?");
//			prop.setProperty(DBAdapterKeys.RUN_INTVL, "1000");
//			prop.setProperty(DBAdapterKeys.RUN_RETRY, "N");
//			prop.setProperty(DBAdapterKeys.RUN_RETRYCNT, "2");
//			prop.setProperty(DBAdapterKeys.RUN_RETRYINTVL, "5000");
//			prop.setProperty(DBAdapterKeys.RUN_MSGTYPE, "JSON");
//
//			prop.setProperty(DBAdapterKeys.DRIVER, "oracle.jdbc.driver.OracleDriver");
//			prop.setProperty(DBAdapterKeys.URL, "jdbc:oracle:thin:@localhost:1521:XE");
//			prop.setProperty(DBAdapterKeys.USER, "eai");
//			prop.setProperty(DBAdapterKeys.PVAL, "eaiadmin");
////			prop.setProperty(DBAdapterKeys.SELECT, "select * from APIJOBSCHE");
//			prop.setProperty(DBAdapterKeys.SELECT, "select * from EAIINF01 where RFLAG IS null ORDER BY UNID");
//			prop.setProperty(DBAdapterKeys.UPDATE, "update EAIINF01 set RFLAG = 'C' where UNID = '%UNID%' ");
//
//			debug("Start Scheduler");
//			adapterName = "_EAI_IN_DBQ_SyC";
//		}
		// TODO : Application Test Code End.
		
		prop.setProperty(DBAdapterKeys.ADAPTER_NAME, adapterName);
		// Start Scheduler
		try{
        	logger.warn(className + " STARTING");
        	init(prop);
        	DBInboudSqlAdapterManager maanger = DBInboudSqlAdapterManager.getInstance();
        	// init adapter configuration values
        	DBInboudSqlAdapter adapter = new DBInboudSqlAdapter(info, prop);
        	maanger.put(adapterName, adapter);
        } catch(Exception e) {
        	e.printStackTrace();
        }
	}
	
	public void stop() throws AdapterException {
		try {
			String adapterName = "";
			if (info == null) {
				adapterName = "_EAI_IN_DBQ_SyC";
//				throw new Exception(this.getClass().getName() +" | AdapterVO°¡ NULLÀÔ´Ï´Ù.");
			}
			else {
				adapterName = info.getName();
			}
			if(scheduler != null) {
	        	try {
	        		DBInboudSqlAdapterManager manager = DBInboudSqlAdapterManager.getInstance();
	        		DBInboudSqlAdapter adapter = manager.get(adapterName);
	        		logger.warn("stop adapter - " + adapterName);
	        		adapter.stop();
	    			// Stop Scheduler
	        		logger.warn("stop scheduler - " + scheduler.getSchedulerName());
	                JobKey key = new JobKey(adapterName, SCHE_GROUP_NAME );
	                scheduler.deleteJob(key);
	        		scheduler.shutdown();
	        	}
	        	catch(SchedulerException se) {
	        		logger.error("stop scheduler failed", se);
	        	}
	        }
		} catch (Exception e) {
			String errCode = ExceptionUtil.getErrorCode(e, "RECEAIOIA009");
			throw new AdapterException(errCode);
		}
	}

	private void debug(String msg) {
		if(isLocalTest) {
			System.out.println (msg);
		}
		else {
			logger.info(msg);
		}
	}
	
	public static void main(String[]  args) {
		try {
			isLocalTest = true;
			System.setProperty("isLocal", "true");
			DBInboudSqlAdapterListener listener = new DBInboudSqlAdapterListener();
			int testSecs = 60;
			System.out.println (String.format(">> Test while %s secs ...", testSecs));
			listener.start();
			Thread.sleep(testSecs * 1000);
			System.out.println ("<< Test end.");
			listener.stop();
		}
		catch(Exception ex) {
			ex.printStackTrace();
		}
	}
}
