/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package kr.co.kihyun.beans.ecross;

import java.lang.reflect.Constructor;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import javax.jdo.JDOException;
import javax.jdo.Query;
import kr.co.kihyun.beans.entity.Board;
import kr.co.kihyun.beans.entity.MDept;
import kr.co.kihyun.beans.entity.ecross.CRUD;
import kr.co.kihyun.beans.entity.ecross.ECross;
import kr.co.kihyun.beans.entity.ecross.IRemotePersistable;
import kr.co.kihyun.beans.entity.ecross.NeisParty;
import kr.co.kihyun.beans.entity.ecross.ReceiverTotReport;
import kr.co.kihyun.beans.entity.util.MPersistenceManager;
import kr.co.kihyun.beans.entity.util.RemoteNotPersistableException;
import kr.co.kihyun.db.CommonDBManager;
import kr.co.kihyun.moumi.MoumiConfig;
import neis.esb.client.AgentClient;

import org.bouncycastle.ocsp.Req;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author bhs
 */
public abstract class ECrossInterface {

	private List<Class<? extends IRemotePersistable>> receiverClasses = new ArrayList<Class<? extends IRemotePersistable>>();
	private static final Logger LOG = LoggerFactory.getLogger(ECrossInterface.class);
	private static String partyId = MoumiConfig.getInitParameter("moumi.partyId");

	protected ECrossInterface(Class<? extends IRemotePersistable>... rps) {
		receiverClasses.addAll(Arrays.asList(rps));
	}

	protected final List<Class<? extends IRemotePersistable>> getRelatedClasses() {
		return Collections.unmodifiableList(receiverClasses);
	}

	public final String generateTransactionId() {
		return MoumiConfig.getInitParameter("moumi.partyId") + "-" + this + "-" + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
	}

	public final <T extends IRemotePersistable> void send(MPersistenceManager pm, ECrossInterface eInterface, String transactionId, Collection<MDept> parties) throws RemoteNotPersistableException {
		NeisParty[] partyArray = toNeisPartyArray(pm, parties);
		send(eInterface, transactionId, partyArray);
	}

	public final <T extends IRemotePersistable> void send(ECrossInterface eInterface, String transactionId, NeisParty... parties) throws RemoteNotPersistableException {
		AgentClient client = AgentClient.getInstance();
		String[] dstPartyIds = new String[parties.length];
		String[] transactionIds = new String[parties.length];
		String[] dstSystemIds = new String[parties.length];
		for (int i = 0; i < parties.length; i++) {
			dstPartyIds[i] = parties[i].toString();
			transactionIds[i] = transactionId;
			dstSystemIds[i] = MoumiConfig.getInitParameter("moumi.subSystemId");
		}

//		try {
//			client.callAsync(partyId, dstPartyIds, dstSystemIds, eInterface.toString(), transactionIds, null);
//		} catch (Exception ex) {
//			throw new RemoteNotPersistableException("Send Failed.", ex);
//		}
	}

	protected final NeisParty[] toNeisPartyArray(MPersistenceManager moumiPm, Collection<MDept> parties) {
		NeisParty[] partyArray = new NeisParty[parties.size()];
		int i = 0;
		for (Iterator<MDept> iter = parties.iterator(); iter.hasNext();) {
			MDept party = iter.next();
			partyArray[i++] = party.getNeisParty(moumiPm);
		}
		return partyArray;
	}

	protected final <T extends IRemotePersistable> void save(MPersistenceManager moumiPm, MPersistenceManager eCrossPm, T pc, CRUD crud, Collection<MDept> parties) throws RemoteNotPersistableException {
		NeisParty[] partyArray = toNeisPartyArray(moumiPm, parties);
		save(eCrossPm, pc, crud, partyArray);
	}

	protected final <T extends IRemotePersistable> void save(MPersistenceManager eCrossPm, T pc, CRUD crud, NeisParty[] dstParties) throws RemoteNotPersistableException {
		try {
			Class senderClass = getSenderClass(pc.getClass());
			Constructor senderConstructor = getConstructor(pc, senderClass);

			List remotePcs = new ArrayList();
			for (NeisParty dstParty : dstParties) {

				ECross ec = (ECross) senderConstructor.newInstance(pc);
//				if (ec.getFromParty() == dstParty)
//					continue;
				ec.setCrud(crud);
				ec.setToParty(dstParty);
//				remotePcs.add(senderClass.cast(ec));
				eCrossPm.makePersistent(senderClass.cast(ec));

			}
//			pm.makePersistentAll(remotePcs);
		} catch (Exception ex) {
                        ex.printStackTrace();
			throw new RemoteNotPersistableException("Could not persist remote entity for " + pc, ex);
		}
	}

