package com.yanzuoguang.dao.impl;

import com.yanzuoguang.dao.DaoConst;
import com.yanzuoguang.dao.TableAnnotation;
import com.yanzuoguang.dao.cond.SqlCondDefault;
import com.yanzuoguang.util.base.MethodField;
import com.yanzuoguang.util.base.ObjectHelper;
import com.yanzuoguang.util.helper.StringHelper;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 表结构的基本信息
 *
 * @author 颜佐光
 */
public class TableStruct {

    private static final int WHERE_ADD = 1;
    private static final int WHERE_REMOVE_ADD = 2;
    private static final int WHERE_ADD_NOT = 0;
    /**
     * 数据库中的表名称
     */
    private String name;

    /**
     * 缓存的字段,根据字段的类型进行缓存,同一个字段可能会属于多个类型。
     */
    private final Map<Integer, List<TableFieldVo>> typeFieldCache = new HashMap<>();

    /**
     * 构造函数
     */
    public TableStruct() {
        this.name = "";
    }


    public TableStruct(String name) {
        this.name = name;
    }

    /**
     * 通过实体的字段来创建表结构信息
     *
     * @param name 表名称
     * @param cls  关联的实体,主键放在第一位,其他字段放到后面;需要注意的是必需和表结构对应起来,会有隐性BUG,比如说在实体中增加了字段,会导致增加修改失败
     */
    public TableStruct(String name, Class<?> cls) {
        this.name = name;

        // 获取实体中的所有字段信息,包含get、set、field
        HashMap<String, MethodField> fields = ObjectHelper.getTypeField(cls);

        // 遍历字段
        for (Map.Entry<String, MethodField> entry : fields.entrySet()) {
            // 字段信息获取
            MethodField field = entry.getValue();
            if (field.getField() == null) {
                continue;
            }
            addMethodField(field);
        }
    }

    /**
     * 添加字段
     *
     * @param field 添加字段
     */
    private void addMethodField(MethodField field) {

        int fieldAction = DaoConst.FIELD_NONE;

        // 默认后台数据库字段和前台参数字段为字段名,字段类型为class
        String fieldName = field.getName();
        String fieldInputName = field.getName();
        Class<?> fieldType = String.class;

        // 获取注解以及返回类型
        TableAnnotation annotation = null;
        if (field.getField() != null) {
            annotation = field.getField().getAnnotation(TableAnnotation.class);
            fieldType = field.getField().getType();
        }

        // 注解不为空,则修改后台数据库映射字段、字段类型
        if (annotation != null) {
            if (!StringHelper.isEmpty(annotation.value())) {
                fieldName = annotation.value();
            }
            fieldAction = annotation.type();
        }

        this.addField(fieldName, fieldInputName, fieldType, fieldAction);
    }

    /**
     * 添加额外字段
     *
     * @param fieldName      字段名称
     * @param fieldInputName 字段输入名称
     * @param fieldType      字段类型
     * @param fieldAction    字段含义
     */
    public void addField(String fieldName, String fieldInputName, Class<?> fieldType, int fieldAction) {
        // 将字段组合成输入字段
        TableFieldVo vo = new TableFieldVo(fieldName, fieldInputName, fieldType);
        // 根据字段名称规则来获取名称默认类型
        int stringAction = getStringAction(vo);
        // 判断是否属于主键
        int resultActionType = getActionType(fieldAction, stringAction);

        // 获取普通类型字段列表
        List<TableFieldVo> commonActionList = this.getFieldActionList(DaoConst.FIELD_COMMON);
        if (resultActionType == DaoConst.FIELD_PRIMARY) {
            // 将历史主键添加到普通列,并且移除历史主键
            List<TableFieldVo> primaryActionList = this.getFieldActionList(DaoConst.FIELD_PRIMARY);
            commonActionList.addAll(primaryActionList);
            primaryActionList.clear();
            // 将现有列添加到主键
            primaryActionList.add(vo);
        } else {
            // 将所有非主键列添加到普通列
            commonActionList.add(vo);

            boolean isTypeMany = resultActionType != DaoConst.FIELD_MD5
                    && resultActionType != DaoConst.FIELD_REMOVE
                    && resultActionType != DaoConst.FIELD_VERSION
                    && resultActionType != DaoConst.FIELD_COMMON;

            if (resultActionType != DaoConst.FIELD_COMMON) {
                List<TableFieldVo> actionList = this.getFieldActionList(resultActionType);
                // 处理其他特殊列
                if (isTypeMany) {
                    actionList.add(vo);
                } else if (resultActionType == fieldAction) {
                    // fieldAction 优先级高于 stringAction
                    // 假如特殊列已经存在,则将已经存在的特殊列删除,并且添加新的特殊列
                    actionList.clear();
                    actionList.add(vo);
                } else if (actionList.isEmpty()) {
                    // stringAction
                    // 假如是默认的,并且特殊列已经存在,则不进行任何处理
                    actionList.add(vo);
                }
            }
        }
    }

