package kr.gmtc.tss.db;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Date;
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.AlarmVO;
import kr.gmtc.tss.data.vo.StandStatusVO;
import kr.gmtc.tss.status.CountStatus;

public class BatchInsertManager {
	private final Logger logger = LoggerFactory.getLogger(this.getClass());

	private SqlSessionFactory sqlSessionFactory;
	private SqlSession session;
	
	private Queue<StandStatusVO> sqlLogStandStatusQueue;
	private Queue<AlarmVO> sqlLogAlarmQueue;

	private int savePos=0;
	private int saveAlarm=0;
	private int saveStatic=0;
	private int failPos=0;
	private int failAlarm=0;
	private int failStatic=0;
	
	/**
	 * mybatis batch insert 속도가 느려서 jdbc 객체를 직접 제어함.
	 * @param sqlSessionFactory
	 * @param dbType
	 */
	public BatchInsertManager(SqlSessionFactory sqlSessionFactory, Queue<StandStatusVO> sqlLogStandStatusQueue, Queue<AlarmVO> sqlLogAlarmQueue) {
		this.sqlSessionFactory = sqlSessionFactory;
		this.sqlLogStandStatusQueue = sqlLogStandStatusQueue;
		this.sqlLogAlarmQueue = sqlLogAlarmQueue;
//		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 insertStandStatusData(StandStatusVO[] setVOArr) {
		insertStandStatusData(setVOArr,true);
	}
	
	
	private void insertStandStatusData(StandStatusVO[] setVOArr, boolean isBatch) {
		int fail = 0;
		int save = 0;
		
		if(setVOArr==null || setVOArr.length<1) {
			logger.debug("insertStandStatusData(Batch:"+isBatch+") - no data in setVOArr");
			return;
		}
		
		SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
		
		String tableName = "SACP_ANALYZE_STAND_STATUS";
		String sql = "INSERT INTO "+tableName+" (" + 
				"	STTUS_DT,STAND_NO,STAND_STTUS_TY,INSTL_PLC,REGISTER_ID) " + 
				"	VALUES (?,?,?,?,?)";
		
		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);
			
			ps = con.prepareStatement(sql);
			for (int i = 0; i < setVOArr.length; i++) {
				StandStatusVO vo = setVOArr[i];
				//입력으로 처리
				//중복 입력 방지를 위함
				vo.setInserted(true);
				try {
//					Date now = new Date();
//					String timestamp = format.format(now);
					
//					ps.setString(1, vo.getAanetDt());
					ps.setString(2, vo.getStandNo());
//					ps.setString(3, vo.getStandSttusTy());
					ps.setString(4, vo.getClsgn());
					ps.setString(5, "ana");
	
					///건별 입력
					if(!isBatch) {
						ps.execute();
						savePos++;
						save++;
					}
				
				} catch (Exception e) {
					logger.debug("Data Insert error UseSqlLog");
					sqlLogStandStatusQueue.add(vo);
					failPos++;
					fail++;
				}
				
				//배치 입력
				if(isBatch) {
					ps.addBatch();	
				}
			}
			if(isBatch) {
				ps.executeBatch();
				//배치 insert는 arr 건수만큼 
				savePos+=setVOArr.length;
//				logger.info("savePos 건수"+savePos);
				save = setVOArr.length - fail;
				logger.info("topic {} 저장 건수 {} : 실패 건수 {}","ic.analyze.stand.status", save, fail);
			} else {
				logger.info("topic {} 저장 건수 {} : 실패 건수 {}","ic.analyze.stand.status", save, fail);
			}

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

	public void insertAlarmData(AlarmVO[] setVOArr) {
		insertAlarmData(setVOArr,true);
	}
	
	private void insertAlarmData(AlarmVO[] setVOArr, boolean isBatch) {
		int fail = 0;
		int save = 0;
		
		if(setVOArr == null || setVOArr.length<1) {
//			logger.error("mergeDynamicLastAll - No tableList data");
			logger.debug("insertAlarmData(Batch:"+isBatch+") - no data in setVOArr");
			return;
		}
		
		String tableName = "SACP_ANALYZE_SITTN_NTCN";
		String sql = " INSERT INTO " + tableName
				  + " (ANALS_ID,ANALS_DT,SITTN_TY,ANALS_MSG,AREA_TY,AREA_ID,TRGT1_TY,TRGT1_ID,TRGT2_TY,TRGT2_ID,REGISTER_ID)"
				  + " VALUES (?,?,?,?,?,?,?,?,?,?,?)";
		
//		System.out.println("insertAlarmData 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);
			
			ps = con.prepareStatement(sql);
			
			for (int i = 0; i < setVOArr.length; i++) {
				AlarmVO vo = setVOArr[i];
				//입력으로 처리
				//중복 입력 방지를 위함
				vo.setInserted(true);
				
				try {
					ps.setString(1, vo.getAnalsId());
					ps.setString(2, vo.getAnalsDt());
					ps.setString(3, "1"); // TODO SITTN_TY 데이터 필요 
					ps.setString(4, vo.getAnalsMsg());
					ps.setString(5, vo.getArea().getArea_type());
					ps.setString(6, vo.getArea().getArea_id());
					ps.setString(7, vo.getTarget1().getTrgt_ty());
					ps.setString(8, vo.getTarget1().getTrgt_id());
					ps.setString(9, vo.getTarget2().getTrgt_ty());
					ps.setString(10, vo.getTarget2().getTrgt_id());
					ps.setString(11, "ana");
	
					///건별 입력
					if(!isBatch) {
						ps.execute();
						saveAlarm++;
						save++;
					}
				} catch (Exception e) {
					logger.debug("Data Insert error UseSqlLog");
					sqlLogAlarmQueue.add(vo);
					failAlarm++;
					fail++;
				}
				
				//배치 입력
				if(isBatch) {
					ps.addBatch();	
				}
			}
			
			if(isBatch) {
				ps.executeBatch();
				
				//배치 insert는 arr 건수만큼 
				saveAlarm += setVOArr.length;
				save = setVOArr.length - fail;
				logger.info("topic {} 저장 건수 {} : 실패 건수 {}","ic.analyze.alarm", save, fail);
			} else {
				logger.info("topic {} 저장 건수 {} : 실패 건수 {}","ic.analyze.alarm", save, fail);
			}

			con.commit();
			
			
		} catch (Exception e) {
			logger.error("insertAlarmData(Batch:"+isBatch+") error", e);
			if(isBatch) {
				logger.error("Try insert row by row");
				insertAlarmData(setVOArr, false);
			}
			
		} finally {
			
			if(ps!=null) {
				try {
					ps.close();
				} catch (SQLException e) {
					logger.error("insertAlarmData(Batch:"+isBatch+") PreparedStatement close error",e);
				}
			}
			if(con!=null) {
				try {
					con.commit();
					con.setAutoCommit(true);
				} catch (SQLException e) {
					logger.error("insertAlarmData(Batch:"+isBatch+") commit error",e);
				}
			}
		}
	}
	public synchronized CountStatus getCountAndSetZero() {
		CountStatus countStatus = new CountStatus(savePos, saveAlarm, saveStatic, failPos, failAlarm, failStatic);
		
		savePos = 0;
		saveAlarm = 0;
		saveStatic = 0;
		failPos = 0;
		failAlarm = 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 "?";
//			}
//		}
//		
//	}
	
	
	
	

}
