package com.yanzuoguang.dao.impl;

import com.yanzuoguang.dao.DaoConst;
import com.yanzuoguang.dao.cond.SqlCond;
import com.yanzuoguang.dao.cond.SqlCondDefault;
import com.yanzuoguang.util.helper.StringFormatHandle;
import com.yanzuoguang.util.helper.StringHelper;

import java.util.ArrayList;
import java.util.List;

/**
 * SQL语句基本信息
 *
 * @author 颜佐光
 */
public class SqlData {

    /**
     * SQL语句类型
     */
    private int sqlType = DaoConst.SQL_TYPE_COMMON;

    /**
     * SQL语句的名称
     */
    private String name;

    /**
     * SQL语句
     */
    private String sql;

    /**
     * 对应的参数顺序
     */
    private List<SqlDataField> sqlDataFields = new ArrayList<SqlDataField>();

    /**
     * 构造函数
     */
    public SqlData() {
        this("", "");
    }

    /**
     * SQL语句的基本信息
     *
     * @param name  SQL语句的名称
     * @param sql   需要执行的SQL语句,其中可以包含大括号括起来的代码片段。 如: {WHERE}
     * @param paras SQL语句参数名称数组
     */
    public SqlData(String name, String sql, String... paras) {
        this.name = name;
        this.sql = sql;
        for (String input : paras) {
            this.add(input);
        }
    }

    /**
     * Sql语句类型
     *
     * @return Sql语句类型
     */
    public int getSqlType() {
        return sqlType;
    }

    /**
     * Sql语句类型
     *
     * @param sqlType Sql语句类型
     */
    public SqlData setSqlType(int sqlType) {
        this.sqlType = sqlType;
        return this;
    }

    public String getName() {
        return name;
    }


    /**
     * 交换SQL语句中的{LIMIT}和{LIMIT_END}
     *
     * @return
     */
    public SqlData switchLimit() {
        this.sql = StringHelper.getFormat(this.sql, StringHelper.EMPTY, new StringFormatHandle() {
            @Override
            public void addPos(StringBuilder sb, String group, String fieldFull, String field, String command) {
                if (StringHelper.compare(group, DaoConst.CODE_LIMIT)) {
                    sb.append(DaoConst.CODE_LIMIT_OUTER);
                } else if (StringHelper.compare(group, DaoConst.CODE_LIMIT_OUTER)) {
                    sb.append(DaoConst.CODE_LIMIT);
                } else {
                    sb.append(group);
                }
            }
        });
        return this;
    }

    /**
     * 设置SQL语句名称
     *
     * @param name SQL语句名称
     * @return
     */
    public SqlData setName(String name) {
        this.name = name;
        return this;
    }


    /**
     * 获取SQL语句
     *
     * @return
     */
    public String getSql() {
        return sql;
    }

    /**
     * 设置SQL语句
     *
     * @param sql
     * @return
     */
    public SqlData setSql(String sql) {
        this.sql = sql;
        return this;
    }

    /**
     * 获取SQL语句字段
     *
     * @return
     */
    public List<SqlDataField> getSqlDataFields() {
        return sqlDataFields;
    }

    /**
     * 设置SQL语句字段
     *
     * @param sqlDataFields
     * @return
     */
    public SqlData setSqlDataFields(List<SqlDataField> sqlDataFields) {
        this.sqlDataFields = sqlDataFields;
        return this;
    }


    /**
     * 根据字段名称获取字段
     *
     * @param fieldName
     * @return
     */
    public SqlDataField getField(String fieldName) {
        SqlCondDefault cond = new SqlCondDefault(fieldName);
        return getField(cond);
    }


    /**
     * 根据字段名称获取字段
     *
     * @param sqlCond
     * @return
     */
    public SqlDataField getField(SqlCond sqlCond) {
        for (SqlDataField sqlDataField : this.sqlDataFields) {
            if (sqlDataField.getCond().equals(sqlCond)) {
                return sqlDataField;
            }
        }
        return null;
    }

    /**
     * 设置所有字段自动
     *
     * @param auto 自动
     * @return
     */
    public SqlData setFieldAuto(boolean auto) {
        for (SqlDataField sqlDataField : this.sqlDataFields) {
            sqlDataField.setAuto(auto);
        }
        return this;
    }

    /**
     * 按照一种类型添加SQL语句
     *
     * @param clsModel 实体
     * @param tag      标签
     * @return
     */
    public SqlData add(Class<?> clsModel, String tag, String... codes) {
        return this.add(clsModel, tag, false, codes);
    }