    /**
     * 获取字段类型
     *
     * @param fieldAction  字段类型
     * @param stringAction 字符串字段类型
     * @return 最终类型
     */
    private int getActionType(int fieldAction, int stringAction) {
        if (fieldAction != DaoConst.FIELD_NONE) {
            return fieldAction;
        } else {
            return stringAction;
        }
    }

    /**
     * 获取字符串动作类型
     *
     * @param vo 输入子弹
     * @return 获取到的自动类型
     */
    private int getStringAction(TableFieldVo vo) {
        if (getKey() == null) {
            return DaoConst.FIELD_PRIMARY;
        } else if (DaoConst.REMOVE_FLAG.equals(vo.inputLName)) {
            return DaoConst.FIELD_REMOVE;
        } else if (DaoConst.VERSION_FLAG.equals(vo.inputLName)) {
            return DaoConst.FIELD_VERSION;
        }
        // 判断是否属于统计字段
        else if (DaoConst.MD5_KEY_FLAG.equals(vo.inputLName)) {
            return DaoConst.FIELD_MD5;
        } else if (vo.inputLName.startsWith(DaoConst.UPDATE_FLAG)) {
            return DaoConst.FIELD_REMOVE_UPDATE;
        } else if (vo.inputLName.startsWith(DaoConst.CREATE_FLAG)) {
            return DaoConst.FIELD_CREATE;
        } else {
            return DaoConst.FIELD_COMMON;
        }

    }

    /**
     * 获取某个类型的所有字段
     *
     * @param type       某个类型,需要排除的类型
     * @param exceptType 需要排除的字段的类型
     * @return 字段列表
     */
    private List<TableFieldVo> getFieldActionList(int type, int... exceptType) {
        if (!typeFieldCache.containsKey(type)) {
            typeFieldCache.put(type, new ArrayList<>());
        }
        List<TableFieldVo> from = typeFieldCache.get(type);
        if (exceptType == null || exceptType.length == 0) {
            return from;
        } else {
            // 缓存需要排除的子弹
            Map<String, Boolean> exceptCache = new HashMap<>(10);
            for (int except : exceptType) {
                if (!typeFieldCache.containsKey(except)) {
                    continue;
                }
                List<TableFieldVo> exceptList = typeFieldCache.get(except);
                for (TableFieldVo exceptField : exceptList) {
                    exceptCache.put(exceptField.name, true);
                }
            }
            // 剩下的字段
            List<TableFieldVo> to = new ArrayList<>();
            for (TableFieldVo fromItem : from) {
                if (exceptCache.containsKey(fromItem.name)) {
                    continue;
                }
                to.add(fromItem);
            }
            return to;
        }
    }

    /**
     * 获取某个类型的第一个字段
     *
     * @param type 类型
     * @return 获取到的子弹
     */
    private TableFieldVo getFieldAction(int type) {
        List<TableFieldVo> list = getFieldActionList(type);
        return !list.isEmpty() ? list.get(0) : null;
    }