	protected final <T extends IRemotePersistable> void saveAll(MPersistenceManager moumiPm, MPersistenceManager eCrossPm, Collection<T> pcs, CRUD crud, Collection<MDept> parties) throws RemoteNotPersistableException {
		NeisParty[] partyArray = toNeisPartyArray(moumiPm, parties);
		saveAll(eCrossPm, pcs, crud, partyArray);
	}

	protected final <T extends IRemotePersistable> void saveAll(MPersistenceManager eCrossPm, Collection<T> pcs, CRUD crud, NeisParty[] dstParties) throws RemoteNotPersistableException {
		T tmpPc;
		if (pcs != null && !pcs.isEmpty())
			tmpPc = pcs.iterator().next();
		else
			return;

		List remotePcs = new ArrayList();
		try {
			Class senderClass = getSenderClass(tmpPc.getClass());
			Constructor senderConstructor = getConstructor(tmpPc, senderClass);

			for (T pc : pcs) {
				for (NeisParty dstParty : dstParties) {
					ECross ec = (ECross) senderConstructor.newInstance(pc);
					if (ec.getFromParty() == dstParty)
						continue;
					ec.setCrud(crud);
					ec.setToParty(dstParty);
//					remotePcs.add(senderClass.cast(ec));
					eCrossPm.makePersistent(senderClass.cast(ec));
				}
			}
//			eCrossPm.makePersistentAll(remotePcs);
		} catch (Exception ex) {
			throw new RemoteNotPersistableException("Could not persist remote entity for " + pcs, ex);
		}
	}

	protected final <T> Constructor getConstructor(T pc, Class senderClass) throws NoSuchMethodException, SecurityException {
		Class<T> entityClass = (Class<T>) pc.getClass();
		Constructor senderConstructor = senderClass.getConstructor(entityClass);
		return senderConstructor;
	}

	public static final Class<ECross> getReceiverClass(Class<? extends IRemotePersistable> clazz) {
		try {
			String senderClassName = "kr.co.kihyun.beans.entity.ecross.Receiver" + clazz.getSimpleName();
			Class senderClass = Class.forName(senderClassName);
			return senderClass;
		} catch (ClassNotFoundException ex) {
			throw new RuntimeException("Could not found Receiver Class.", ex);
		}
	}

	public static final Class<ECross> getSenderClass(Class<? extends IRemotePersistable> clazz) {
		try {
			String senderClassName = "kr.co.kihyun.beans.entity.ecross.Sender" + clazz.getSimpleName();
			Class senderClass = Class.forName(senderClassName);
			return senderClass;
		} catch (ClassNotFoundException ex) {
			throw new RuntimeException("Could not found Receiver Class.", ex);
		}
	}

	protected final <T extends IRemotePersistable> List<T> saveAll(MPersistenceManager pm, Class<T> clazz, String transactionId) {
		try {
			String receiverClassName = "kr.co.kihyun.beans.entity.ecross.Receiver" + clazz.getSimpleName();
			LOG.debug("receiverClassName: {}", receiverClassName);
			Class<? extends ECross> receiverClass = (Class<? extends ECross>) Class.forName(receiverClassName);

			Query q = pm.newQuery(receiverClass, "transactionId == tid");
			q.declareParameters("String tid");
                        //v2. 6.SQL 삽입 : JDO형식이므로 해결책에 따른 prepare SQL 문으로 변경할 수 없음
			List<? extends ECross> receivedList = (List<? extends ECross>) q.execute(transactionId);
                        //================

			List<T> moumiList = new ArrayList<T>();
			for (ECross<T> received : receivedList) {
				moumiList.add(received.toMoumiEntity(pm, clazz));
			}

			return (List<T>) pm.makePersistentAll(moumiList);
		} catch (ClassNotFoundException ex) {
			throw new JDOException("Could not persist from ECross table for class " + clazz, ex);
		}
	}

	// TODO: Implement.
	protected final List<? extends IRemotePersistable> loadAll(MPersistenceManager moumiPm, MPersistenceManager eCrossPm, String transactionId) throws RemoteNotPersistableException {
		List<IRemotePersistable> resultList = new ArrayList<IRemotePersistable>();

		List<Class<? extends IRemotePersistable>> relatedClasses = this.getRelatedClasses();
		for (Class<? extends IRemotePersistable> clazz : relatedClasses) {
			Query q = eCrossPm.newQuery(clazz, "transactionId == tid");
			q.declareParameters("String tid");
                        //v2. 6.SQL 삽입 : JDO형식이므로 해결책에 따른 prepare SQL 문으로 변경할 수 없음
			List<ECross> remoteEntities = (List<ECross>) q.execute(transactionId);
                        //================
			List<IRemotePersistable> localEntities = new ArrayList<IRemotePersistable>();

			for (ECross ec : remoteEntities) {
				localEntities.add(ec.toMoumiEntity(moumiPm, clazz));
			}
			resultList.addAll(localEntities);
			eCrossPm.makePersistentAll(remoteEntities);
		}

		return resultList;
	}

