package kr.gmtc.tss.db;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Queue;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import kr.gmtc.tss.data.vo.AsdeTrackVO;
import kr.gmtc.tss.main.MainServer;
import kr.gmtc.tss.status.CountStatus;

public class BatchInsertManager {

	/** Logger. */
	private final Logger logger = LoggerFactory.getLogger(this.getClass());

	private SqlSessionFactory sqlSessionFactory;
	private SqlSession session;
	
	private Queue<AsdeTrackVO> sqlLogAsdeTrackQueue;
	private Queue<AsdeTrackVO> sqlLogAsdeTrackLastQueue;

	private int savePos=0;
	private int saveLast=0;
	private int saveStatic=0;
	private int failPos=0;
	private int failLast=0;
	private int failStatic=0;
	
	/**
	 * mybatis batch insert 속도가 느려서 jdbc 객체를 직접 제어함.
	 * @param sqlSessionFactory
	 * @param dbType
	 */
	public BatchInsertManager(SqlSessionFactory sqlSessionFactory, Queue<AsdeTrackVO> sqlLogAsdeTrackQueue,Queue<AsdeTrackVO> sqlLogAsdeTrackLastQueue) {
		this.sqlSessionFactory = sqlSessionFactory;
		this.sqlLogAsdeTrackQueue = sqlLogAsdeTrackQueue;
		this.sqlLogAsdeTrackLastQueue = sqlLogAsdeTrackLastQueue;
//		this.dbType=dbType;
		openSession(false);
	}
	
	public void openSession(boolean forceOpen) {
		if(session==null||forceOpen)
			session = sqlSessionFactory.openSession();
	}
	
	public void closeSession() {
		if(session!=null)
			session.close();
	}
	