    /**
     * 获取所有普通子弹
     *
     * @return 所有的普通股字段
     */
    public List<TableFieldVo> getFields() {
        return getFieldActionList(DaoConst.FIELD_COMMON);
    }

    /**
     * 获取统计纬度列
     *
     * @return 获取统计纬度列
     */
    public List<TableFieldVo> getGroupLatitudeFields() {
        return getFieldActionList(DaoConst.FIELD_COMMON,
                DaoConst.FIELD_ADD_GROUP,
                DaoConst.FIELD_REPLACE_GROUP,
                DaoConst.FIELD_MD5
        );
    }

    /**
     * 获取表名
     *
     * @return 获取到的名称
     */
    public String getName() {
        return name;
    }

    /**
     * 设置表名
     *
     * @param name 设置的表名
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 主键
     *
     * @return 获取到的键值
     */
    public TableFieldVo getKey() {
        return getFieldAction(DaoConst.FIELD_PRIMARY);
    }

    /**
     * 主键名称
     *
     * @return 主键名称
     */
    public String getKeyName() {
        return this.getKey().inputName;
    }

    /**
     * 主键数据类型
     *
     * @return 主键类型
     */
    public Class<?> getKeyType() {
        return this.getKey().type;
    }

    /**
     * MD5缓存字段
     *
     * @return md5字段
     */
    public TableFieldVo getMd5Key() {
        return getFieldAction(DaoConst.FIELD_MD5);
    }

    /**
     * MD5缓存键值
     *
     * @return MD5名称
     */
    public String getMD5KeyName() {
        TableFieldVo md5Key = this.getMd5Key();
        return md5Key != null ? md5Key.inputName : null;
    }

    /**
     * 判断是否包含版本号字段
     *
     * @return 版本号字段
     */
    public TableFieldVo getVersion() {
        return getFieldAction(DaoConst.FIELD_VERSION);
    }

    /**
     * 判断是否包含remove字段
     *
     * @return 删除字段
     */
    public TableFieldVo getRemove() {
        return getFieldAction(DaoConst.FIELD_REMOVE);
    }


    /**
     * 获取删除时更新子弹
     *
     * @return 删除时更新字段
     */
    public List<TableFieldVo> getRemoveUpdate() {
        return getFieldActionList(DaoConst.FIELD_REMOVE_UPDATE);
    }

    /**
     * 获取某一列
     *
     * @param name 列名
     * @return 获取到的字段
     */
    public TableFieldVo getField(String name) {
        if (StringHelper.isEmpty(name)) {
            return null;
        }
        for (TableFieldVo fieldVo : this.getFields()) {
            if (fieldVo.lName.equals(name.toLowerCase()) || fieldVo.inputLName.equals(name.toLowerCase())) {
                return fieldVo;
            }
        }
        return null;
    }

    /**
     * 获取某一列
     *
     * @param fieldType 字段类型
     * @return 获取到的字段
     */
    public List<TableFieldVo> getFields(int fieldType) {
        return getFieldActionList(fieldType);
    }

    /**
     * 通过表结构自动生成SQL语句
     *
     * @return 初始化的表SQL语句
     */
    public void init(TableSqlCache table) {
        table.setTable(this);
        if (!StringHelper.isEmpty(this.name)) {
            table.add(
                    releaseSqlReplace(),
                    releaseSqlCreate(),
                    releaseSqlUpdate().sortCond(),
                    releaseSqlRemove().sortCond(),
                    releaseSqlLoad().sortCond(),
                    releaseSqlQuery().sortCond()
            );
        }
        initSaveWith(table);
        initAddGroup(table);
    }

    /**
     * 初始化SaveWith
     *
     * @return 初始化的表SQL语句
     */
    private void initSaveWith(TableSqlCache table) {
        List<TableFieldVo> saveWithField = getFieldActionList(DaoConst.FIELD_SAVE_WITH);
        if (saveWithField == null || saveWithField.isEmpty()) {
            return;
        }
        this.addSaveWithSql(table, DaoConst.SAVE_WITH, saveWithField);
    }

