package com.yanzuoguang.dao.impl;

import com.yanzuoguang.dao.DaoConst;

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

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

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

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

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

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

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

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

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

    public List<SqlDataField> getSqlDataFields() {
        return sqlDataFields;
    }

    public void setSqlDataFields(List<SqlDataField> sqlDataFields) {
        this.sqlDataFields = sqlDataFields;
    }

    public String getName() {
        return name;
    }

    public String getSql() {
        return sql;
    }

    public void setSql(String sql) {
        this.sql = sql;
    }

    /**
     * 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);
        }
    }

    /**
     * 根据字段名称获取字段
     *
     * @param fieldName
     * @return
     */
    public SqlDataField getField(String fieldName) {
        String to = fieldName.toLowerCase().replaceAll("_", "");
        for (SqlDataField sqlDataField : this.sqlDataFields) {
            if (to.equals(sqlDataField.paraName.toLowerCase())) {
                return sqlDataField;
            }
        }
        return null;
    }

    /**
     * 添加参数,当在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(paraName, "", false);
    }

    /**
     * 添加常规代码片段,即不论如何都会将该代码片段增加到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("", "", 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 add(String paraName, String cond, String... codes) {
        return addCodeExecute(paraName, cond, 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 addCodeExecute(paraName, "", true, 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(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(paraName, "", false, codes);
    }

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

    /**
     * 删除字段
     *
     * @param fieldName 字段名称
     * @return
     */
    public SqlData removeField(String fieldName) {
        SqlDataField field = this.getField(fieldName);
        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;
    }

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