	public void insertAsdeData(AsdeTrackVO[] setAsdeTrackVoArr) {
		insertAsdeData(setAsdeTrackVoArr,true);
	}
	
	
	private void insertAsdeData(AsdeTrackVO[] setAsdeTrackVoArr, boolean isBatch) {
		int fail = 0;
		int save = 0;
		if(setAsdeTrackVoArr==null || setAsdeTrackVoArr.length<1) {
//			logger.error("insertDataAll - No tableList data");
			logger.debug("insertData(Batch:"+isBatch+") - no data in setAsdeTrackVoArr");
			return;
		}
//		Table destTable=tableList.get(0);
		
		
//		String sql = "INSERT INTO " + destTable.getName() + " (" + getInsertCols(destTable.getColumnList()) + ") " 
//					+ "VALUES (" + getInsertValueParams(destTable.getColumnList()) + ")";

//		String tableName = "SACP_ASDE_TRACK_" + setAsdeTrackVoArr[0].getRecptnDt().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
		
		// 날짜 테이블 삭제됨으로 사용안함
		SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
		String now_dt = format.format(setAsdeTrackVoArr[0].getRecptnDt());
		
		//String tableName = "SACP_ASDE_TRACK_" + now_dt;
		String tableName = "SACP_ASDE_TRACK";
		String sql = "INSERT INTO "+tableName+" (" + 
				"	RECPTN_DT,"
				+ "	TRGT_ID,"
				+ " MODE_S_CD,"
				+ " SSR_CD,"
				+ " CLSGN,"
				+ " AC_REG_NO,"
				+ " TRACK_NO,"
				+ " CAT_TY,"
				+ " LAT,"
				+ " LON,"
				+ " SPD,"
				+ " COS,"
				+ " TRGT_TY, "
				+ " REGISTER_ID) " + 
				"	VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'SYSTEM')";
		
		//System.out.println("sql = " + sql);
		PreparedStatement ps=null;
		Connection con=null;
		try  {
			
			con=session.getConnection();
			if(con.isClosed() || !con.isValid(1)) {
				closeSession();				
				openSession(true);
				con=session.getConnection();
			}
			con.setAutoCommit(false);
			
//			Statement statement = session.getConnection().createStatement();
			ps = con.prepareStatement(sql);
//			logger.info("수신 건수"+setAsdeTrackVoArr.length);
			for (int i = 0; i < setAsdeTrackVoArr.length; i++) {
				AsdeTrackVO vo = setAsdeTrackVoArr[i];
				
				//입력으로 처리
				//중복 입력 방지를 위함
				vo.setInserted(true);
				
				try {
					ps.setDate(1, vo.getRecptnDt());
					ps.setString(2, vo.getTrgtId());
					ps.setString(3, vo.getModeScd());
					ps.setString(4, vo.getSsrCd());
					ps.setString(5, vo.getClsgn());
					ps.setString(6, vo.getTailNo());
					ps.setDouble(7, vo.getTrackNo());
					ps.setDouble(8, vo.getCatTy());
					ps.setDouble(9, vo.getLat());
					ps.setDouble(10, vo.getLon());
					ps.setDouble(11, vo.getSpd());
					ps.setDouble(12, vo.getCos());
					ps.setString(13, vo.getTrgtTy());
	
					///건별 입력
					if(!isBatch) {
						ps.execute();
						savePos++;
						save++;
					}
				
				} catch (Exception e) {
					logger.debug("Data Insert error UseSqlLog");
					sqlLogAsdeTrackQueue.add(vo);
					failPos++;
					fail++;
				}
				
				//배치 입력
				if(isBatch) {
					ps.addBatch();	
				}
			}
			if(isBatch) {
				ps.executeBatch();
				
				//배치 insert는 arr 건수만큼 
				savePos+=setAsdeTrackVoArr.length;
				save = setAsdeTrackVoArr.length - fail;
//				logger.info("savePos 건수"+savePos);
//				logger.info("failPos 건수"+failPos);
				logger.info("저장 건수 {} : 실패 건수 {}", save, fail);
			} else {
				logger.info("저장 건수 {} : 실패 건수 {}", save, fail);
			}

			con.commit();
			
			
		} catch (Exception e) {
			logger.error("insertData(Batch:"+isBatch+") error", e);
			if(isBatch) {
				logger.error("Try insert row by row");
				insertAsdeData(setAsdeTrackVoArr, false);
			}
			
		} finally {
			
			if(ps!=null) {
				try {
					ps.close();
				} catch (SQLException e) {
					logger.error("insertData(Batch:"+isBatch+") PreparedStatement close error",e);
				}
			}
			if(con!=null) {
				try {
					con.commit();
					con.setAutoCommit(true);
				} catch (SQLException e) {
					logger.error("insertData(Batch:"+isBatch+") commit error",e);
				}
			}
		}
		
	}

	public void insertAsdeLastData(AsdeTrackVO[] setAsdeTrackVoArr) {
		insertAsdeLastData(setAsdeTrackVoArr,true);
	}
	