    /**
     * 初始化添加统计SQL语句
     *
     * @return 初始化的表SQL语句
     */
    private void initAddGroup(TableSqlCache table) {
        List<TableFieldVo> addGroupField = getFieldActionList(DaoConst.FIELD_ADD_GROUP);
        List<TableFieldVo> replaceGroupField = getFieldActionList(DaoConst.FIELD_REPLACE_GROUP);
        List<TableFieldVo> commonField = this.getGroupLatitudeFields();
        this.addGroupSql(table, commonField, replaceGroupField, addGroupField);
    }

    /**
     * 生成创建的SQL语句
     *
     * @return 生成的语句
     */
    private SqlData releaseSqlReplace() {
        return releaseSqlCreateReplace(DaoConst.SQL_REPLACE, DaoConst.REPLACE, DaoConst.SQL_TYPE_CREATE);
    }

    /**
     * 生成创建的SQL语句
     *
     * @return 生成的语句
     */
    private SqlData releaseSqlCreate() {
        return releaseSqlCreateReplace(DaoConst.SQL_INSERT, DaoConst.CREATE, DaoConst.SQL_TYPE_CREATE);
    }

    private SqlData releaseSqlCreateReplace(String sqlModel, String sqlName, int sqlType) {
        // 生成添加的SQL语句
        String text = sqlModel.replace(DaoConst.CODE_TABLE, this.name);
        SqlData sql = new SqlData(sqlName, text);
        sql.setSqlType(sqlType);
        // 第一个增加的字段,不需要增加 ","
        String flag = StringHelper.EMPTY;
        if (this.getKeyType() == String.class) {
            sql.addParaConst(this.getKey().inputName, DaoConst.CODE_FIELD, this.getKey().name,
                    DaoConst.CODE_VALUES, DaoConst.CODE_PARA
            );
            flag = DaoConst.CODE_SPLIT;
        }
        for (TableFieldVo field : this.getFields()) {
            sql.addParaConst(field.inputName, DaoConst.CODE_FIELD, flag + field.name,
                    DaoConst.CODE_VALUES, flag + DaoConst.CODE_PARA
            );
            flag = DaoConst.CODE_SPLIT;
        }
        return sql;
    }

    /**
     * 生成修改的SQL语句
     *
     * @return 生成的语句
     */
    private SqlData releaseSqlUpdate() {
        TableFieldVo remove = this.getRemove();
        // 生成添加的SQL语句
        String text = DaoConst.SQL_UPDATE.replace(DaoConst.CODE_TABLE, this.name);
        SqlData sql = new SqlData(DaoConst.UPDATE, text);
        sql.setSqlType(DaoConst.SQL_TYPE_UPDATE);

        // 主键字段操作
        sql.addCode(DaoConst.CODE_FIELD, String.format(DaoConst.CODE_UPDATE_PRIMARY, this.getKey().name, this.getKey().name));
        sql.addConst(this.getKey().inputName, String.format(DaoConst.CODE_WHERE_EQUALS_PARA, this.getKey().name));

        // 增加普通代码片段字段
        List<TableFieldVo> updateList = getFieldActionList(DaoConst.FIELD_COMMON,
                DaoConst.FIELD_CREATE, DaoConst.FIELD_REMOVE, DaoConst.FIELD_VERSION);
        for (TableFieldVo field : updateList) {
            sql.addParaConst(field.inputName,
                    DaoConst.CODE_FIELD, String.format(DaoConst.CODE_UPDATE_FIELD_PARA, field.name)
            );
        }

        // 设置删除标记可以通过前台传入
        if (remove != null) {
            sql.addParaConst(remove.inputName, DaoConst.CODE_FIELD, String.format(DaoConst.CODE_UPDATE_FIELD_PARA, remove.name));
        }

        // 添加删除字段
        // addWhereRemove(sql);
        addUpdateVersion(sql);
        // 添加版本号条件
        if (getVersion() != null) {
            sql.addConst(getVersion().inputName, String.format(DaoConst.CODE_WHERE_EQUALS_PARA, getVersion().name));
        }
        return sql;
    }