    /**
     * 按照一种类型添加SQL语句
     *
     * @param clsModel 实体
     * @param tag      标签
     * @return
     */
    public SqlData add(Class<?> clsModel, String tag, boolean removeFlag, String... codes) {
        // 生成表结构
        TableStruct table = new TableStruct(StringHelper.EMPTY, clsModel);
        table.addWhereExtend(this, tag, removeFlag, codes);
        return this;
    }

    /**
     * 添加参数,当在SQL语句中存在参数时,用于处理。{@id} 代表前台输入参数字段为id
     * 例子:
     * SqlData sql = new SqlData("SQL_NAME","SELECT * FROM TABLE WHERE id=?");
     * sql.add( "id" );
     * 最终SQL语句为:
     * SELECT * FROM TABLE WHERE id={id}"
     *
     * @param paraName 前台参数名称
     */
    public SqlData add(String paraName) {
        return addCodeExecute(getCondDefault(paraName), "", false);
    }

    /**
     * 当前台参数传入值时,在 {WHERE} 条件中增加条件,并增加附加的代码片段
     * <p>
     * 例子:
     * SqlData sql = new SqlData("SQL_NAME","SELECT * FROM TABLE {INNER} WHERE 1=1 {WHERE}");
     * sql.add("id" , " AND id = ? ",
     * "{INNER}", " INNER JOIN TABLE_B "
     * );
     * 最终SQL语句为: (1=1 AND 会自动去掉)
     * SELECT * FROM TABLE INNER JOIN TABLE_B WHERE id = {@id}
     *
     * @param paraName 前台参数名称
     * @param condSql  {WHERE}代码片段中的条件
     * @param codes    扩展代码片段
     */
    public SqlData add(String paraName, String condSql, String... codes) {
        return add(getCondDefault(paraName), condSql, codes);
    }

    /**
     * 当前台参数传入值时,在 {WHERE} 条件中增加条件,并增加附加的代码片段
     * <p>
     * 例子:
     * SqlData sql = new SqlData("SQL_NAME","SELECT * FROM TABLE {INNER} WHERE 1=1 {WHERE}");
     * sql.add("id" , " AND id = ? ",
     * "{INNER}", " INNER JOIN TABLE_B "
     * );
     * 最终SQL语句为: (1=1 AND 会自动去掉)
     * SELECT * FROM TABLE INNER JOIN TABLE_B WHERE id = {@id}
     *
     * @param cond    前台参数对应的条件
     * @param condSql {WHERE}代码片段中的条件
     * @param codes   扩展代码片段
     */
    public SqlData add(SqlCond cond, String condSql, String... codes) {
        return addCodeExecute(cond, condSql, true, codes);
    }


    /**
     * 当前台参数传入值时,增加附加的代码片段
     * <p>
     * 例子:
     * SqlData sql = new SqlData("SQL_NAME","SELECT * FROM TABLE {INNER} WHERE 1=1 {WHERE}");
     * sql.addPara("id" ,
     * "{WHERE}", " AND id = ? ",
     * "{INNER}", " INNER JOIN TABLE_B "
     * );
     * 最终SQL语句为: (1=1 AND 会自动去掉)
     * SELECT * FROM TABLE INNER JOIN TABLE_B WHERE id = {@id}
     *
     * @param paraName 字段
     * @param codes    代码片段
     */
    public SqlData addPara(String paraName, String... codes) {
        return addPara(getCondDefault(paraName), codes);
    }

    /**
     * 当前台参数传入值时,增加附加的代码片段
     * <p>
     * 例子:
     * SqlData sql = new SqlData("SQL_NAME","SELECT * FROM TABLE {INNER} WHERE 1=1 {WHERE}");
     * sql.addPara("id" ,
     * "{WHERE}", " AND id = ? ",
     * "{INNER}", " INNER JOIN TABLE_B "
     * );
     * 最终SQL语句为: (1=1 AND 会自动去掉)
     * SELECT * FROM TABLE INNER JOIN TABLE_B WHERE id = {@id}
     *
     * @param cond  字段
     * @param codes 代码片段
     */
    public SqlData addPara(SqlCond cond, String... codes) {
        return addCodeExecute(cond, "", true, codes);
    }