	public final List<? extends IRemotePersistable> loadAll(MPersistenceManager moumiPm, MPersistenceManager eCrossPm) {
		List<IRemotePersistable> resultList = new ArrayList<IRemotePersistable>();

		List<Class<? extends IRemotePersistable>> relatedClasses = this.getRelatedClasses();
		CommonDBManager db=new CommonDBManager();
        try{
		for (Class<? extends IRemotePersistable> clazz : relatedClasses) {
//			Query q = pm.newQuery(clazz, "transactionId == tid");
			Query q = eCrossPm.newQuery(ECrossInterface.getReceiverClass(clazz), "isAplied == false");
//			q.declareParameters("String tid");
//			List<ECross> remoteEntities = (List<ECross>) q.execute(transactionId);
                        //v2. 6.SQL 삽입 : JDO형식이므로 해결책에 따른 prepare SQL 문으로 변경할 수 없음
			List<ECross> oldremoteEntities = (List<ECross>) q.execute();
                        //================
			List<ECross> remoteEntities=new ArrayList<ECross>();
			//중복제거
			for(ECross ec: oldremoteEntities){
				boolean isDup=false;
				for(ECross nec: remoteEntities){
					if(ec.getId().equals(nec.getId())){
						isDup=true;
						break;
					}
				}
				if(!isDup)remoteEntities.add(ec);
			}
			List<IRemotePersistable> localEntities = new ArrayList<IRemotePersistable>();

			for (ECross ec : remoteEntities) {
				String ecid=ec.getId().toString();
				IRemotePersistable localEntity =null;
				//에러시 무시
				try{
					localEntity= ec.toMoumiEntity(moumiPm, clazz);
					try{
						//존재하지 않을경우 인서트
						Object existObject= moumiPm.getObjectById(clazz, ec.getId());
					}catch(Exception ex){
						ex.printStackTrace();
						moumiPm.makePersistent(localEntity);
						db.execUpdate(
								"insert into moumi_tot_log " +
								" (NUM,ACT,CLIENT_IP,CS_URI,DES,GROUP_ID,LOCATION,LOG_LEVEL,DEPT_ID,USER_ID,MESSAGE,DOC_ID,WRITE_DATE) " +
								" values " +
								" ((select count(num)+1 from moumi_tot_log),'연계',null,null,null,null,null,null,null,null,?,null,sysdate)",
								clazz.toString()+" "+ex.getMessage()+" ECrossInterface::272 ,id:"+ec.getId());
					}
					localEntities.add(localEntity);
				}catch(Exception e1){
					e1.printStackTrace();
					db.execUpdate(
							"insert into moumi_tot_log " +
							" (NUM,ACT,CLIENT_IP,CS_URI,DES,GROUP_ID,LOCATION,LOG_LEVEL,DEPT_ID,USER_ID,MESSAGE,DOC_ID,WRITE_DATE) " +
							" values " +
							" ((select count(num)+1 from moumi_tot_log),'연계',null,null,null,null,null,null,null,null,?,null,sysdate)",
							clazz.toString()+" "+e1.getMessage()+" ECrossInterface::272 ,id:"+ec.getId());
				}
			}

			//적용된 아이디 setapplied ->true
			for(ECross ec: oldremoteEntities){
				String ecid=ec.getId().toString();
				for (IRemotePersistable iRemotePersistable : localEntities) {
					String irid=iRemotePersistable.getId().toString();
					if(irid.equals(ecid)){
						ec.setAplied(true);
						eCrossPm.makePersistent(ec);
						break;
					}
				}
			}
			resultList.addAll(localEntities);
//			eCrossPm.makePersistentAll(remoteEntities);
		}
                }catch (Exception e){
                	try {
						db.execUpdate(
								"insert into moumi_tot_log " +
								" (NUM,ACT,CLIENT_IP,CS_URI,DES,GROUP_ID,LOCATION,LOG_LEVEL,DEPT_ID,USER_ID,MESSAGE,DOC_ID,WRITE_DATE) " +
								" values " +
								" ((select count(*)+1 from moumi_tot_log),'연계',null,null,null,null,null,null,null,null,?,null,sysdate)",
								e.getMessage());
					} catch (SQLException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					}
                    e.printStackTrace();
                }
        db.execClose();
		return resultList;
	}

	public abstract void saveAll(MPersistenceManager moumiPm, MPersistenceManager eCrossPm, Collection<MDept> parties);

        //20160425 추가
       	public List<? extends IRemotePersistable> loadAll_VCMCCMC2013(MPersistenceManager moumiPm, MPersistenceManager eCrossPm){
            List<IRemotePersistable> resultList = new ArrayList<IRemotePersistable>();
            return resultList;
}

}