    /**
     * 生成删除的SQL语句
     *
     * @return 生成的语句
     */
    private SqlData releaseSqlRemove() {
        TableFieldVo remove = this.getRemove();
        if (remove != null) {
            // 生成添加的SQL语句
            String text = DaoConst.SQL_UPDATE.replace(DaoConst.CODE_TABLE, this.name);
            SqlData sql = new SqlData(DaoConst.REMOVE, text);
            sql.setSqlType(DaoConst.SQL_TYPE_REMOVE);

            // 设置删除字段标记
            sql.addCode(DaoConst.CODE_FIELD, String.format(DaoConst.CODE_UPDATE_FIELD_REMOVE, remove.name));

            // 设置删除时需要修改的字段的值
            for (TableFieldVo field : this.getFieldActionList(DaoConst.FIELD_REMOVE_UPDATE)) {
                sql.addParaConst(field.inputName,
                        DaoConst.CODE_FIELD, String.format(DaoConst.CODE_UPDATE_FIELD_PARA, field.name)
                );
            }
            // 增加版本号字段的值
            addUpdateVersion(sql);
            // 生成逻辑删除WHERE条件
            addWhereField(sql, DaoConst.CODE_TAG, true);
            return sql;
        } else {
            String text = DaoConst.SQL_REMOVE.replace(DaoConst.CODE_TABLE, this.name);
            SqlData sql = new SqlData(DaoConst.REMOVE, text);
            // 生成删除语句Where条件
            addWhereField(sql, DaoConst.CODE_TAG, true);
            return sql;
        }
    }

    private SqlData releaseSqlQuery(String sqlName, int sqlType) {
        // 生成添加的SQL语句
        String text = DaoConst.SQL_LOAD.replace(DaoConst.CODE_TABLE, this.name);
        SqlData sql = new SqlData(sqlName, text);
        sql.addParaConst(DaoConst.CODE_FIELD_DEFAULT_NAME, DaoConst.CODE_FIELD, DaoConst.CODE_FIELD_DEFAULT);
        sql.setSqlType(sqlType);
        // 生成加载语句的WHERE条件
        addWhereField(sql, DaoConst.CODE_TAG, false);

        return sql;
    }

    /**
     * 生成加载的SQL语句
     *
     * @return 生成的语句
     */
    private SqlData releaseSqlLoad() {
        return releaseSqlQuery(DaoConst.LOAD, DaoConst.SQL_TYPE_LOAD);
    }

    /**
     * 生成查询语句
     *
     * @return
     */
    private SqlData releaseSqlQuery() {
        return releaseSqlQuery(DaoConst.QUERY, DaoConst.SQL_TYPE_COMMON);
    }

    /**
     * 当前当前表所有字段的等于SQL语句
     *
     * @param sql      SDL语句
     * @param tag      标记
     * @param isRemove 是否生成删除相关字段
     * @return 生成的语句
     */
    private void addWhereField(SqlData sql, String tag, boolean isRemove) {
        addWhereBase(sql, DaoConst.CODE_WHERE, tag, isRemove, false);
        // 查询时,不能查询到非删除的字段
        addWhereRemove(sql);
    }


    /**
     * 对当前Sql语句进行扩展
     *
     * @param sql 需要扩展的SQL语句
     * @param tag 扩展标签
     */
    public void addWhereExtend(SqlData sql, String tag, boolean removeHistory, String... codes) {
        addWhereBase(sql, DaoConst.CODE_WHERE, tag, false, removeHistory, codes);
    }

