package com.yonge.toolset.mybatis.service.impl;

/**
 * GenericServiceImpl.java 
 * Copyright © 2015-2015
 * 
 * @author pengdc
 * @create 2015年7月13日
 */

import com.yonge.toolset.mybatis.dal.BaseDAO;
import com.yonge.toolset.base.page.PageInfo;
import com.yonge.toolset.base.page.QueryInfo;
import com.yonge.toolset.mybatis.service.BaseService;
import com.yonge.toolset.utils.collection.MapUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.*;

/**
 * SERVICE操作基类
 * @param <PK>
 * @param <T>
 */
public abstract class BaseServiceImpl<PK extends Serializable, T> implements BaseService<PK, T> {

	@Autowired
	protected SqlSessionFactory sqlSessionFactory;

	public abstract BaseDAO<PK, T> getDAO();

	/**
	 * 通过主键id加载对象
	 * @param id
	 * @return
	 */
	public T get(final PK id) {
		return this.getDAO().get(id);
	}

	/**
	 * 更新实体对象
	 * @param bean
	 * @return int
	 */
	public int update(T bean) {
		return this.getDAO().update(bean);
	}

	/**
	 * 通过主键id删除对象
	 * @param id
	 * @return int
	 */
	public int delete(final PK id) {
		return this.getDAO().delete(id);
	}

    /**
     * 删除对象
     * @param bean
     * @return
     */
	public int delete(T bean){
	    return this.getDAO().delete(bean);
    }

	/**
	 * 写入实体对象
	 * @param bean
	 * @return int
	 */
	public long insert(T bean) {
		return this.getDAO().insert(bean);
	}

	/**
	 * 通过参数查找所有结果集
	 * @param params
	 * @return
	 */
	public List<T> findAll(Map<String, Object> params) {
		
		return this.getDAO().findAll(params);
	}

    /**
     * 通过参数查找所有结果集，也适合分页
     * @param entity
     * @return
     */
    public List<T> findList(T entity) {
        return this.getDAO().findList(entity);
    }

	/**
	 * 通过参数查找结果集，适合分页场景
	 * @param queryInfo
	 * @return
	 */
	public PageInfo<T> queryPage(QueryInfo queryInfo) {
		PageInfo<T> pageInfo = new PageInfo<T>(queryInfo.getPage(), queryInfo.getRows());
		Map<String, Object> params = new HashMap<String, Object>();
		MapUtil.populateMap(params, queryInfo);
		
		List<T> dataList = null;
		int count = this.findCount(params);
		if (count > 0) {
			pageInfo.setTotal(count);
			params.put("offset", pageInfo.getOffset());
			dataList = this.getDAO().queryPage(params);
		}
		if (count == 0) {
			dataList = new ArrayList<T>();
		}
		pageInfo.setRows(dataList);
		return pageInfo;
	}

	/**
	 * 通过参数查找结果集数目
	 * @author pengdc
	 * @param params
	 * @return
	 */
	public int findCount(Map<String, Object> params) {
		return this.getDAO().queryCount(params);
	}