	private void insertAsdeLastData(AsdeTrackVO[] setAsdeTrackVoArr, boolean isBatch) {

		if(setAsdeTrackVoArr==null || setAsdeTrackVoArr.length<1) {
//			logger.error("mergeDynamicLastAll - No tableList data");
			logger.debug("insertAsdeLastData(Batch:"+isBatch+") - no data in setAsdeTrackVoArr");
			return;
		}
//		Table destTable=tableList.get(0);
		
		
//		String sql = "INSERT INTO " + destTable.getName() + " (" + getInsertCols(destTable.getColumnList()) + ") " 
//					+ "VALUES (" + getInsertValueParams(destTable.getColumnList()) + ")";
		
		
		String tableName = "SACP_ASDE_TRACK_LAST";
//		String sql = "MERGE INTO UTRACK."+tableName+" A" + 
//				"	USING DUAL" +
//				"		ON (A.TRGT_ID = ?)" +
//				"	WHEN MATCHED THEN" +
//				"		UPDATE" +
//				"			SET A.AC_REG_NO=?, A.CLSGN=?, A.SSR_CD=?, A.MODE_S_CD=?, A.RECPTN_DT=TO_TIMESTAMP(SYSDATE,'yyyyMMdd'), A.CAT_TY=?, A.LAT=?, A.LON=?, A.SPD=?, A.COS=?, A.ALT=?, A.VIRTL_TRGT_AT=?, A.TRACK_CRRCT_AT=?, A.TRACK_CNFDNC=?, A.UPDUSR_ID=?, A.UPDT_DT=TO_TIMESTAMP(SYSDATE,'yyyyMMdd')" +
//				"	WHEN NOT MATCHED THEN " + 
//				"		INSERT " +
//				"			(A.TRGT_ID, A.AC_REG_NO, A.CLSGN, A.SSR_CD, A.MODE_S_CD, A.RECPTN_DT, A.CAT_TY, A.LAT, A.LON, A.SPD, A.COS, A.ALT, A.VIRTL_TRGT_AT, A.TRACK_CRRCT_AT, A.TRACK_CNFDNC, A.REGISTER_ID)" +
//				"				VALUES (?, ?, ?, ?, ?, TO_TIMESTAMP(SYSDATE,'yyyyMMdd'), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
		String sql = "";
		
		if(MainServer.LAST_DATA_CNT > 0) {
			sql = " UPDATE " + tableName
				  + " SET AC_REG_NO=?, CLSGN=?, SSR_CD=?, MODE_S_CD=?, RECPTN_DT=?, CAT_TY=?, LAT=?, LON=?, "
				  + " SPD=?, COS=?, ALT=?, VIRTL_TRGT_AT=?, TRACK_CRRCT_AT=?,  "
				  + " TRACK_CNFDNC=?, UPDUSR_ID='SYSTEM', UPDT_DT=TO_TIMESTAMP(SYSDATE,'yyyyMMdd')"
				  + " WHERE TRGT_ID = ?";
		}else {
			sql = " INSERT INTO " + tableName
				  + " ( TRGT_ID, AC_REG_NO, CLSGN, SSR_CD, MODE_S_CD, RECPTN_DT, CAT_TY, "
				  + "  LAT, LON, SPD, COS, ALT, VIRTL_TRGT_AT, TRACK_CRRCT_AT, "
				  + "  TRACK_CNFDNC, REGISTER_ID)"
				  + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'SYSTEM')";
		}
		