    /**
     * 对当前Sql语句进行扩展
     *
     * @param sql 需要扩展的SQL语句
     * @param tag 扩展标签
     */
    public void addWhereExtend(SqlData sql, String codeName, String tag, boolean removeHistory, String... codes) {
        addWhereBase(sql, codeName, tag, false, removeHistory, codes);
    }

    private void addWhereBase(SqlData sql, String codeName, String tag, boolean isRemove, boolean removeHistory, String... codes) {
        addWhereFieldCommon(sql, codeName, this.getKey(), tag, removeHistory);

        // Where条件包含的字段
        List<TableFieldVo> fields;
        if (!isRemove) {
            // 所有字段
            fields = this.getFields();
        } else {
            // 非删除时需要更新的字段
            fields = this.getFieldActionList(DaoConst.FIELD_COMMON, DaoConst.FIELD_REMOVE_UPDATE);
        }

        List<String> codesField = new ArrayList<>();
        // 添加普通的Where条件
        for (TableFieldVo field : fields) {
            int isAdd = addWhereFieldCommon(sql, codeName, field, tag, removeHistory);
            if (isAdd != WHERE_ADD_NOT) {
                codesField.add(field.inputName);
            }
        }
        if (!codesField.isEmpty()) {
            sql.addPara(new SqlCondDefault(codesField), codes);
        }
    }

    private int addWhereFieldCommon(SqlData sql, String codeName, TableFieldVo field, String tag, boolean removeHistory) {
        addWhereFieldNotExtend(sql, field.inputName, codeName,
                String.format(DaoConst.CODE_WHERE_EQUALS, tag, field.name, DaoConst.CODE_PARA), removeHistory);
        // 添加in条件
        String sqlIn = String.format(DaoConst.CODE_WHERE_IN, tag, field.name, DaoConst.CODE_PARA);

        return addWhereFieldNotExtend(sql, DaoConst.getArrayParameterName(field.inputName), codeName,
                sqlIn, removeHistory);
    }

    private int addWhereFieldNotExtend(SqlData sql, String inputName, String codeName, String sqlWhere, boolean removeHistory) {
        SqlDataField field = sql.getField(inputName);
        if (field == null) {
            // 添加新的条件
            sql.addPara(inputName, codeName, sqlWhere);
            return WHERE_ADD;
        } else if (field != null && removeHistory) {
            // 删除历史条件
            sql.removeField(inputName);
            // 添加新的条件
            sql.addPara(inputName, codeName, sqlWhere);
            return WHERE_REMOVE_ADD;
        }
        return WHERE_ADD_NOT;
    }

    /**
     * 添加删除WHERE条件字段
     *
     * @param sql SQL语句实体
     */
    private void addWhereRemove(SqlData sql) {
        if (getRemove() != null) {
            sql.addParaConst(DaoConst.REMOVE_FLAG_INPUT,
                    DaoConst.CODE_WHERE,
                    String.format(DaoConst.CODE_WHERE_EQUALS_NOT_REMOVE, this.getRemove().name)
            );
        }
    }

    /**
     * 版本号进行累加
     *
     * @param sql 需要处理的SQL语句
     */
    private void addUpdateVersion(SqlData sql) {
        // 添加版本字段
        if (getVersion() != null) {
            sql.addCode(DaoConst.CODE_FIELD, String.format(DaoConst.CODE_UPDATE_VERSION_FIELD, getVersion().name, getVersion().name));
        }
    }