    /**
     * 添加常规代码片段,即不论如何都会将该代码片段增加到SQL语句中。
     * 例子:
     * SqlData sql = new SqlData("SQL_NAME","SELECT * FROM TABLE {INNER} WHERE 1=1 {WHERE}");
     * sql.addCode(
     * "{INNER}", " INNER JOIN TABLE_B " ,
     * "{WHERE}", " AND 1=1" ,
     * );
     * 最终SQL语句为: (1=1 AND 会自动去掉)
     * SELECT * FROM TABLE INNER JOIN TABLE_B WHERE 1=1"
     *
     * @param codes 代码片段
     */
    public SqlData addCode(String... codes) {
        return addCodeExecute(getCondDefault(StringHelper.EMPTY), "", false, codes);
    }

    /**
     * 不论前台参数是否有值,在 {WHERE} 条件中增加条件,并增加附加的代码片段
     * <p>
     * 例子:
     * SqlData sql = new SqlData("SQL_NAME","SELECT * FROM TABLE {INNER} WHERE 1=1 {WHERE}");
     * sql.add("id" , " AND id = ? ",
     * "{INNER}", " INNER JOIN TABLE_B "
     * );
     * 最终SQL语句为: (1=1 AND 会自动去掉)
     * SELECT * FROM TABLE INNER JOIN TABLE_B WHERE id = {@id}
     *
     * @param paraName 前台参数名称
     * @param cond     {WHERE}代码片段中的条件
     * @param codes    扩展代码片段
     */
    public SqlData addConst(String paraName, String cond, String... codes) {
        return addCodeExecute(getCondDefault(paraName), cond, false, codes);
    }

    /**
     * 不论前台参数是否有值,增加代码片段
     * <p>
     * 例子:
     * SqlData sql = new SqlData("SQL_NAME","SELECT * FROM TABLE {INNER} WHERE 1=1 {WHERE}");
     * sql.addPara("id" ,
     * "{WHERE}", " AND id = ? ",
     * "{INNER}", " INNER JOIN TABLE_B "
     * );
     * 最终SQL语句为: (1=1 AND 会自动去掉)
     * SELECT * FROM TABLE INNER JOIN TABLE_B WHERE id = {@id}
     *
     * @param paraName 前台参数名称
     * @param codes    代码片段
     */
    public SqlData addParaConst(String paraName, String... codes) {
        return addCodeExecute(getCondDefault(paraName), "", false, codes);
    }

    /**
     * 添加SQL语句的执行方法
     *
     * @param condInput 输入条件
     * @param condSql   包含条件的Sql语句
     * @param auto      未false时表示属于必须输入的参数
     * @param codes     代码片段
     * @return
     */
    private SqlData addCodeExecute(SqlCond condInput, String condSql, boolean auto, String... codes) {
        SqlDataField sql = new SqlDataField(condInput, condSql);
        for (String code : codes) {
            sql.getCodes().add(code);
        }
        sql.setAuto(auto);
        this.sqlDataFields.add(sql);
        return this;
    }


    /**
     * 删除字段
     *
     * @param fieldName 字段名称
     * @return
     */
    public SqlData removeField(String fieldName) {
        SqlCondDefault cond = new SqlCondDefault(fieldName);
        return this.removeField(cond);
    }

    /**
     * 删除字段
     *
     * @param sqlCond 条件信息
     * @return
     */
    public SqlData removeField(SqlCond sqlCond) {
        SqlDataField field = this.getField(sqlCond);
        if (field != null) {
            this.sqlDataFields.remove(field);
        }
        return this;
    }

    /**
     * 删除删除标记字段
     *
     * @return
     */
    public SqlData removeFieldRemove() {
        this.removeField(DaoConst.REMOVE_FLAG_INPUT);
        return this;
    }


    /**
     * 将当前SQL语句进行复制
     *
     * @return 复制的结果
     */
    public SqlData copy() {
        SqlData to = new SqlData(this.name, this.sql);
        for (SqlDataField sqlDataField : this.sqlDataFields) {
            to.sqlDataFields.add(sqlDataField.copy());
        }
        return to;
    }


    /**
     * 条件排序
     */
    public SqlData sortCond() {
        this.sqlDataFields = SqlCondUtil.sortCond(this.sqlDataFields);
        return this;
    }

    /**
     * 获取默认条件
     *
     * @param paraName
     * @return
     */
    public static SqlCond getCondDefault(String paraName) {
        return new SqlCondDefault(paraName);
    }
}