		System.out.println("last sql = "+sql);
		PreparedStatement ps=null;
		Connection con=null;
		try  {
			
			con=session.getConnection();
			if(con.isClosed() || !con.isValid(1)) {
				closeSession();				
				openSession(true);
				con=session.getConnection();
			}
			con.setAutoCommit(false);
					
			
//			Statement statement = session.getConnection().createStatement();
			ps = con.prepareStatement(sql);
			
			for (int i = 0; i < setAsdeTrackVoArr.length; i++) {
				AsdeTrackVO vo = setAsdeTrackVoArr[i];
				//입력으로 처리
				//중복 입력 방지를 위함
				vo.setInserted(true);
				
				try {
					if(MainServer.LAST_DATA_CNT > 0) {
						//ps.setString(1, vo.getAcRegNo());
						ps.setString(2, vo.getClsgn());
						ps.setString(3, vo.getSsrCd());
						ps.setString(4, vo.getModeScd());
						ps.setDate(5, vo.getRecptnDt());
						ps.setDouble(6, vo.getCatTy());
						ps.setDouble(7, vo.getLat());
						ps.setDouble(8, vo.getLon());
						ps.setDouble(9, vo.getSpd());
						ps.setDouble(10, vo.getCos());
						//ps.setDouble(11, vo.getAlt());
						//ps.setString(12, vo.getVirtlTrgtAt());
						//ps.setString(13, vo.getTrackCrrctAt());
						//ps.setString(14, vo.getTrackCnfdnc());
						ps.setString(15, vo.getTrgtId());
					}else {
						ps.setString(1, vo.getTrgtId());
						//ps.setString(2, vo.getAcRegNo());
						ps.setString(3, vo.getClsgn());
						ps.setString(4, vo.getSsrCd());
						ps.setString(5, vo.getModeScd());
						ps.setDate(6, vo.getRecptnDt());
						ps.setDouble(7, vo.getCatTy());
						ps.setDouble(8, vo.getLat());
						ps.setDouble(9, vo.getLon());
						ps.setDouble(10, vo.getSpd());
						ps.setDouble(11, vo.getCos());
						//ps.setDouble(12, vo.getAlt());
						//ps.setString(13, vo.getVirtlTrgtAt());
						//ps.setString(14, vo.getTrackCrrctAt());
						//ps.setString(15, vo.getTrackCnfdnc());
					}
	
					///건별 입력
					if(!isBatch) {
						ps.execute();
						saveLast++;
						
						if(MainServer.LAST_DATA_CNT == 0 ) {
							MainServer.LAST_DATA_CNT = 1;
						}
					}
				
				} catch (Exception e) {
					logger.debug("Data Insert error UseSqlLog");
					//sqlLogAsdeTrackLastQueue.add(vo);
					failLast++;
				}
				
				//배치 입력
				if(isBatch) {
					ps.addBatch();
				}
			}
			if(isBatch) {
				ps.executeBatch();
				
				if(MainServer.LAST_DATA_CNT == 0 ) {
					MainServer.LAST_DATA_CNT = 1;
				}

				//배치 insert는 arr 건수만큼 
				saveLast+=setAsdeTrackVoArr.length;
			}

			con.commit();
			
			
		} catch (Exception e) {
			logger.error("asdeLast(Batch:"+isBatch+") error", e);
			if(isBatch) {
				logger.error("Try insert row by row");
				insertAsdeLastData(setAsdeTrackVoArr, false);
			}
			
		} finally {
			
			if(ps!=null) {
				try {
					ps.close();
				} catch (SQLException e) {
					logger.error("asdeLast(Batch:"+isBatch+") PreparedStatement close error",e);
				}
			}
			if(con!=null) {
				try {
					con.commit();
					con.setAutoCommit(true);
				} catch (SQLException e) {
					logger.error("asdeLast(Batch:"+isBatch+") commit error",e);
				}
			}
		}
		
	}
	public synchronized CountStatus getCountAndSetZero() {
		CountStatus countStatus = new CountStatus(savePos, saveLast, saveStatic, failPos, failLast, failStatic);
		
		savePos = 0;
		saveLast = 0;
		saveStatic = 0;
		failPos = 0;
		failLast = 0;
		failStatic = 0;

		return countStatus;
	}
	
	/**
	 * 
	 * 오류 발생시 건/건으로 저장할 수 있도록 수정
	 * @param setDynamicVoArr
	 */
	/*public void insertData(SetDynamicVO[] setDynamicVoArr) {

		if(setDynamicVoArr==null || setDynamicVoArr.length<1) {
//			logger.error("insertDataAll - No tableList data");
			logger.debug("insertData - no data in setDynamicVoArr");
			return;
		}
//		Table destTable=tableList.get(0);
		
		
//		String sql = "INSERT INTO " + destTable.getName() + " (" + getInsertCols(destTable.getColumnList()) + ") " 
//					+ "VALUES (" + getInsertValueParams(destTable.getColumnList()) + ")";

		String tableName = "th_ais_" + setDynamicVoArr[0].getDateTime().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
		
		String sql = "INSERT INTO "+tableName +" (" + 
				"	ship_id, recv_dt, lon_val, lat_val, sog_val, cog_val, hdg_val, rot_val, zone_id) " + 
				"	VALUES (?, TO_TIMESTAMP(?,'yyyyMMddhh24miss'), ?, ?, ?, ?, ?, ?, ?)";
		
		
		PreparedStatement ps=null;
		Connection con=null;
		try  {
			
			con=session.getConnection();
			if(con.isClosed() || !con.isValid(1)) {
				closeSession();				
				openSession(true);
				con=session.getConnection();
			}
			con.setAutoCommit(false);
					
			
//			Statement statement = session.getConnection().createStatement();
			ps = con.prepareStatement(sql);
			
			for (int i = 0; i < setDynamicVoArr.length; i++) {
				SetDynamicVO vo = setDynamicVoArr[i];
				//입력으로 처리
				//중복 입력 방지를 위함
				vo.setInserted(true);
				
				
				try {
					
					ps.setString(1, vo.getShipID());
	//				ps.setDate(2, vo.getDateTime());
					ps.setString(2, vo.getDateTime().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")));
					ps.setDouble(3, vo.getLongitude());
					ps.setDouble(4, vo.getLatitude());
					ps.setDouble(5,vo.getSog());
					ps.setDouble(6,vo.getCog());
					ps.setInt(7, vo.getHeading());
					ps.setInt(8, vo.getRot());
					ps.setString(9, vo.getZoneId());
	//				ps.addBatch();
					ps.execute();

				} catch (Exception e) {
//					logger.error("insertData error", e);
					
					
				}
				
			}
//			ps.executeBatch();

			con.commit();
			
			
		} catch (Exception e) {
			logger.error("insertData error", e);
		} finally {
			
			if(ps!=null) {
				try {
					ps.close();
				} catch (SQLException e) {
					logger.error("insertData PreparedStatement close error",e);
				}
			}
			if(con!=null) {
				try {
					con.commit();
					con.setAutoCommit(true);
				} catch (SQLException e) {
					logger.error("insertData commit error",e);
				}
			}
		}
		
	}*/
	