    /**
     * 生成SQL语句
     *
     * @param sqlType     SQL语句类型
     * @param name        SQL语句名称
     * @param model       SQL语句模板
     * @param valueModel  值字段模板
     * @param valueFields 值字段
     * @param whereFields WHERE字段
     * @return 生成的SQL语句
     */
    private SqlData releaseSql(int sqlType, String name, String model, String valueModel, List<TableFieldVo> valueFields, List<TableFieldVo> whereFields) {
        // 生成修改的SQL语句
        SqlData sql = new SqlData(name, model.replace(DaoConst.CODE_TABLE, this.name));
        sql.setSqlType(sqlType);
        // 生成添加的SQL语句
        String flag = StringHelper.EMPTY;
        for (TableFieldVo field : valueFields) {
            sql.addParaConst(field.inputName, DaoConst.CODE_FIELD, flag + valueModel.replace(DaoConst.CODE_FIELD, field.name));
            flag = DaoConst.CODE_SPLIT;
        }

        for (TableFieldVo field : whereFields) {
            sql.addConst(field.inputName, String.format(DaoConst.CODE_WHERE_EQUALS_PARA, field.name));
        }

        return sql;
    }

    /**
     * 根据来源字符串获取结束字符串
     *
     * @param fieldFrom 来源字符串
     * @return 返回字符串
     */
    private List<TableFieldVo> getFieldString(TableFieldString fieldFrom) {
        List<TableFieldVo> list = new ArrayList<>();
        if (fieldFrom != null) {
            for (String fieldName : fieldFrom.getFields()) {
                list.add(this.getField(fieldName));
            }
        }
        return list;
    }

    /**
     * 生成根据某些字段不存在则保存的SQL语句
     *
     * @param tableStruct 表结构
     * @param sqlName     SQL语句
     * @param whereFields WHERE条件
     */
    public void addSaveWithSql(TableSqlCache tableStruct, String sqlName, TableFieldString whereFields) {
        addSaveWithSql(tableStruct, sqlName, getFieldString(whereFields));
    }

    /**
     * 生成根据某些字段不存在则保存的SQL语句
     *
     * @param tableStruct 表结构
     * @param sqlName     SQL语句
     * @param whereFields WHERE条件
     */
    private void addSaveWithSql(TableSqlCache tableStruct, String sqlName, List<TableFieldVo> whereFields) {
        SqlData sqlData = this.releaseSql(DaoConst.SQL_TYPE_SAVE_WITH, sqlName, DaoConst.SQL_LOAD, StringHelper.EMPTY, new ArrayList<>(), whereFields);
        sqlData.addParaConst(DaoConst.CODE_FIELD_DEFAULT_NAME, DaoConst.CODE_FIELD, DaoConst.CODE_FIELD_DEFAULT);
        tableStruct.add(sqlData);
    }

    /**
     * 生成统计的SQL语句
     *
     * @param sqlTableData 需要生成的实体
     * @param whereFields  WHERE字段
     * @param addFields    需要增加的值的字段
     */
    public void addGroupSql(TableSqlCache sqlTableData, TableFieldString whereFields, TableFieldString addFields) {
        addGroupSql(sqlTableData, whereFields, null, addFields);
    }

    /**
     * 生成统计的SQL语句
     *
     * @param sqlTableData 需要生成的实体
     * @param whereFields  WHERE字段
     * @param addFields    需要增加的值的字段
     */
    public void addGroupSql(TableSqlCache sqlTableData, TableFieldString whereFields, TableFieldString replaceFields, TableFieldString addFields) {
        addGroupSql(sqlTableData, getFieldString(whereFields), getFieldString(replaceFields), getFieldString(addFields));
    }

