package com.usoftchina.uas.office.service;

import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.CallableStatementCallback;
import org.springframework.jdbc.core.CallableStatementCreator;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Types;
import java.util.List;

/**
 * @author yingp
 * @date 2020/1/13
 */
public abstract class AbstractService {

    @Autowired
    protected JdbcTemplate jdbcTemplate;

    @Autowired
    protected NamedParameterJdbcTemplate namedJdbcTemplate;

    private final static Logger logger = LoggerFactory.getLogger(AbstractService.class);

    protected <T> T queryForObject(String statement, Class<T> targetCls, Object... arguments) {
        try {
            return jdbcTemplate.queryForObject(statement, targetCls, arguments);
        } catch (EmptyResultDataAccessException e) {
            return null;
        }
    }

    protected <T> List<T> queryForList(String statement, Class<T> targetCls, Object... arguments) {
        try {
            return jdbcTemplate.queryForList(statement, targetCls, arguments);
        } catch (EmptyResultDataAccessException e) {
            return null;
        }
    }

    protected <T> T queryForBean(String statement, Class<T> targetCls, Object... arguments) {
        try {
            return jdbcTemplate.queryForObject(statement, new BeanPropertyRowMapper<>(targetCls), arguments);
        } catch (EmptyResultDataAccessException e) {
            return null;
        }
    }

    protected <T> List<T> queryForBeanList(String statement, Class<T> targetCls, Object... arguments) {
        try {
            return jdbcTemplate.query(statement, new BeanPropertyRowMapper<>(targetCls), arguments);
        } catch (EmptyResultDataAccessException e) {
            return null;
        }
    }

    /**
     * 从 闪回区间 查找已删除的对象
     *
     * @param <T>
     * @return
     */
    protected <T> T queryFlashbackBean(String table, String whereClause, Class<T> targetCls, Object... arguments) {
        return queryForBean("select * from " + table + " as of timestamp (systimestamp - interval '20' second) "
                + whereClause, targetCls, arguments);
    }

    /**
     * 从 uas系统回收站 查找已删除的对象
     *
     * @param <T>
     * @return
     */
    protected <T> T queryRecycleBean(String formCaller, Class<T> targetCls, Integer key) {
        String jsonData = queryForObject("select re_data from (select re_data,rownum r from recycles where re_caller=? and re_keyvalue=? order by re_id desc) where r<2",
                String.class, formCaller, key);
        if (null != jsonData) {
            return JSON.parseObject(jsonData, targetCls);
        }
        return null;
    }

    /**
     * 生成序列值
     *
     * @param sequence 序列名
     * @return
     */
    protected Integer generateId(String sequence) {
        return jdbcTemplate.queryForObject("select " + sequence + ".nextval from dual", Integer.class);
    }

    /**
     * 生成流水码
     *
     * @param code 规则名称
     * @param type 规则类型
     * @return
     */
    protected String generateCode(final String code, final int type) {
        return jdbcTemplate.execute(new CallableStatementCreator() {
            @Override
            public CallableStatement createCallableStatement(Connection con) throws SQLException {
                CallableStatement cs = con.prepareCall("{call Sp_GetMaxNumber(?,?,?)}");
                cs.setObject(1, code);
                cs.setObject(2, type);
                cs.registerOutParameter(3, Types.VARCHAR);
                return cs;
            }
        }, new CallableStatementCallback<String>() {
            @Override
            public String doInCallableStatement(CallableStatement cs) throws SQLException, DataAccessException {
                cs.execute();
                return cs.getString(3);
            }
        });
    }
}
