# ReticleDAOImpl.java

    package com.mycim.server.reticle.dao.impl;

    import com.fa.sesa.threadlocal.LocalContext;
    import com.mycim.framework.jdbc.JdbcTemplate;
    import com.mycim.framework.jdbc.Page;
    import com.mycim.framework.jdbc.mapper.RowMapper;
    import com.mycim.framework.utils.lang.StringUtils;
    import com.mycim.framework.utils.lang.collections.MapUtils;
    import com.mycim.framework.utils.lang.time.DateUtils;
    import com.mycim.server.reticle.dao.ReticleDAO;
    import com.mycim.valueobject.ObjectList;
    import com.mycim.valueobject.bas.TransactionLog;
    import com.mycim.valueobject.consts.DataBaseNames;
    import com.mycim.valueobject.consts.EntityEnum;
    import com.mycim.valueobject.consts.ReferenceDetailNames;
    import com.mycim.valueobject.ems.Entity;
    import com.mycim.valueobject.ems.Location;
    import com.mycim.valueobject.ems.Reticle;
    import com.mycim.valueobject.wip.TransReason;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Repository;

    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Timestamp;
    import java.util.*;

    @Repository
    public class ReticleDAOImpl implements ReticleDAO {

        @Autowired
        JdbcTemplate jdbcTemplate;

        @Override
        public void addReticleH(Reticle reticle) {
            String sql = "INSERT INTO RETICLE_H (" + "TRANS_RRN,TRANS_SEQUENCE,RETICLE_RRN,LOT_RRN,LOT_ID,LOT_QTY1," +
                    "LOT_STEP_SEQUENCE," + "EQPT_RRN,PREV_CURRENT_STATUS,CURRENT_STATUS,COMMENTS" + ",TRANS_ID,SYS_RRN," +
                    "RETICLE_ID,FACILITY_RRN,DESCRIPTION,OBJ_SPACE,OBJ_TYPE," + "OBJ_SUBTYPE,OBJ_STATUS, " +
                    "ALLOWABLE_EVENTS_RRN," + "LOCATION_RRN,AVAILABILITY,PRV_LOCATION_RRN,RETICLE_FAMILY_ID," +
                    "MASK_INSPECTION_ID," + "VERSION,GRADE,MASK_HOUSE,MASK_TYPE,MAGNIFICATION," + "MASK_SIZE," +
                    "CURRENT_USE_TIMES,MAX_USE_TIMES,OVERDUE_TIME,PDFLAG,PROCESS_TIME,PD_TIME," + "RETICLE_TYPE," +
                    "TRANS_USER_RRN,TRANS_TIME" + ") SELECT ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, " + "?, SYS_RRN,RETICLE_ID," +
                    "FACILITY_RRN,DESCRIPTION,OBJ_SPACE,OBJ_TYPE,OBJ_SUBTYPE," + "OBJ_STATUS,ALLOWABLE_EVENTS_RRN," +
                    "LOCATION_RRN,AVAILABILITY,PRV_LOCATION_RRN,RETICLE_FAMILY_ID,MASK_INSPECTION_ID," + "VERSION,GRADE," +
                    "MASK_HOUSE,MASK_TYPE,MAGNIFICATION," + "MASK_SIZE,CURRENT_USE_TIMES,MAX_USE_TIMES,OVERDUE_TIME," +
                    "PDFLAG,PROCESS_TIME,PD_TIME," + "RETICLE_TYPE,?,? " + " FROM RETICLE WHERE SYS_RRN = ?";
            jdbcTemplate.update(sql, reticle.getTransRrn(), reticle.getTransSequence(), reticle.getInstanceRrn(),
                                reticle.getLotRrn(), reticle.getLotId(), reticle.getLotQty1(), reticle.getLotStepSequence(),
                                reticle.getEqptRrn(), reticle.getPrevEntityStatus(), reticle.getCurrentEntityStatus(),
                                reticle.getComments(), StringUtils.isNotBlank(reticle.getTransId()) ? reticle.getTransId()
                                                                                                             .toUpperCase() : StringUtils.EMPTY,
                                LocalContext.getUserRrn(), reticle.getLastUpdateTimestamp(), reticle.getInstanceRrn());
        }

        @Override
        public List<Map> getHoldReasons(long instanceRrn) {
            String sql = "SELECT REASON_CATEGORY,REASON_CODE,REASON," + "SEQUENCE_NUMBER,HOLD_PASSWORD,INSTANCE_ID," +
                    "HOLD_TIMESTAMP,B.HOLD_BY" + " FROM " + DataBaseNames.TRANS_REASON + " A," +
                    DataBaseNames.MULTIPLE_HOLD + " B," + DataBaseNames.NAMEDOBJECT + " C" +
                    " WHERE A.INSTANCE_RRN = B.INSTANCE_RRN" + " AND A.TRANS_RRN = B.TRANS_RRN" +
                    " AND A.INSTANCE_RRN = ?" + " AND B.HOLD_BY = C.INSTANCE_RRN";
            List<Map> list = jdbcTemplate.query(sql, new Object[]{instanceRrn}, new RowMapper<Map>() {

                @Override
                public Map<String, Object> mapRow(ResultSet rs, int rowNum) throws SQLException {
                    Map<String, Object> map = new HashMap<String, Object>();
                    map.put("REASON_CATEGORY", rs.getString("REASON_CATEGORY"));
                    map.put("REASON_CODE", rs.getString("REASON_CODE"));
                    map.put("REASON", rs.getString("REASON"));
                    map.put("SEQUENCE_NUMBER", rs.getString("SEQUENCE_NUMBER"));
                    map.put("HOLD_PASSWORD", rs.getString("HOLD_PASSWORD"));
                    map.put("INSTANCE_ID", rs.getString("INSTANCE_ID"));
                    map.put("HOLD_BY", rs.getString("HOLD_BY"));
                    map.put("HOLD_TIMESTAMP", rs.getString("HOLD_TIMESTAMP"));
                    return map;
                }
            });
            List<Map> holdReasons = new ArrayList();
            for (Map map : list) {
                HashMap holdReason = new HashMap();
                holdReason.put("instanceRrn", (new Long(instanceRrn)).toString());
                holdReason.put("reasonCategory", MapUtils.getString(map, "REASON_CATEGORY"));
                holdReason.put("reasonCode", MapUtils.getString(map, "REASON_CODE"));
                holdReason.put("reason", MapUtils.getString(map, "REASON"));
                holdReason.put("sequenceNumber", MapUtils.getString(map, "SEQUENCE_NUMBER"));
                holdReason.put("holdPassword", MapUtils.getString(map, "HOLD_PASSWORD"));
                String holdName = this.getTransByName(MapUtils.getString(map, "INSTANCE_ID"));
                if (holdName != null) {
                    holdReason.put("holdBy", MapUtils.getString(map, "INSTANCE_ID") + " " + holdName);
                } else {
                    holdReason.put("holdBy", MapUtils.getString(map, "INSTANCE_ID"));
                }
                holdReason.put("holdByRrn", MapUtils.getString(map, "HOLD_BY"));
                holdReason.put("holdDate", map.get("HOLD_TIMESTAMP"));
                holdReasons.add(holdReason);
            }
            return holdReasons;
        }

        @Override
        public void insertMultipleHold(long instanceRrn, String recipeKey, long holdBy, String holdPassword,
                                       long transRrn) {
            String sql = "INSERT INTO " + DataBaseNames.MULTIPLE_HOLD + "(INSTANCE_RRN,OBJECT,SEQUENCE_NUMBER," +
                    "HOLD_PASSWORD," + "HOLD_BY,HOLD_TIMESTAMP,TRANS_RRN) VALUES(?,?," + "NVL((SELECT MAX(NVL" +
                    "(SEQUENCE_NUMBER,0))+1 FROM " + DataBaseNames.MULTIPLE_HOLD + " WHERE INSTANCE_RRN = ?),1),?,?,?,?)";
            jdbcTemplate.update(sql, new Object[]{instanceRrn, recipeKey, instanceRrn, holdPassword, holdBy, new Timestamp(
                    System.currentTimeMillis()), transRrn});
        }

        @Override
        public void insertTransReason(long transRrn, long lotRrn, TransReason transReason, int reasonCodeSequence) {
            String sql = "INSERT INTO " + DataBaseNames.TRANS_REASON + "(TRANS_RRN,INSTANCE_RRN,REASON_CODE_SEQUENCE," +
                    "REASON_CATEGORY," + "REASON_CODE,REASON,TRANS_QTY1,TRANS_QTY2,RESPONSIBILITY,ACCOUNT_CODE) " +
                    "VALUES(?,?,?,?,?,?,?,?,?,?)";
            jdbcTemplate.update(sql,
                                new Object[]{transRrn, lotRrn, reasonCodeSequence, transReason.getReasonCategory(),
                                        transReason.getReasonCode(), transReason.getReason(), transReason.getTransQty1(),
                                        transReason.getTransQty2(), transReason.getResponsibility(),
                                        transReason.getAccountCode()});
        }

        @Override
        public void deleteMultipleHold(long instanceRrn, long sequenceNumber) {
            String sql = "DELETE FROM " + DataBaseNames.MULTIPLE_HOLD + " WHERE INSTANCE_RRN = ? AND " + "SEQUENCE_NUMBER" +
                    " = ?";
            jdbcTemplate.update(sql, new Object[]{instanceRrn, sequenceNumber});
        }

        @Override
        public boolean isMultipleHoldExisted(long instanceRrn) {
            String sql = "SELECT count(*) FROM " + DataBaseNames.MULTIPLE_HOLD + " WHERE INSTANCE_RRN = ?";
            int result = jdbcTemplate.queryForObject(sql, new Object[]{instanceRrn}, int.class);
            boolean flag = true;
            if (result == 0) {
                flag = false;
            }
            return flag;
        }

        @Override
        public Page qryReticleHistory(long reticleRrn, String startDateStr, String endDateStr, Page page) {

            StringBuilder sb = new StringBuilder("select distinct ");
            sb.append("tr.trans_id,tr.trans_start_timestamp,tr.trans_performed_by,");
            sb.append("getinstanceid(eh.allowable_events_rrn)allowable_events_id,");
            sb.append("eh.location_rrn,eh.prv_location_rrn,eh.reticle_family_id,eh.overdue_time,");
            sb.append("eh.max_use_times,eh.current_use_times,eh.pdflag,eh.process_time,eh.pd_time,rh" + ".lot_id,");
            sb.append("rh.lot_qty1,rh.lot_step_sequence,getinstanceid(rh.eqpt_rrn) as eqpt_id,");
            sb.append("rh.prev_current_status,rh.current_status,eeh.comments ");
            sb.append(
                    "from transaction_log tr,entity_h eh,reticle_h rh,ENTITY_EVENT_HISTORY eeh where tr" + ".trans_rrn=eh" +
                            ".trans_rrn and eeh.trans_rrn=eh.trans_rrn ");
            sb.append("and eh.trans_rrn=rh.trans_rrn and eh.entity_rrn=rh.reticle_rrn ");
            sb.append(" and eh.entity_rrn= ? ");
            sb.append(" AND TR.TRANS_START_TIMESTAMP >=TO_TIMESTAMP(? ,'" + DateUtils.DATE_FORMAT24 + "') ");
            sb.append(" AND TR.TRANS_START_TIMESTAMP <=TO_TIMESTAMP(? ,'" + DateUtils.DATE_FORMAT24 + "') ");
            sb.append("ORDER BY TR.TRANS_START_TIMESTAMP DESC ");

            String startDate = startDateStr + " 00:00:00";
            String endDate = endDateStr + " 23:59:59";
            return jdbcTemplate.queryForPage(page, sb.toString(), new Object[]{reticleRrn, startDate, endDate},
                                             new RowMapper<Map<String, Object>>() {

                                                 @Override
                                                 public Map<String, Object> mapRow(ResultSet rs,
                                                                                   int rowNum) throws SQLException {
                                                     Map<String, Object> map = new HashMap<String, Object>();
                                                     map.put("transId", rs.getString("trans_id"));
                                                     map.put("transStartTimestamp",
                                                             rs.getTimestamp("trans_start_timestamp") ==
                                                                     null ? null : DateUtils
                                                                     .formatDate(rs.getTimestamp("trans_start_timestamp")));
                                                     map.put("transPerformedBy", rs.getString("trans_performed_by"));
                                                     map.put("allowableEventsId", rs.getString("allowable_events_id"));

                                                     Long tmpRrn = rs.getLong("location_rrn");
                                                     map.put("location_rrn", tmpRrn);

                                                     tmpRrn = rs.getLong("prv_location_rrn");
                                                     map.put("prv_location_rrn", tmpRrn);

                                                     map.put("reticleFamilyId", rs.getString("reticle_family_id"));
                                                     map.put("overdueTime",
                                                             rs.getTimestamp("overdue_time") == null ? null : DateUtils
                                                                     .formatDate(rs.getTimestamp("overdue_time")));
                                                     map.put("maxUseTimes", rs.getString("max_use_times"));
                                                     map.put("currentUseTimes", rs.getString("current_use_times"));
                                                     map.put("pdflag", rs.getString("pdflag"));
                                                     map.put("processTime", rs.getString("process_time"));
                                                     map.put("pdTime", rs.getTimestamp("pd_time") == null ? null : DateUtils
                                                             .formatDate(rs.getTimestamp("pd_time")));
                                                     map.put("lotId", rs.getString("lot_id"));
                                                     map.put("lotQty1", rs.getString("lot_qty1"));
                                                     map.put("lotStepSequence", rs.getString("lot_step_sequence"));
                                                     map.put("eqptId", rs.getString("eqpt_id"));
                                                     map.put("prevCurrentStatus", rs.getString("prev_current_status"));
                                                     map.put("currentStatus", rs.getString("current_status"));
                                                     map.put("comments", rs.getString("comments"));

                                                     return map;
                                                 }
                                             });
        }

        @Override
        public Page qryReticleFamilyHistory(long reticleFamilyRrn, String startDateStr, String endDateStr, Page page) {

            StringBuilder sb = new StringBuilder("select * from ( ");
            sb.append("SELECT G.TRANS_ID, G.TRANS_START_TIMESTAMP, G.TRANS_PERFORMED_BY, GETINSTANCEID(L" + ".TO_RRN) " +
                              "RETICLE_GROUP_ID,");
            sb.append("'' AS INSTANCE_DESC, GETINSTANCEID(L.FROM_RRN) AS RETICLE_ID ,L.TO_RRN AS " + "INSTANCE_RRN ");
            sb.append("FROM RELATION_H L, TRANSACTION_LOG G ");
            sb.append("WHERE L.TRANS_RRN = G.TRANS_RRN AND L.LINK_TYPE = 'RETICLE_TO_RETICLEFAMILY' AND L" + ".TO_RRN " +
                              "= ? ");
            sb.append("UNION ALL ");
            sb.append("SELECT G.TRANS_ID, G.TRANS_START_TIMESTAMP, G.TRANS_PERFORMED_BY, L.INSTANCE_ID, L" +
                              ".INSTANCE_DESC, '' AS RETICLE_ID,L.INSTANCE_RRN ");
            sb.append("FROM NAMED_OBJECT_H L, TRANSACTION_LOG G ");
            sb.append("WHERE L.TRANS_RRN = G.TRANS_RRN AND L.OBJECT = 'RETICLEFAMILY' AND L.OBJECT_TYPE = " +
                              "'RETICLEFAMILY' AND L.INSTANCE_RRN = ?) TR ");
            sb.append("WHERE TR.INSTANCE_RRN=? ");
            sb.append(" AND TR.TRANS_START_TIMESTAMP >=TO_TIMESTAMP(? ,'" + DateUtils.DATE_FORMAT24 + "') ");
            sb.append(" AND TR.TRANS_START_TIMESTAMP <=TO_TIMESTAMP(? ,'" + DateUtils.DATE_FORMAT24 + "') ");
            sb.append("ORDER BY TR.TRANS_START_TIMESTAMP DESC ");

            String startDate = startDateStr + " 00:00:00";
            String endDate = endDateStr + " 23:59:59";
            return jdbcTemplate.queryForPage(page, sb.toString(),
                                             new Object[]{reticleFamilyRrn, reticleFamilyRrn, reticleFamilyRrn, startDate
                                                     , endDate},
                                             new RowMapper<Map<String, Object>>() {

                                                 @Override
                                                 public Map<String, Object> mapRow(ResultSet rs,
                                                                                   int rowNum) throws SQLException {
                                                     Map<String, Object> map = new HashMap<String, Object>();
                                                     map.put("transId", rs.getString("TRANS_ID"));
                                                     map.put("transStartTimestamp", DateUtils
                                                             .formatDate(rs.getTimestamp("TRANS_START_TIMESTAMP"),
                                                                         DateUtils.DATE_FORMAT4DATE));
                                                     map.put("transPerformedBy", rs.getString("TRANS_PERFORMED_BY"));
                                                     map.put("reticleFamilyId", rs.getString("RETICLE_GROUP_ID"));
                                                     map.put("instanceDesc", rs.getString("INSTANCE_DESC"));
                                                     map.put("reticleId", rs.getString("RETICLE_ID"));
                                                     return map;
                                                 }
                                             });
        }

        @Override
        public int getLocationCount(Location location) {
            String sql = "SELECT count(*) FROM " + DataBaseNames.LOCATION + " WHERE LOCATION_TYPE = ? " + " AND " +
                    "LOCATION_ID_MAIN = ?";
            return jdbcTemplate
                    .queryForObjectWithNull(sql, new Object[]{location.getLocationType(), location.getLocationIdMain()},
                                            int.class);
        }

        @Override
        public int getLocationCount(String locationType, String locationId, Integer locationR, Integer locationP) {
            String sql = "SELECT count(*) FROM " + DataBaseNames.LOCATION + " WHERE LOCATION_TYPE = ? " + " AND " +
                    "LOCATION_ID_MAIN = ? " + " AND LOCATION_R =? " + "  AND LOCATION_P =? ";
            return jdbcTemplate
                    .queryForObjectWithNull(sql, new Object[]{locationType, locationId, locationR, locationP}, int.class);
        }

        @Override
        public void insertLocation(long instanceRrn, String locationType, String locationIdMain, Integer locationR,
                                   Integer locationC, Integer locationP, long maxQty, Location location) {
            String insertSql =
                    "INSERT INTO " + DataBaseNames.LOCATION + " (location_rrn,location_type,location_id_main," + " " +
                            "location_r,location_c,location_p,max_qty," + " SYS_RRN,LOCATION_ID,DESCRIPTION,FACILITY_RRN," +
                            " OBJ_SPACE,OBJ_TYPE,OBJ_STATUS,CREATE_TIME,UPDATE_TIME," + " CREATE_USER_RRN," +
                            "UPDATE_USER_RRN,LOCK_VERSION)" + " VALUES (?,?,?,?,?,?,?," + "?,?,?,?,?,?,?,?,?,?," + "?,?)";
            Object[] args = {instanceRrn, locationType, locationIdMain, locationR, locationC, locationP, maxQty,
                    location.getInstanceRrn(), location.getLocationId(), location.getInstanceDesc(),
                    LocalContext.getFacilityRrn(), location.getNamedSpace(), location.getObjectType(),
                    location.getInstanceStatus(), location.getCreatedTimestamp(), location.getCreatedTimestamp(),
                    LocalContext.getUserRrn(), LocalContext.getUserRrn(), location.getLockVersion()};
            jdbcTemplate.update(insertSql, args);

        }

        @Override
        public List<Map> getReticleByLotUse(Long reticleRrn) {
            String sql = "SELECT L.LOT_ID,L.LOT_RRN,N.INSTANCE_ID AS EQPT_ID,L.EQPT_RRN " + " FROM LOT  L, NAMED_OBJECT  " +
                    "N  WHERE L.EQPT_RRN = N.INSTANCE_RRN " + " AND  L.RETICLE_RRN = " + reticleRrn;
            return jdbcTemplate.query(sql, new Object[]{}, new RowMapper() {

                @Override
                public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                    Map map = new HashMap();
                    map.put("lotId", rs.getString("LOT_ID"));
                    map.put("lotRrn", rs.getLong("LOT_RRN"));
                    map.put("eqptId", rs.getString("EQPT_ID"));
                    map.put("eqptRrn", rs.getLong("EQPT_RRN"));
                    return map;
                }
            });
        }

        @Override
        public List<Map> getAllReticleOverdueTime() {
            String sql = "SELECT EQPT_RRN,OVERDUE_TIME,CURRENT_USE_TIMES,MAX_USE_TIMES,PDFLAG,PROCESS_TIME," + "PD_TIME," +
                    "CREATE_DATETIME,NAMED_SPACE FROM " + DataBaseNames.ENTITY_EXT + " E," + DataBaseNames.NAMEDOBJECT +
                    " N " + " WHERE e.eqpt_rrn=n.instance_rrn and n.object_type='" + ObjectList.RETICLE_KEY +
                    "' and n.object='" + ObjectList.ENTITY_KEY + "'";

            List list = jdbcTemplate.query(sql, new Object[]{}, new RowMapper() {

                @Override
                public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                    Map map = new HashMap();
                    map.put("reticleRrn", rs.getLong("EQPT_RRN"));
                    map.put("overdueTime", rs.getTimestamp("OVERDUE_TIME"));
                    map.put("currentUseTimes", rs.getInt("CURRENT_USE_TIMES"));
                    map.put("maxUseTimes", rs.getInt("MAX_USE_TIMES"));
                    map.put("pdFlag", rs.getString("PDFLAG"));
                    map.put("processTime", rs.getString("PROCESS_TIME"));
                    map.put("pdTime", rs.getString("PD_TIME"));
                    map.put("createDate", rs.getString("CREATE_DATETIME"));
                    map.put("namedSpace", rs.getString("NAMED_SPACE"));
                    return map;
                }
            });
            return list;
        }

        @Override
        public void updateReticleLotcation(Entity reticle) {
            String sql = "UPDATE ENTITY SET LOCATION_RRN=?,PRV_LOCATION_RRN=? WHERE ENTITY_RRN=?";
            jdbcTemplate.update(sql, reticle.getLocationRrn(), reticle.getPrevLocationRrn(), reticle.getInstanceRrn());
            String newTableSql = "UPDATE " + DataBaseNames.RETICLE + " SET LOCATION_RRN=?,PRV_LOCATION_RRN=?," +
                    "UPDATE_USER_RRN=?,UPDATE_TIME=?  " + "WHERE SYS_RRN=?";
            jdbcTemplate
                    .update(newTableSql, reticle.getLocationRrn(), reticle.getPrevLocationRrn(), LocalContext.getUserRrn(),
                            reticle.getLastUpdateTimestamp(), reticle.getInstanceRrn());

        }

        @Override
        public Page qryReticleByPage(Page page, Map<String, Object> argMap) {
            List<Object> args = new ArrayList<Object>();
            StringBuilder sql = new StringBuilder("SELECT ");
            sql.append("N.INSTANCE_RRN AS INSTANCE_RRN , N.INSTANCE_ID AS RETICLE_ID, N.INSTANCE_DESC AS RETICLE_DESC, ES.CURRENT_STATUS AS " +
                               "RETICLE_STATUS, MATERIAL_REF.RETICLE_MATERIAL_DESC AS RETICLE_MATERIAL, ");
            sql.append(
                    "TYPE_REF.RETICLE_TYPE_DESC AS RETICLE_TYPE, getinstanceid(E.PRV_LOCATION_RRN) AS " + "PREV_LOCATION," +
                            " getinstanceid(E.LOCATION_RRN) AS LOCATION, EE.RETICLE_FAMILY_ID, ");
            sql.append("EE.GRADE AS RETICLE_LEVEL, MASKINSPECTIONID_REF.RETICLE_MASKINSPECTIONID_DESC AS " +
                               "MASK_INSPECTION_ID, EE.VERSION, MASK_HOUSE_REF.RETICLE_MASK_HOUSE_DESC AS " +
                               "MASK_HOUSE,");
            sql.append(" EE.STP_TYPE, EE.MAGNIFICATION, MASKSIZE_REF.RETICLE_MASKSIZE_DESC AS MASK_SIZE, EE" + ".PDFLAG," +
                               " EE.PD_TIME, EE.MAX_USE_TIMES, EE.CURRENT_USE_TIMES, EE.PROCESS_TIME, ");
            sql.append("EE.OVERDUE_TIME, getinstanceid(EE.CREATE_USER_RRN) AS CREATE_USER, N" + ".CREATED_TIMESTAMP ,RETICLE.CLEAN_COUNT AS CLEAN_COUNT ");

            sql.append(
                    "FROM NAMED_OBJECT N LEFT JOIN ENTITY E ON N.INSTANCE_RRN = E.ENTITY_RRN LEFT JOIN " + "ENTITY_EXT EE" +
                            " ON N.INSTANCE_RRN = EE.EQPT_RRN LEFT JOIN ENTITY_STATUS ES ON N" + ".INSTANCE_RRN = ES" +
                            ".ENTITY_RRN LEFT JOIN ");
            sql.append("(SELECT R.KEY_1_VALUE AS RETICLE_TYPE_CODE, R.DATA_1_VALUE AS RETICLE_TYPE_DESC FROM " +
                               "NAMED_OBJECT N, REFERENCE_FILE_DETAIL R ");
            sql.append("WHERE N.INSTANCE_RRN = R.REFERENCE_FILE_RRN AND N.OBJECT = ? AND N.NAMED_SPACE = ? " + "AND N" +
                               ".INSTANCE_ID = ?) TYPE_REF ON EE.RETICLE_TYPE = TYPE_REF.RETICLE_TYPE_CODE LEFT " +
                               "JOIN ");
            sql.append("(SELECT R.KEY_1_VALUE AS RETICLE_MATERIAL_CODE, R.DATA_1_VALUE AS " + "RETICLE_MATERIAL_DESC " +
                               "FROM NAMED_OBJECT N, REFERENCE_FILE_DETAIL R ");
            sql.append("WHERE N.INSTANCE_RRN = R.REFERENCE_FILE_RRN AND N.OBJECT = ? AND N.NAMED_SPACE = ? " + "AND N" +
                               ".INSTANCE_ID = ?) MATERIAL_REF ON N.OBJECT_SUBTYPE = MATERIAL_REF" +
                               ".RETICLE_MATERIAL_CODE" + " LEFT JOIN");
            sql.append("(SELECT R.KEY_1_VALUE AS RETICLE_MASKINSPECTIONID_CODE, R.DATA_1_VALUE AS " +
                               "RETICLE_MASKINSPECTIONID_DESC FROM NAMED_OBJECT N, REFERENCE_FILE_DETAIL R ");
            sql.append("WHERE N.INSTANCE_RRN = R.REFERENCE_FILE_RRN AND N.OBJECT = ? AND N.NAMED_SPACE = ? " + "AND N" +
                               ".INSTANCE_ID = ?) MASKINSPECTIONID_REF ON EE.MASK_INSPECTION_ID = " +
                               "MASKINSPECTIONID_REF" + ".RETICLE_MASKINSPECTIONID_CODE LEFT JOIN ");
            sql.append("(SELECT R.KEY_1_VALUE AS RETICLE_MASK_HOUSE_CODE, R.DATA_1_VALUE AS " + "RETICLE_MASK_HOUSE_DESC " +
                               "FROM NAMED_OBJECT N, REFERENCE_FILE_DETAIL R ");
            sql.append("WHERE N.INSTANCE_RRN = R.REFERENCE_FILE_RRN AND N.OBJECT = ? AND N.NAMED_SPACE = ? " + "AND N" +
                               ".INSTANCE_ID = ?) MASK_HOUSE_REF ON EE.MASK_HOUSE = MASK_HOUSE_REF" +
                               ".RETICLE_MASK_HOUSE_CODE LEFT JOIN ");
            sql.append("(SELECT R.KEY_1_VALUE AS RETICLE_MASKSIZE_CODE, R.DATA_1_VALUE AS " + "RETICLE_MASKSIZE_DESC " +
                               "FROM NAMED_OBJECT N, REFERENCE_FILE_DETAIL R ");
            sql.append("WHERE N.INSTANCE_RRN = R.REFERENCE_FILE_RRN AND N.OBJECT = ? AND N.NAMED_SPACE = ? " + "AND N" +
                               ".INSTANCE_ID = ?) MASKSIZE_REF ON  EE.MASK_SIZE = MASKSIZE_REF" +
                               ".RETICLE_MASKSIZE_CODE LEFT JOIN RETICLE ON N.INSTANCE_RRN = RETICLE.SYS_RRN ");
            sql.append("WHERE ");
            sql.append(" N.OBJECT = ? AND N.OBJECT_TYPE = ? AND N.NAMED_SPACE = ? ");

            args.add(ObjectList.REFERENCE_FILE_KEY);
            args.add(MapUtils.getStringCheckNull(argMap, "referenceFileNamedSpace"));
            args.add(ReferenceDetailNames.RETICLE_TYPE);

            args.add(ObjectList.REFERENCE_FILE_KEY);
            args.add(MapUtils.getStringCheckNull(argMap, "referenceFileNamedSpace"));
            args.add(ReferenceDetailNames.RETICLE_MATERIAL);

            args.add(ObjectList.REFERENCE_FILE_KEY);
            args.add(MapUtils.getStringCheckNull(argMap, "referenceFileNamedSpace"));
            args.add(ReferenceDetailNames.RETICLE_MASKINSPECTIONID);

            args.add(ObjectList.REFERENCE_FILE_KEY);
            args.add(MapUtils.getStringCheckNull(argMap, "referenceFileNamedSpace"));
            args.add(ReferenceDetailNames.RETICLE_MASK_HOUSE);

            args.add(ObjectList.REFERENCE_FILE_KEY);
            args.add(MapUtils.getStringCheckNull(argMap, "referenceFileNamedSpace"));
            args.add(ReferenceDetailNames.RETICLE_MASKSIZE);

            args.add(ObjectList.ENTITY_KEY);
            args.add(ObjectList.RETICLE_KEY);
            args.add(MapUtils.getStringCheckNull(argMap, "reticleNamedSpace"));

            if (StringUtils.isNotBlank(MapUtils.getStringCheckNull(argMap, "reticleId"))) {
                sql.append("AND N.INSTANCE_ID LIKE ? ");
                args.add(MapUtils.getStringCheckNull(argMap, "reticleId"));
            }
            if (StringUtils.isNotBlank(MapUtils.getStringCheckNull(argMap, "reticleFamilyId"))) {
                sql.append("AND EE.RETICLE_FAMILY_ID LIKE ? ");
                args.add(MapUtils.getStringCheckNull(argMap, "reticleFamilyId"));
            }
            if (MapUtils.getObject(argMap, "reticleStatus") != null) {
                String[] reticleStatus = (String[]) argMap.get("reticleStatus");
                if (reticleStatus.length > 0) {
                    sql.append("AND ES.CURRENT_STATUS IN ( " + StringUtils.repeat("?,", reticleStatus.length - 1) + "?) ");
                    args.addAll(Arrays.asList(reticleStatus));
                }
            }
            sql.append("ORDER BY N.CREATED_TIMESTAMP DESC ");

            return jdbcTemplate.queryForPage(page, sql.toString(), args.toArray(), new RowMapper<Reticle>() {

                @Override
                public Reticle mapRow(ResultSet rs, int rowNum) throws SQLException {
                    Reticle r = new Reticle();
                    r.setInstanceRrn(rs.getLong("INSTANCE_RRN"));
                    r.setInstanceId(rs.getString("RETICLE_ID"));
                    r.setInstanceDesc(rs.getString("RETICLE_DESC"));
                    r.setStatus(rs.getString("RETICLE_STATUS"));
                    r.setObjectSubtype(rs.getString("RETICLE_MATERIAL"));
                    r.setReticleType(rs.getString("RETICLE_TYPE"));
                    r.setEntityPrevLocation(rs.getString("PREV_LOCATION"));
                    r.setEntityLocation(rs.getString("LOCATION"));
                    r.setReticleFamilyId(rs.getString("RETICLE_FAMILY_ID"));
                    r.setGrade(rs.getString("RETICLE_LEVEL"));
                    r.setMaskInspectionId(rs.getString("MASK_INSPECTION_ID"));
                    r.setVersion(rs.getString("VERSION"));
                    r.setMaskHouse(rs.getString("MASK_HOUSE"));
                    r.setStpType(rs.getString("STP_TYPE"));
                    r.setMagnification(rs.getString("MAGNIFICATION"));
                    r.setMaskSize(rs.getString("MASK_SIZE"));
                    r.setPDFlag(rs.getString("PDFLAG"));
                    r.setPdTime(rs.getString("PD_TIME"));
                    r.setMaxUseTimes(rs.getInt("MAX_USE_TIMES"));
                    r.setCurrentUseTimes(rs.getInt("CURRENT_USE_TIMES"));
                    r.setProcessTime(rs.getString("PROCESS_TIME"));
                    r.setCreateUser(rs.getString("CREATE_USER"));
                    r.setCreateDateTime(DateUtils.formatDate(rs.getTimestamp("CREATED_TIMESTAMP")));
                    r.setOverdueTime(DateUtils.formatDate(rs.getDate("OVERDUE_TIME"), DateUtils.DATE_FORMAT4DAY));
                    r.setCleanCount(Integer.valueOf(rs.getInt("CLEAN_COUNT")));
                    return r;
                }

            });
        }

        @Override
        public void manualReticlePD(Entity entity) {
            String sql = "UPDATE ENTITY_EXT SET overdue_time = to_timestamp('" + entity.getOverdueTime() + "','" +
                    DateUtils.DATE_FORMAT24 + "')," + "current_use_times = 0,pd_time = to_timestamp('" +
                    entity.getPdTime() + "','" + DateUtils.DATE_FORMAT24 + "') where eqpt_rrn = " + entity.getInstanceRrn();
            jdbcTemplate.batchUpdate(sql);
        }

        @Override
        public String getLocationId(long locationRrn) {
            String sql = " SELECT location_id FROM location WHERE location_rrn = ?";
            String locationId = jdbcTemplate.queryForObjectWithNull(sql, new Object[]{locationRrn}, String.class);
            return StringUtils.trimToEmpty(locationId);
        }

        @Override
        public void insertReticle(Entity e) {
            if (StringUtils.isBlank(e.getOverdueTime())) {
                e.setOverdueTime(StringUtils.EMPTY);
            }
            if (StringUtils.isBlank(e.getPDFlag())) {
                e.setPDFlag(EntityEnum.PDFLAG_F.getValue());
            }
            if (StringUtils.isBlank(e.getProcessTime())) {
                e.setProcessTime(StringUtils.EMPTY);
            }
            if (StringUtils.isBlank(e.getPdTime())) {
                e.setPdTime(StringUtils.EMPTY);
            }
            String sql = "INSERT INTO RETICLE (" + "SYS_RRN,RETICLE_ID,FACILITY_RRN,DESCRIPTION,OBJ_SPACE," + "OBJ_TYPE," +
                    "OBJ_SUBTYPE,OBJ_STATUS,OBJ_CURRENT_VERSION,OBJ_ACTIVE_VERSION," + "ALLOWABLE_EVENTS_RRN," +
                    "LOCATION_RRN,LAST_TRANS_RRN,AVAILABILITY,PRV_LOCATION_RRN," + "RETICLE_FAMILY_ID,MASK_INSPECTION_ID," +
                    "VERSION,GRADE,MASK_HOUSE," + "MASK_TYPE,MAGNIFICATION,MASK_SIZE,CURRENT_USE_TIMES,MAX_USE_TIMES," +
                    "OVERDUE_TIME,PDFLAG,PROCESS_TIME,PD_TIME,RETICLE_TYPE," + "CREATE_TIME,UPDATE_TIME,CREATE_USER_RRN," +
                    "UPDATE_USER_RRN,LOCK_VERSION) " + " VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?," +
                    "TO_DATE(?,'" + DateUtils.DATE_FORMAT24 + "'),?,?,TO_DATE(?,'" + DateUtils.DATE_FORMAT24 + "'),?,?,?," +
                    "?,?,?) ";
            jdbcTemplate
                    .update(sql, e.getInstanceRrn(), e.getInstanceId(), LocalContext.getFacilityRrn(), e.getInstanceDesc(),
                            e.getNamedSpace(), e.getObjectType(), e.getObjectSubtype(), e.getInstanceStatus(),
                            e.getCurrentVersion(), e.getActiveVersion(), e.getAllowableEventsRrn(), e.getLocationRrn(),
                            e.getLastTransRrn(), e.getAvailability(), e.getPrevLocationRrn(), e.getReticleFamilyId(),
                            e.getMaskInspectionId(), e.getVersion(), e.getGrade(), e.getMaskHouse(), e.getMaskType(),
                            e.getMagnification(), e.getMaskSize(), e.getCurrentUseTimes(), e.getMaxUseTimes(),
                            e.getOverdueTime(), e.getPDFlag(), e.getProcessTime(), e.getPdTime(), e.getReticleType(),
                            e.getCreatedTimestamp(), e.getCreatedTimestamp(), LocalContext.getUserRrn(),
                            LocalContext.getUserRrn(), e.getLockVersion());
        }

        @Override
        public void updateReticle(Entity e) {
            if (StringUtils.isBlank(e.getOverdueTime())) {
                e.setOverdueTime("");
            }
            if (StringUtils.isBlank(e.getPDFlag())) {
                e.setPDFlag(EntityEnum.PDFLAG_F.getValue());
            }
            if (StringUtils.isBlank(e.getProcessTime())) {
                e.setProcessTime(StringUtils.EMPTY);
            }
            if (StringUtils.isBlank(e.getPdTime())) {
                e.setPdTime(StringUtils.EMPTY);
            }
            String sql = "UPDATE " + DataBaseNames.RETICLE + " SET ALLOWABLE_EVENTS_RRN = ?,LOCATION_RRN = ?," +
                    "LAST_TRANS_RRN =?,PRV_LOCATION_RRN =" + " ?,RETICLE_FAMILY_ID = ?," + "MASK_INSPECTION_ID=?," +
                    "VERSION=?,GRADE=?,MASK_HOUSE=?,MASK_TYPE=?, " + "MAGNIFICATION=?,MASK_SIZE=?,MAX_USE_TIMES=?," +
                    "OVERDUE_TIME=TO_DATE(?,'" + DateUtils.DATE_FORMAT24 + "'),PDFLAG=?, " + "PROCESS_TIME=?," +
                    "PD_TIME=TO_DATE(?,'" + DateUtils.DATE_FORMAT24 + "'),RETICLE_TYPE=?,DESCRIPTION=?,update_user_rrn=?," +
                    "update_time=?  " + "WHERE SYS_RRN = ?";
            jdbcTemplate
                    .update(sql, e.getAllowableEventsRrn(), e.getLocationRrn(), e.getLastTransRrn(), e.getPrevLocationRrn(),
                            e.getReticleFamilyId(), e.getMaskInspectionId(), e.getVersion(), e.getGrade(), e.getMaskHouse(),
                            e.getMaskType(), e.getMagnification(), e.getMaskSize(), e.getMaxUseTimes(), e.getOverdueTime(),
                            e.getPDFlag(), e.getProcessTime(), e.getPdTime(), e.getReticleType(), e.getInstanceDesc(),
                            LocalContext.getUserRrn(), e.getLastUpdateTimestamp(), e.getInstanceRrn());
        }

        @Override
        public void deleteReticle(Reticle reticle) {
            String sql = "DELETE " + DataBaseNames.RETICLE + " WHERE SYS_RRN = ? ";
            jdbcTemplate.update(sql, reticle.getInstanceRrn());
        }

        @Override
        public void updateReticleStatus(Entity entity) {
            String sql = "UPDATE " + DataBaseNames.RETICLE + " SET AVAILABILITY = ?,UPDATE_USER_RRN=?,UPDATE_TIME=? WHERE" +
                    " SYS_RRN = ? ";
            jdbcTemplate.update(sql, entity.getAvailability(), LocalContext.getUserRrn(), entity.getLastUpdateTimestamp(),
                                entity.getInstanceRrn());
        }

        @Override
        public void insertLocationHis(long locationRrn, TransactionLog transactionLog) {
            String sql = "INSERT INTO " + DataBaseNames.LOCATION_H + " (TRANS_RRN,TRANS_ID,LOCATION_RRN,SYS_RRN," +
                    "LOCATION_ID," + " DESCRIPTION,FACILITY_RRN,OBJ_SPACE,OBJ_TYPE,OBJ_STATUS," + " LOCATION_TYPE," +
                    "LOCATION_ID_MAIN,LOCATION_R,LOCATION_C," + " LOCATION_P,MAX_QTY,AVAIL_QTY,TRANS_USER_RRN,TRANS_TIME)" +
                    " SELECT " + " ?,?,LOCATION_RRN,SYS_RRN,LOCATION_ID,DESCRIPTION," + " FACILITY_RRN,OBJ_SPACE," +
                    "OBJ_TYPE,OBJ_STATUS,LOCATION_TYPE," + " LOCATION_ID_MAIN,LOCATION_R,LOCATION_C,LOCATION_P,MAX_QTY," +
                    " AVAIL_QTY,?,? FROM " + DataBaseNames.LOCATION + " WHERE LOCATION_RRN = ?";
            Object[] args = new Object[]{transactionLog.getTransRrn(), transactionLog.getTransId(),
                    LocalContext.getUserRrn(), transactionLog.getTransStartTimestamp(), locationRrn};
            jdbcTemplate.update(sql, args);
        }

        @Override
        public void updateReticleCleanCount(Reticle reticle) {
            String sql = "UPDATE RETICLE SET CLEAN_COUNT = ? WHERE SYS_RRN = ?";
            Object[] args = new Object[]{reticle.getCleanCount(),reticle.getInstanceRrn()};
            jdbcTemplate.update(sql,args);
        }

        @Override
        public Reticle getReticleById(String reticleId) {
            StringBuilder sql = new StringBuilder("SELECT ");
            sql.append(" R.SYS_RRN, R.RETICLE_ID, R.DESCRIPTION, R.RETICLE_FAMILY_ID, R.MASK_INSPECTION_ID, R.MAX_USE_TIMES,");
            sql.append(" R.VERSION, R.GRADE, R.MASK_HOUSE, R.MAGNIFICATION, R.MASK_SIZE, R.CURRENT_USE_TIMES, R.OVERDUE_TIME,");
            sql.append(" R.PDFLAG, R.PROCESS_TIME, RS.CURRENT_STATUS, R.LOCATION_RRN,R.PRV_LOCATION_RRN FROM ");
            sql.append(DataBaseNames.RETICLE);
            sql.append(" R, ");
            sql.append(DataBaseNames.RETICLE_STATUS);
            sql.append(" RS WHERE R.SYS_RRN = RS.RETICLE_SYS_RRN  AND R.RETICLE_ID = ?");
            List args = new ArrayList();
            args.add(reticleId);

            return jdbcTemplate.queryForObjectWithNull(sql.toString(), args.toArray(), new RowMapper<Reticle>() {
                @Override
                public Reticle mapRow(ResultSet rs, int rowNum) throws SQLException {
                    Reticle reticle = new Reticle();
                    reticle.setInstanceRrn(rs.getLong("SYS_RRN"));
                    reticle.setInstanceId(rs.getString("RETICLE_ID"));
                    reticle.setInstanceDesc(rs.getString("DESCRIPTION"));
                    reticle.setReticleFamilyId(rs.getString("RETICLE_FAMILY_ID"));
                    reticle.setMaskInspectionId(rs.getString("MASK_INSPECTION_ID"));
                    reticle.setMaxUseTimes(rs.getInt("MAX_USE_TIMES"));
                    reticle.setVersion(rs.getString("VERSION"));
                    reticle.setGrade(rs.getString("GRADE"));
                    reticle.setMaskHouse(rs.getString("MASK_HOUSE"));
                    reticle.setMagnification(rs.getString("MAGNIFICATION"));
                    reticle.setMaskSize(rs.getString("MASK_SIZE"));
                    reticle.setCurrentUseTimes(rs.getInt("CURRENT_USE_TIMES"));
                    reticle.setOverdueTime(DateUtils.formatDate(rs.getDate("OVERDUE_TIME"), DateUtils.DATE_FORMAT4DAY));
                    reticle.setPDFlag(rs.getString("PDFLAG"));
                    reticle.setProcessTime(rs.getString("PROCESS_TIME"));
                    reticle.setCurrentEntityStatus(rs.getString("CURRENT_STATUS"));
                    reticle.setLocationRrn(rs.getLong("LOCATION_RRN"));
                    reticle.setPrevLocationRrn(rs.getLong("PRV_LOCATION_RRN"));
                    return reticle;
                }
            });
        }

        public String getTransByName(String transBy) {
            String sql =
                    "select t.user_name from user_profile t,named_object o " + " where t.user_rrn=o.instance_rrn " + " " +
                            "and o.instance_id='" + transBy + "' and o.object='" + ObjectList.USER_KEY + "'";
            return jdbcTemplate.queryForObject(sql, String.class);
        }

    }