    /**
     * 生成统计的SQL语句
     *
     * @param sqlTableData  需要生成的实体
     * @param replaceFields WHERE字段
     * @param addFields     需要增加的值的字段
     */
    private void addGroupSql(TableSqlCache sqlTableData, List<TableFieldVo> whereFields, List<TableFieldVo> replaceFields, List<TableFieldVo> addFields) {
        List<TableFieldVo> prmaryKey = this.getFieldActionList(DaoConst.FIELD_PRIMARY);
        // 生成统计加载SQL语句
        SqlData sqlLoad = this.releaseSql(DaoConst.SQL_TYPE_ADD_GROUP, DaoConst.GROUP_QUERY, DaoConst.SQL_LOAD,
                StringHelper.EMPTY, new ArrayList<>(), whereFields);
        sqlLoad.addParaConst(DaoConst.CODE_FIELD_DEFAULT_NAME, DaoConst.CODE_FIELD, DaoConst.CODE_FIELD_DEFAULT);

        // 生成统计累加SQL语句
        SqlData sqlGroupAdd = this.releaseSql(DaoConst.SQL_TYPE_ADD_GROUP, DaoConst.GROUP_ADD, DaoConst.SQL_UPDATE,
                DaoConst.CODE_GROUP_ADD, addFields, prmaryKey);
        // 当没有字段时,直接修改主键
        if (addFields.isEmpty()) {
            sqlGroupAdd.addCode(DaoConst.CODE_FIELD, String.format("%s=%s", prmaryKey.get(0).inputName, prmaryKey.get(0).inputName));
        }
        // 生成覆盖值
        if (replaceFields != null) {
            for (TableFieldVo field : replaceFields) {
                sqlGroupAdd.addPara(field.inputName, DaoConst.CODE_FIELD, String.format(",a.%s=?", field.name));
            }
        }
        sqlTableData.add(sqlLoad);
        sqlTableData.add(sqlGroupAdd);
    }

    /**
     * 生成判断数据是否存在的SQL语句
     *
     * @param sqlTableData   表结构
     * @param sqlName        SQL语句的名称
     * @param mustField      需要判断的字段
     * @param allowNullField 需要判断的字段
     */
    public void addExist(TableSqlCache sqlTableData, String sqlName, TableFieldString mustField, TableFieldString allowNullField) {
        // String[] fields
        SqlData sql = new SqlData(sqlName, DaoConst.SQL_LOAD.replace(DaoConst.CODE_TABLE, this.name));
        sql.addParaConst(DaoConst.CODE_FIELD_DEFAULT_NAME, DaoConst.CODE_FIELD, DaoConst.CODE_FIELD_DEFAULT);

        sql.setSqlType(DaoConst.SQL_TYPE_EXISTS);
        sql.addConst(this.getKey().inputName,
                String.format(DaoConst.CODE_WHERE_NOT_EQUALS_PARA, this.getKey().name)
        );

        // 必须判断的字段
        if (mustField != null && mustField.getFields() != null) {
            for (String fieldName : mustField.getFields()) {
                TableFieldVo field = this.getField(fieldName);
                sql.addConst(field.inputName,
                        String.format(DaoConst.CODE_WHERE_EQUALS_PARA, field.name)
                );
            }
        }

        // 允许空值的字段
        if (allowNullField != null && allowNullField.getFields() != null) {
            for (String fieldName : allowNullField.getFields()) {
                TableFieldVo field = this.getField(fieldName);
                sql.addConst(field.inputName,
                        String.format(DaoConst.CODE_WHERE_EQUALS_NOT_EMPTY_PARA, field.name)
                );
            }
        }
        addWhereRemove(sql);
        sqlTableData.add(sql);
    }


    /**
     * 表结构累加
     *
     * @param froms 来源数据
     * @param cls   类型
     * @param <T>
     * @return
     */
    public static <T extends GroupAdd> List<T> megerGroupAdd(List<T> froms, Class<T> cls) {
        List<T> tos = new ArrayList<>();
        Map<String, T> mapFrom = new HashMap<>();

        TableStruct tableStruct = new TableStruct(StringHelper.EMPTY, cls);
        List<TableFieldVo> fields = tableStruct.getGroupLatitudeFields();

        for (T from : froms) {
            StringBuilder sb = new StringBuilder();
            for (TableFieldVo field : fields) {
                String value = StringHelper.getFirst(ObjectHelper.getString(from, field.inputName));
                sb.append(value);
                sb.append(":");
            }

            String key = StringHelper.getIdMD5(sb.toString());
            if (!mapFrom.containsKey(key)) {
                tos.add(from);
                mapFrom.put(key, from);
            } else {
                T history = mapFrom.get(key);
                history.add(from);
            }
        }

        return tos;
    }


}