//	/**
//	 * Insert colums 성성
//	 * @param columnList
//	 * @return
//	 */
//	private String getInsertCols(List<Column> columnList) {
//		StringBuilder result=new StringBuilder();
//		for (int i 	= 0; i < columnList.size(); i++) {
//			result.append(columnList.get(i).getName());
//			//마지막에는 ,를 안붙이기 위해
//			if(i!=columnList.size()-1)
//				result.append(",");
//		}
//		return result.toString();
//	}
//	
//
//	private String getInsertValueParams(List<Column> columnList) {
//		StringBuilder result=new StringBuilder();
//		for (int i 	= 0; i < columnList.size(); i++) {
//			result.append(setInsertParam(columnList.get(i)));
//			//마지막에는 ,를 안붙이기 위해
//			if(i!=columnList.size()-1)
//				result.append(",");
//		}
//		return result.toString();
//	}
//
//	/**
//	 * 파라미터는 ? 로 표현하여 ps.set~~~으로...
//	 * @param column
//	 * @return
//	 */
//	private String setInsertParam(Column column) {
//		switch (dbType) {
//		case ORACLE:
//			return setInsertParamOracle(column);
//		default:
//			//mariadb default
//			return setInsertParamMariadb(column);
//		}
//		
//		
//	}
//	
//	
//	private String setInsertParamMariadb(Column column) {
//		
//		if(column.isCustom()) {
//			return column.getCustomStr();
//		}else {
//			switch (column.getColumnTypeName()) {
//			case "DATE":
//			case "DATETIME":
//				return "STR_TO_DATE(?,'%Y%m%d%H%i%S')";
//			case "TIMESTAMP":
//			case "TIMESTAMP_WITH_TIMEZONE":
//				return "STR_TO_DATE(?,'%Y%m%d%H%i%S%f')";	
//			case "TIME":
//			case "TIME_WITH_TIMEZONE":
//				return "STR_TO_DATE(?,'%H%i%S')";	
//			default:
//				return "?";
//			}
//		}
//	}
//	
//
//	
//	
//	private String setInsertParamOracle(Column column) {
//
//		if(column.isCustom()) {
//			return column.getCustomStr();
//		}else {
//			switch (column.getColumnTypeName()) {
//			case "DATE":
//			case "DATETIME":
//				return "TO_DATE(?,'yyyymmddhh24miss')";
//			case "TIMESTAMP":
//			case "TIMESTAMP_WITH_TIMEZONE":
//				return "TO_TIMESTAMP(?,'yyyymmddhh24missff')";	
//			case "TIME":
//			case "TIME_WITH_TIMEZONE":
//				return "TO_DATE(?,'hh24miss')";	
//			default:
//				return "?";
//			}
//		}
//		
//	}
	
	
	
	

}