	@Override
	public <K extends Collection, Y, Z> Map<Y,Z> getMap(String tableName, String columnKey, String columnValue, K ids,Integer tenantId, Class<Y> keyType, Class<Z> valueType){
		if(CollectionUtils.isEmpty(ids)){
			return Collections.emptyMap();
		}
		StringBuffer sql=new StringBuffer();
		Map<Y,Z> result=new HashMap();
		try {
			SqlSession sqlSession = sqlSessionFactory.openSession();
			Connection connection = sqlSession.getConnection();
			sql.append("SELECT ").append(columnKey).append(",").append(columnValue).append(" FROM ").append(tableName).append(" WHERE ").append(columnKey).append(" IN (").append(StringUtils.join(ids, ",")).append(")");
			if(tenantId != null){
				sql.append(" AND tenant_id_ = ").append(tenantId);
			}
			PreparedStatement ps = connection.prepareStatement(sql.toString());
			ResultSet resultSet = ps.executeQuery();
			while (resultSet.next()){
				Y key;
				Z value;
				if(keyType.isAssignableFrom(BigDecimal.class)){
					key = (Y) BigDecimal.class.getDeclaredConstructor(String.class).newInstance(resultSet.getString(1));
				}else if(keyType.isAssignableFrom(String.class)){
					key = (Y) resultSet.getString(1);
				}else{
					key = (Y) keyType.getMethod("valueOf", String.class).invoke(null,resultSet.getString(1));
				}
				if(valueType.isAssignableFrom(BigDecimal.class)){
					value = (Z) BigDecimal.class.getDeclaredConstructor(String.class).newInstance(resultSet.getString(2));
				}else if(valueType.isAssignableFrom(String.class)){
					value = (Z) resultSet.getString(2);
				}else{
					value = (Z) valueType.getMethod("valueOf", String.class).invoke(null,resultSet.getString(2));
				}
				result.put(key, value);
			}
			if(resultSet!=null){
				resultSet.close();
			}
			if(ps!=null){
				ps.close();
			}
			if(sqlSession!=null){
				sqlSession.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		return result;
	}

	@Override
	public <K extends List, Y, Z> Map<Y,Z> getMap(String tableName, String columnKey, String columnValue, String ids, Class<Y> keyType, Class<Z> valueType){
		if(StringUtils.isEmpty(ids)){
			return Collections.emptyMap();
		}
		StringBuffer sql=new StringBuffer();
		Map<Y,Z> result=new HashMap();
		try {
			SqlSession sqlSession = sqlSessionFactory.openSession();
			Connection connection = sqlSession.getConnection();
			sql.append("SELECT ").append(columnKey).append(",").append(columnValue).append(" FROM ").append(tableName).append(" WHERE ").append(columnKey).append(" IN (").append(ids).append(")");
			PreparedStatement ps = connection.prepareStatement(sql.toString());
			ResultSet resultSet = ps.executeQuery();
			while (resultSet.next()){
				Y key;
				Z value;
				if(keyType.isAssignableFrom(BigDecimal.class)){
					key = (Y) BigDecimal.class.getDeclaredConstructor(String.class).newInstance(resultSet.getString(1));
				}else if(keyType.isAssignableFrom(String.class)){
					key = (Y) resultSet.getString(1);
				}else{
					key = (Y) keyType.getMethod("valueOf", String.class).invoke(null,resultSet.getString(1));
				}
				if(valueType.isAssignableFrom(BigDecimal.class)){
					value = (Z) BigDecimal.class.getDeclaredConstructor(String.class).newInstance(resultSet.getString(2));
				}else if(valueType.isAssignableFrom(String.class)){
					value = (Z) resultSet.getString(2);
				}else{
					value = (Z) valueType.getMethod("valueOf", String.class).invoke(null,resultSet.getString(2));
				}
				result.put(key, value);
			}
			if(resultSet!=null){
				resultSet.close();
			}
			if(ps!=null){
				ps.close();
			}
			if(sqlSession!=null){
				sqlSession.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		return result;
	}


	@Override
	public <K extends List, Y, Z> Map<Y,Z> getMap(String tableName, String columnKey, String columnValue,Boolean hasDelFlag,Integer tenantId, Class<Y> keyType, Class<Z> valueType){
		StringBuffer sql=new StringBuffer();
		Map<Y,Z> result=new HashMap();
		try {
			SqlSession sqlSession = sqlSessionFactory.openSession();
			Connection connection = sqlSession.getConnection();
			sql.append("SELECT ").append(columnKey).append(",").append(columnValue).append(" FROM ").append(tableName).append(" WHERE 1 = 1");
			if(hasDelFlag){
				sql.append(" AND del_flag_ = 0");
			}
			if(tenantId != null){
				sql.append(" AND tenant_id_ = ").append(tenantId);
			}
			PreparedStatement ps = connection.prepareStatement(sql.toString());
			ResultSet resultSet = ps.executeQuery();
			while (resultSet.next()){
				Y key;
				Z value;
				if(keyType.isAssignableFrom(BigDecimal.class)){
					key = (Y) BigDecimal.class.getDeclaredConstructor(String.class).newInstance(resultSet.getString(1));
				}else if(keyType.isAssignableFrom(String.class)){
					key = (Y) resultSet.getString(1);
				}else{
					key = (Y) keyType.getMethod("valueOf", String.class).invoke(null,resultSet.getString(1));
				}
				if(valueType.isAssignableFrom(BigDecimal.class)){
					value = (Z) BigDecimal.class.getDeclaredConstructor(String.class).newInstance(resultSet.getString(2));
				}else if(valueType.isAssignableFrom(String.class)){
					value = (Z) resultSet.getString(2);
				}else{
					value = (Z) valueType.getMethod("valueOf", String.class).invoke(null,resultSet.getString(2));
				}
				result.put(key, value);
			}
			if(resultSet!=null){
				resultSet.close();
			}
			if(ps!=null){
				ps.close();
			}
			if(sqlSession!=null){
				sqlSession.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		return result;
	}
}
