/*
 * Copyright 2006-2025 www.anyline.org
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.anyline.metadata;

import org.anyline.metadata.type.DatabaseType;
import org.anyline.metadata.type.JavaType;
import org.anyline.metadata.type.TypeMetadata;
import org.anyline.util.BasicUtil;

import java.io.Serializable;
import java.util.*;

public class Column extends TableAffiliation<Column> implements Serializable {
    private static final long serialVersionUID = 1L;

    public static LinkedHashMap<TypeMetadata.CATEGORY, TypeMetadata.Refer> typeCategoryConfigs = new LinkedHashMap<>();

    public enum TYPE implements Type{
        NORMAL(1),
        TAG(2);
        public final int value;
        TYPE(int value) {
            this.value = value;
        }
        public int value() {
            return value;
        }
    }
    public enum Aggregation {
        MIN			            ("MIN"  			    , "最小"),
        MAX			            ("MAX"  			    , "最大"),
        SUM			            ("SUM"  			    , "求和"),
        REPLACE			        ("REPLACE"  			, "替换"),                    // 对于维度列相同的行，指标列会按照导入的先后顺序，后导入的替换先导入的。
        REPLACE_IF_NOT_NULL     ("REPLACE_IF_NOT_NULL", "非空值替换"),               // 与REPLACE的区别在于对于null值，不做替换。这里要注意的是字段默认值要给NULL，而不能是空字符串，如果是空字符串，会给你替换成空字符串。
        HLL_UNION			    ("HLL_UNION"  		, "HLL 类型的列的聚合方式"),     // 通过 HyperLogLog 算法聚合
        BITMAP_UNION            ("BITMAP_UNION"  		, "BIMTAP 类型的列的聚合方式，");// 进行位图的并集聚合
        final String code;
        final String name;
        Aggregation(String code, String name) {
            this.code = code;
            this.name = name;
        }
        public String getName() {
            return name;
        }
        public String getCode() {
            return code;
        }
    }
    public static <T extends Column>  void sort(Map<String, T> columns) {
        sort(columns, false);
    }
    public static <T extends Column>  void sort(Map<String, T> columns, boolean nullFirst) {
        List<T> list = new ArrayList<>();
        list.addAll(columns.values());
        sort(list, nullFirst);
        columns.clear();
        for(T column:list) {
            columns.put(column.getName().toUpperCase(), column);
        }
    }
    public static <T extends Column>  void sort(List<T> columns) {
        sort(columns, false);
    }

    /**
     * 列排序
     * @param columns 列集合
     * @param nullFirst 未设置过位置(setPosition)的列是否排在最前面
     * @param <T> Column
     */
    public static <T extends Column>  void sort(List<T> columns, boolean nullFirst) {
        Collections.sort(columns, new Comparator<T>() {
            @Override
            public int compare(T o1, T o2) {
                Integer p1 = o1.getPosition();
                Integer p2 = o2.getPosition();
                if(p1 == p2) {
                    return 0;
                }
                if(nullFirst) {
                    if (null == p1) {
                        return -1;
                    }
                    if (null == p2) {
                        return 1;
                    }
                }else{
                    if (null == p1) {
                        return 1;
                    }
                    if (null == p2) {
                        return -1;
                    }
                }
                return p1 > p2 ? 1:-1;
            }
        });
    }
    public static class Property{
        String type;
        public Property(String type) {
            this.type = type;
        }
        public String getType() {
            return type;
        }

        public void setType(String type) {
            this.type = type;
        }
    }

    /**
     * 虚拟列属性
     */
    public static class Virtual{
        public enum TYPE{
            VIRTUAL,
            STORED;
        }
        private String expr;
        private TYPE type;

        public Virtual(){

        }
        public Virtual(String expr){
            setExpr(expr);
        }
        public Virtual(String expr, TYPE type) {
            this.type = type;
            this.expr = expr;
        }

        public TYPE getType() {
            return type;
        }

        public void setType(TYPE type) {
            this.type = type;
        }

        public String getExpr() {
            return expr;
        }

        public void setExpr(String expr) {
            this.expr = expr;
        }
    }
    protected String keyword = "COLUMN"           ;
    protected DataTypeDefine type                 ; // 数据类型
    protected Virtual virtual                     ; // 虚拟列
    protected Boolean nullable              = null; // 是否可以为NULL -1:未配置 1:是(NULL)  0:否(NOT NULL)
    protected Boolean caseSensitive         = null; // 是否区分大小写
    protected Boolean currency              = null; // 是否是货币
    protected Boolean signed                = null; // 是否可以带正负号
    protected Boolean autoIncrement         = null; // 是否自增
    protected Integer incrementSeed         = null; // 自增起始值
    protected Integer incrementStep         = null; // 自增增量
    protected Boolean primary               = null; // 是否主键
    protected String primaryType                  ; // 主键类型 如BTREE
    protected Boolean unique                = null; // 是否唯一
    protected Boolean generated             = null; // 是否generated
    protected Object defaultValue                 ; // 默认值
    protected String defaultConstraint            ; // 默认约束名
    protected String charset                      ; // 编码
    protected String collate                      ; // 排序编码
    protected Aggregation aggregation             ; //聚合类型
    protected Boolean withTimeZone          = null;
    protected Boolean withLocalTimeZone     = null;
    protected Column reference                    ; // 外键依赖列
    protected boolean isKey                       ; // doris中用到

    protected Integer position                    ; // 在表或索引中的位置, 如果需要在第一列 设置成0
    protected String order                        ; // 在索引中的排序方式ASC | DESC

    protected String after                        ; // 修改列时 在表中的位置
    protected String before                       ; // 修改列时 在表中的位置
    protected String onUpdate = null              ; // 是否在更新行时 更新这一列数据
    protected Object value                        ;
    protected boolean defaultCurrentDateTime = false;
    protected Boolean index                       ; // 是否需要创建索引(ES里用的其他数据库应该通过new Index()创建索引)
    protected Boolean store                       ; // 是否需要存储
    protected String analyzer                     ; // 分词器
    protected String searchAnalyzer               ; // 查询分词器
    protected Integer ignoreAbove                 ; // 可创建索引的最大词长度
    protected String coerce;
    protected String copyTo;
    protected String docValues;
    protected String dynamic;
    protected String eagerGlobalOrdinals;
    protected String enabled;
    protected String format;
    protected String ignoreMalformed;
    protected String indexOptions;
    protected String indexPhrases;
    protected String indexPrefixes;
    protected String meta;
    protected String fields;
    protected String normalizer;
    protected String norms;
    protected String nullValue;
    protected String positionIncrementGap;
    protected LinkedHashMap<String, Property> properties = new LinkedHashMap<>();
    protected String similarity                 ; // 相似度算法 如l2_norm dot_product cosine max_inner_product
    protected String subObjects;
    protected String termVector;
    protected ColumnFamily family;                 ; // 列族

    public Column() {
        this.type = new DataTypeDefine();
    }
    public Column(Table table, String name, String type) {
        this.type = new DataTypeDefine();
        setTable(table);
        setName(name);
        setType(type);
    }
    public Column(String name) {
        this.type = new DataTypeDefine();
        setName(name);
    }
    public Column(Schema schema, String table, String name) {
        this(null, schema, table, name);
    }
    public Column(Catalog catalog, Schema schema, String table, String name) {
        this.type = new DataTypeDefine();
        setCatalog(catalog);
        setSchema(schema);
        setName(name);
        setTable(table);
    }
    public Column(String name, String type, int precision, int scale) {
        this.type = new DataTypeDefine();
        this.name = name;
        setType(type, precision, scale);
    }

    public Column(String name, String type, int precision) {
        this.name = name;
        setType(type, precision);
    }
    public Column(Table table, String name, String type, int precision, int scale) {
        this.type = new DataTypeDefine();
        setTable(table);
        this.name = name;
        setType(type, precision, scale);
    }

    public Column(Table table, String name, String type, int precision) {
        this.type = new DataTypeDefine();
        setTable(table);
        this.name = name;
        setType(type, precision);
    }

    public Column(String name, String type) {
        this.type = new DataTypeDefine();
        this.name = name;
        setType(type);
    }

    @Override
    public void setDatabaseType(DatabaseType databaseType) {
        this.databaseType = databaseType;
        this.type.setDatabase(databaseType);
    }
    public DataTypeDefine type(){
        return type;
    }
    public Boolean getIndex() {
        return index;
    }
    public boolean isIndex() {
        return null != index && index;
    }

    public Column setIndex(Boolean index) {
        this.index = index;
        return this;
    }

    public Boolean getStore() {
        return store;
    }
    public boolean isStore() {
        return null != store && store;
    }

    public Column setStore(Boolean store) {
        this.store = store;
        return this;
    }

    public String getAnalyzer() {
        return analyzer;
    }

    public Column setAnalyzer(String analyzer) {
        this.analyzer = analyzer;
        return this;
    }
    public String getQualifier() {
        return type.getQualifier();
    }

    public Column setQualifier(String qualifier) {
        type.setQualifier(qualifier);
        return this;
    }

    public String getSearchAnalyzer() {
        return searchAnalyzer;
    }

    public Column setSearchAnalyzer(String searchAnalyzer) {
        this.searchAnalyzer = searchAnalyzer;
        return this;
    }

    public Integer getIgnoreAbove() {
        return ignoreAbove;
    }

    public Column setIgnoreAbove(Integer ignoreAbove) {
        this.ignoreAbove = ignoreAbove;
        return this;
    }

    public String getCoerce() {
        return coerce;
    }

    public Column setCoerce(String coerce) {
        this.coerce = coerce;
        return this;
    }

    public String getCopyTo() {
        return copyTo;
    }

    public Column setCopyTo(String copyTo) {
        this.copyTo = copyTo;
        return this;
    }

    public String getDocValues() {
        return docValues;
    }

    public Column setDocValues(String docValues) {
        this.docValues = docValues;
        return this;
    }

    public String getDynamic() {
        return dynamic;
    }

    public Column setDynamic(String dynamic) {
        this.dynamic = dynamic;
        return this;
    }

    public String getEagerGlobalOrdinals() {
        return eagerGlobalOrdinals;
    }

    public Column setEagerGlobalOrdinals(String eagerGlobalOrdinals) {
        this.eagerGlobalOrdinals = eagerGlobalOrdinals;
        return this;
    }

    public String getEnabled() {
        return enabled;
    }

    public Column setEnabled(String enabled) {
        this.enabled = enabled;
        return this;
    }

    public Virtual getVirtual() {
        return virtual;
    }

    public void setVirtual(Virtual virtual) {
        this.virtual = virtual;
    }

    public void setVirtual(String expr) {
        if(BasicUtil.isNotEmpty(expr)){
            this.virtual = new Virtual(expr);
        }else{
            this.virtual = null;
        }
    }
    public void setVirtual(String expr, Virtual.TYPE type) {
        this.virtual = new Virtual(expr, type);
    }

    public Integer getDimension() {
        return type.getDimension();
    }

    public Column setDimension(Integer dimension) {
        type.setDimension(dimension);
        return this;
    }

    public String getFormat() {
        return format;
    }

    public void setFormat(String format) {
        this.format = format;
    }

    public String getIgnoreMalformed() {
        return ignoreMalformed;
    }

    public Column setIgnoreMalformed(String ignoreMalformed) {
        this.ignoreMalformed = ignoreMalformed;
        return this;
    }

    public String getIndexOptions() {
        return indexOptions;
    }

    public Column setIndexOptions(String indexOptions) {
        this.indexOptions = indexOptions;
        return this;
    }

    public String getIndexPhrases() {
        return indexPhrases;
    }

    public Column setIndexPhrases(String indexPhrases) {
        this.indexPhrases = indexPhrases;
        return this;
    }

    public String getIndexPrefixes() {
        return indexPrefixes;
    }

    public Column setIndexPrefixes(String indexPrefixes) {
        this.indexPrefixes = indexPrefixes;
        return this;
    }

    public String getMeta() {
        return meta;
    }

    public Column setMeta(String meta) {
        this.meta = meta;
        return this;
    }

    public String getFields() {
        return fields;
    }

    public Column setFields(String fields) {
        this.fields = fields;
        return this;
    }

    public String getNormalizer() {
        return normalizer;
    }

    public Column setNormalizer(String normalizer) {
        this.normalizer = normalizer;
        return this;
    }

    public String getNorms() {
        return norms;
    }

    public Column setNorms(String norms) {
        this.norms = norms;
        return this;
    }

    public String getNullValue() {
        return nullValue;
    }

    public Column setNullValue(String nullValue) {
        this.nullValue = nullValue;
        return this;
    }

    public String getPositionIncrementGap() {
        return positionIncrementGap;
    }

    public Column setPositionIncrementGap(String positionIncrementGap) {
        this.positionIncrementGap = positionIncrementGap;
        return this;
    }

    public String getSimilarity() {
        return similarity;
    }

    public Column setSimilarity(String similarity) {
        this.similarity = similarity;
        return this;
    }

    public String getSubObjects() {
        return subObjects;
    }

    public Column setSubObjects(String subObjects) {
        this.subObjects = subObjects;
        return this;
    }

    public String getTermVector() {
        return termVector;
    }

    public Column setTermVector(String termVector) {
        this.termVector = termVector;
        return this;
    }
    public Column addProperty(String name, String type) {
        properties.put(name, new Property(type));
        return this;
    }
    public LinkedHashMap<String, Property> getProperties() {
        return properties;
    }

    public void setProperties(LinkedHashMap<String, Property> properties) {
        this.properties = properties;
    }

    public Column drop() {
        this.action = ACTION.DDL.COLUMN_DROP;
        return super.drop();
    }

    public void setKeyword(String keyword) {
        this.keyword = keyword;
    }
    public boolean isArray() {
        return type.isArray();
    }

    public Column setArray(boolean array) {
        type.setArray(array);
        return this;
    }

    public String getDateScale() {
        if(getmap && null != update) {
            return update.getDateScale();
        }
        return type.getDateScale();
    }

    public Boolean getWithTimeZone() {
        return withTimeZone;
    }
    public boolean isWithTimeZone() {
        return null != withLocalTimeZone && withLocalTimeZone;
    }

    public void setWithTimeZone(int withTimeZone) {
        if(withTimeZone == 0){
            this.withTimeZone = false;
        }else if(withTimeZone == 1){
            this.withTimeZone = true;
        }
    }
    public void setWithTimeZone(Boolean withTimeZone) {
        this.withTimeZone = withTimeZone;
    }

    public Boolean getWithLocalTimeZone() {
        return withLocalTimeZone;
    }

    public boolean setWithLocalTimeZone() {
        return null != withLocalTimeZone && withLocalTimeZone;
    }

    public void setWithLocalTimeZone(int withLocalTimeZone) {
        if(withLocalTimeZone == 0){
            this.withLocalTimeZone = false;
        }else if(withLocalTimeZone == 1){
            this.withLocalTimeZone = true;
        }
    }

    public Column setDateScale(String dateScale) {
        if(setmap && null != update) {
            update.setDateScale(dateScale);
            return this;
        }
        type.setDateScale(dateScale);
        return this;
    }

    public boolean isKey() {
        return isKey;
    }

    public void setKey(boolean key) {
        isKey = key;
    }

    public String getClassName() {
        if(getmap && null != update) {
            return update.getClassName();
        }
        return type.getClassName();
    }

    public Column setClassName(String className) {
        if(setmap && null != update) {
            update.setClassName(className);
            return this;
        }
        type.setClassName(className);
        return this;
    }

    public String getChildTypeName() {
        if(getmap && null != update) {
            return update.getChildTypeName();
        }
        return type.getChildName();
    }

    public Column setChildTypeName(String childTypeName) {
        if(setmap && null != update) {
            update.setChildTypeName(childTypeName);
            return this;
        }
        type.setChild(childTypeName);
        return this;
    }



    public Integer getDisplaySize() {
        if(getmap && null != update) {
            return update.getDisplaySize();
        }
        return type.getDisplaySize();
    }

    public Column setDisplaySize(Integer displaySize) {
        if(setmap && null != update) {
            update.setDisplaySize(displaySize);
            return this;
        }
        type.setDisplaySize(displaySize);
        return this;
    }
    public void setOriginType(String originType) {
        type.setOriginType(originType);
    }



    /**
     * 设置数据类型 根据数据库定义的数据类型 实际调用了setTypeName(String)
     * @param type  数据类型 如 int  varchar(10) decimal(18, 6)
     * @return Column
     */
    public Column setType(String type, int precision, int scale) {
        if(setmap && null != update) {
            update.setType(type, precision, scale);
            return this;
        }
        this.type = new DataTypeDefine(type, precision, scale);
        return this;
    }
    public Column setType(String type, int precision) {
        if(setmap && null != update) {
            update.setType(type, precision);
            return this;
        }
        this.type = new DataTypeDefine(type, precision);
        return this;
    }
    public Column setType(String type) {
        if(setmap && null != update) {
            update.setType(type);
            return this;
        }
        this.type.setName(type, true);
        return this;
    }
    public Column setType(DataTypeDefine type) {
        if(setmap && null != update) {
            update.setType(type);
            return this;
        }
        this.type = type;
        return this;
    }

    public String getTypeName() {
        if(getmap && null != update) {
            return update.getTypeName();
        }
        return type.getName();
    }

    public String getJdbcType() {
        if(getmap && null != update) {
            return update.getJdbcType();
        }
        return type.getJdbcType();
    }

    public Column setJdbcType(String jdbcType) {
        if(setmap && null != update) {
            update.setJdbcType(jdbcType);
            return this;
        }
        type.setJdbcType(jdbcType);
        return this;
    }

    public Column setTypeName(String typeName) {
        return setTypeName(typeName, true);
    }

    /**
     * 设置数据类型 根据数据库定义的数据类型
     * @param typeName 数据类型 如 int  varchar(10) decimal(18, 6)
     * @return Column
     */
    public Column setTypeName(String typeName, boolean parse) {
        if(setmap && null != update) {
            update.setTypeName(typeName, parse);
            return this;
        }
        type.setName(typeName, parse);
        return this;
    }

    /**
     *
     * @param lvl 解析阶段
     * @param database 新数据库类型
     * @return Column
     */
    public Column parseType(int lvl, DatabaseType database) {
        type.parse(lvl, database);
        return this;
    }

    public int getParseLvl() {
        return type.getParseLvl();
    }

    public void setParseLvl(int parseLvl) {
        type.setParseLvl(parseLvl);
    }

    public Column setFullType(String fullType) {
        type.setFullType(fullType);
        return this;
    }
    public String getFullType() {
        return getFullType(databaseType);
    }

    public String getFullType(DatabaseType database) {
        return getFullType(database, null);
    }
    public String getFullType(DatabaseType database, TypeMetadata.Refer refer) {
        if(getmap && null != update) {
            return update.getFullType(database);
        }
        return type.getFullType(database, refer);
    }

    /**
     * 精确长度 根据数据类型返回precision或length
     * @return Integer
     */
    public Integer getPrecisionLength() {
        return type.getPrecisionLength();
    }
    public Integer getLength() {
        if(getmap && null != update) {
            return update.getLength();
        }
        return type.getLength();
    }
    public Column resetLength(Integer length){
        String originType = type.getOriginType();
        int len = type.getLength();
        if(null != originType) {
            originType = originType.replace("(" + len, "(" + length);
            type.setOriginType(originType);
        }
        setLength(length);
        setParseLvl(0);
        return this;
    }
    public Column setLength(Integer length) {
        if(setmap && null != update) {
            update.setLength(length);
            return this;
        }
        type.setLength(length);
        //fullType = null;
        return this;
    }

    public Integer getOctetLength() {
        if(getmap && null != update) {
            return update.getOctetLength();
        }
        return type.getOctetLength();
    }
    public Column setOctetLength(Integer length) {
        if(setmap && null != update) {
            update.setOctetLength(length);
            return this;
        }
        type.setOctetLength(length);
        return this;
    }

    public Integer getPrecision() {
        if(getmap && null != update) {
            return update.getPrecision();
        }
        return type.getPrecision();
    }

    public Column setPrecision(Integer precision) {
        if(setmap && null != update) {
            update.setPrecision(precision);
            return this;
        }
        type.setPrecision(precision);
        return this;
    }
    public Column setPrecision(Integer precision, Integer scale) {
        if(setmap && null != update) {
            update.setPrecision(precision, scale);
            return this;
        }
        type.setPrecision(precision, scale);
        return this;
    }

    public Object getValue() {
        if(getmap && null != update) {
            return update.value;
        }
        return value;
    }

    public Column setValue(Object value) {
        if(setmap && null != update) {
            update.setValue(value);
            return this;
        }
        this.value = value;
        return this;
    }

    public Boolean getCaseSensitive() {
        if(getmap && null != update) {
            return update.getCaseSensitive();
        }
        return caseSensitive;
    }

    public boolean isCaseSensitive() {
        if(getmap && null != update) {
            return update.isCaseSensitive();
        }
        return null != caseSensitive && caseSensitive;
    }

    public Column setCaseSensitive(int caseSensitive) {
        if(setmap && null != update) {
            update.setCaseSensitive(caseSensitive);
            return this;
        }
        if (caseSensitive == 1) {
            this.caseSensitive = true;
        }else if (caseSensitive == 0) {
            this.caseSensitive = false;
        }
        return this;
    }
    public Column caseSensitive(int caseSensitive) {
        return setCaseSensitive(caseSensitive);
    }
    public Column caseSensitive(Boolean caseSensitive) {
        if(setmap && null != update) {
            update.caseSensitive(caseSensitive);
            return this;
        }
        this.caseSensitive = caseSensitive;
        return this;
    }

    public Boolean getCurrency() {
        if(getmap && null != update) {
            return update.currency;
        }
        return currency;
    }
    public boolean isCurrency() {
        if(getmap && null != update) {
            return update.isCurrency();
        }
        return null != currency && currency;
    }

    public Column setCurrency(int currency) {
        if(setmap && null != update) {
            update.setCurrency(currency);
            return this;
        }
        if (currency == 1) {
            this.currency = true;
        }else if (currency == 0) {
            this.currency = false;
        }

        return this;
    }
    public Column currency(int currency) {
        return setCurrency(currency);
    }
    public Column setCurrency(Boolean currency) {
        return currency(currency);
    }
    public Column currency(Boolean currency) {
        if(setmap && null != update) {
            update.currency(currency);
            return this;
        }
        this.currency = currency;
        return this;
    }

    public Boolean getSigned() {
        if(getmap && null != update) {
            return update.signed;
        }
        return signed;
    }
    public boolean isSigned() {
        if(getmap && null != update) {
            return update.isSigned();
        }
        return null != signed && signed;
    }

    public Column setSigned(int signed) {
        if(setmap && null != update) {
            update.setSigned(signed);
            return this;
        }
        if (signed == 1) {
            this.signed = true;
        }else if (signed == 0) {
            this.signed = false;
        }
        return this;
    }
    public Column signed(int signed) {
        return setSigned(signed);
    }
    public Column setSigned(Boolean signed) {
        if(setmap && null != update) {
            update.setSigned(signed);
            return this;
        }
        this.signed = signed;
        return this;
    }

    public Aggregation getAggregation() {
        if(getmap && null != update) {
            return update.aggregation;
        }
        return aggregation;
    }

    public Column setAggregation(Aggregation aggregation) {
        if(setmap && null != update) {
            update.setAggregation(aggregation);
            return this;
        }
        this.aggregation = aggregation;
        return this;
    }

    public Integer getScale() {
        if(getmap && null != update) {
            return update.getScale();
        }
        return type.getScale();
    }

    public Column setScale(Integer scale) {
        if(setmap && null != update) {
            update.setScale(scale);
            return this;
        }
        type.setScale(scale);
        return this;
    }

    public Boolean getNullable() {
        if(getmap && null != update) {
            return update.nullable;
        }
        return nullable;
    }
    public boolean isNullable() {
        if(getmap && null != update) {
            return update.isNullable();
        }
        return null != nullable && nullable;
    }

    public Column setNullable(int nullable) {
        if(setmap && null != update) {
            update.setNullable(nullable);
            return this;
        }
        if (nullable == 1) {
            this.nullable = true;
        }else if (nullable == 0) {
            this.nullable = false;
        }
        return this;
    }
    public Column nullable(int nullable) {
        return setNullable(nullable);
    }
    public Column setNullable(Boolean nullable) {
        return nullable(nullable);
    }
    public Column nullable(Boolean nullable) {
        if(setmap && null != update) {
            update.nullable(nullable);
            return this;
        }
        this.nullable = nullable;
        return this;
    }

    public Boolean getAutoIncrement() {
        if(getmap && null != update) {
            return update.autoIncrement;
        }
        return autoIncrement;
    }
    public Boolean isAutoIncrement() {
        if(getmap && null != update) {
            return update.isAutoIncrement();
        }
        return null != autoIncrement && autoIncrement;
    }

    public Column setAutoIncrement(int autoIncrement) {
        if(setmap && null != update) {
            update.setAutoIncrement(autoIncrement);
            return this;
        }
        if(autoIncrement == 1) {
            nullable(false);
            this.autoIncrement = true;
        }else if (autoIncrement == 0) {
            this.autoIncrement = false;
        }
        //fullType = null;
        return this;
    }

    public Column autoIncrement(int autoIncrement) {
        return setAutoIncrement(autoIncrement);
    }
    //不要实现 setAutoIncrement有些工具会因为参数与属性类型不一致抛出异常
    public Column setAutoIncrement(Boolean autoIncrement) {
        return autoIncrement(autoIncrement);
    }
    public Column autoIncrement(Boolean autoIncrement) {
        if(setmap && null != update) {
            update.autoIncrement(autoIncrement);
            return this;
        }
        if(null != autoIncrement) {
            if(autoIncrement) {
                nullable(false);
            }
        }
        this.autoIncrement = autoIncrement;
        return this;
    }

    /**
     * 递增列
     * @param seed 起始值
     * @param step 增量
     * @return  Column
     */
    public Column setAutoIncrement(int seed, int step) {
        if(setmap && null != update) {
            update.setAutoIncrement(seed, step);
            return this;
        }
        setAutoIncrement(1);
        this.incrementSeed= seed;
        this.incrementStep = step;
        return this;
    }

    public Boolean getUnique() {
        if(getmap && null != update) {
            return update.unique;
        }
        return unique;
    }

    public boolean isUnique() {
        if(getmap && null != update) {
            return update.isUnique();
        }
        return null != unique && unique;
    }
    public Column setUnique(int unique) {
        if(setmap && null != update) {
            update.setUnique(unique);
            return this;
        }
        if (unique == 1) {
            this.unique = true;
        }else if (unique == 0) {
            this.unique = false;
        }
        return this;
    }

    public Column unique(int unique) {
        return setUnique(unique);
    }
    public Column setUnique(Boolean unique) {
        return unique(unique);
    }
    public Column unique(Boolean unique) {
        if(setmap && null != update) {
            update.unique(unique);
            return this;
        }
        this.unique = unique;
        return this;
    }

    public Boolean getPrimaryKey() {
        if(getmap && null != update) {
            return update.primary;
        }
        return primary;
    }
    public boolean isPrimaryKey() {
        if(getmap && null != update) {
            return update.primary;
        }
        return null != primary && primary;
    }

    public Column setPrimary(int primary) {
        if(setmap && null != update) {
            update.setPrimary(primary);
            return this;
        }
        if (primary == 1) {
            this.primary = true;
        }else if (primary == 0) {
            this.primary = false;
        }
        return this;
    }
    public Column primary(int primary) {
        return setPrimary(primary);
    }
    public Column setPrimary(Boolean primary) {
        return primary(primary);
    }
    public Column setPrimaryKey(Boolean primary) {
        return primary(primary);
    }
    public Column primary(Boolean primary) {
        if(setmap && null != update) {
            update.primary(primary);
            return this;
        }
        this.primary = primary;
        return this;
    }

    public String getPrimaryType() {
        return primaryType;
    }

    public void setPrimaryType(String primaryType) {
        this.primaryType = primaryType;
    }

    public Column setPrimary(int primary, String type) {
        setPrimary(primary);
        this.primaryType = type;
        return this;
    }
    public Column primary(int primary, String type) {
        primary(primary);
        this.primaryType = type;
        return this;
    }
    public Column setPrimary(Boolean primary, String type) {
        setPrimary(primary);
        this.primaryType = type;
        return this;
    }
    public Column setPrimaryKey(Boolean primary, String type) {
        setPrimaryKey(primary);
        this.primaryType = type;
        return this;
    }
    public Column primary(Boolean primary, String type) {
        primary(primary);
        this.primaryType = type;
        return this;
    }

    public Boolean getGenerated() {
        if(getmap && null != update) {
            return update.generated;
        }
        return generated;
    }

    public boolean isGenerated() {
        if (getmap && null != update) {
            return update.isGenerated();
        }
        return null != generated && generated;
    }

    public Column setGenerated(int generated) {
        if(setmap && null != update) {
            update.setGenerated(generated);
            return this;
        }
        if (generated == 1) {
            this.generated = true;
        }else if (generated == 0) {
            this.generated = false;
        }
        return this;
    }
    public Column generated(int generated) {
       return setGenerated(generated);
    }
    public Column setGenerated(Boolean generated) {
        return generated(generated);
    }
    public Column generated(Boolean generated) {
        if(setmap && null != update) {
            update.generated(generated);
            return this;
        }
        this.generated = generated;
        return this;
    }

    public Object getDefaultValue() {
        if(getmap && null != update) {
            return update.defaultValue;
        }
        return defaultValue;
    }

    public Column setDefaultValue(Object defaultValue) {
        if(setmap && null != update) {
            update.setDefaultValue(defaultValue);
            return this;
        }
        this.defaultValue = defaultValue;
        return this;
    }
    public Column setDefaultCurrentDateTime(boolean currentDateTime) {
        if(setmap && null != update) {
            update.setDefaultCurrentDateTime(currentDateTime);
            return this;
        }
        this.defaultCurrentDateTime = currentDateTime;
        return this;
    }
    public Column setDefaultCurrentDateTime() {
        return setDefaultCurrentDateTime(true);
    }
    public boolean isDefaultCurrentDateTime() {
        return this.defaultCurrentDateTime;
    }

    public String getDefaultConstraint() {
        if(getmap && null != update) {
            return update.defaultConstraint;
        }
        return defaultConstraint;
    }

    public Column setDefaultConstraint(String defaultConstraint) {
        if(setmap && null != update) {
            update.setDefaultConstraint(defaultConstraint);
            return this;
        }
        this.defaultConstraint = defaultConstraint;
        return this;
    }

    public Integer getPosition() {
        if(getmap && null != update) {
            return update.position;
        }
        return position;
    }

    public String getOrder() {
        if(getmap && null != update) {
            return update.order;
        }
        return order;
    }

    public Column setOrder(String order) {
        if(setmap && null != update) {
            update.setOrder(order);
            return this;
        }
        this.order = order;
        return this;
    }

    public Column setPosition(Integer position) {
        if(setmap && null != update) {
            update.setPosition(position);
            return this;
        }
        this.position = position;
        return this;
    }

    public String getAfter() {
        if(getmap && null != update) {
            return update.after;
        }
        return after;
    }

    public Integer getIncrementSeed() {
        if(getmap && null != update) {
            return update.incrementSeed;
        }
        return incrementSeed;
    }

    public Column setIncrementSeed(Integer incrementSeed) {
        if(setmap && null != update) {
            update.setIncrementSeed(incrementSeed);
            return this;
        }
        this.incrementSeed = incrementSeed;
        return this;
    }

    public Integer getIncrementStep() {
        if(getmap && null != update) {
            return update.incrementStep;
        }
        return incrementStep;
    }

    public Column setIncrementStep(Integer incrementStep) {
        if(setmap && null != update) {
            update.setIncrementStep(incrementStep);
            return this;
        }
        this.incrementStep = incrementStep;
        return this;
    }

    public String getOnUpdate() {
        if(getmap && null != update) {
            return update.onUpdate;
        }
        return onUpdate;
    }

    public Column setOnUpdate(String onUpdate) {
        this.onUpdate = onUpdate;
        return this;
    }
    public Column onUpdate(String onUpdate) {
        return setOnUpdate(onUpdate);
    }


    public Column setAfter(String after) {
        if(setmap && null != update) {
            update.setAfter(after);
            return this;
        }
        this.after = after;
        return this;
    }

    public String getOriginName() {
        if(getmap && null != update) {
            return update.getOriginName();
        }
        return type.getOriginName();
    }

    public Column setOriginName(String originName) {
        if(setmap && null != update) {
            update.setOriginName(originName);
            return this;
        }
        type.setOriginName(originName);
        return this;
    }

    public String getBefore() {
        if(getmap && null != update) {
            return update.before;
        }
        return before;
    }

    public String getCharset() {
        if(getmap && null != update) {
            return update.charset;
        }
        return charset;
    }

    public Column setCharset(String charset) {
        if(setmap && null != update) {
            update.setCharset(charset);
            return this;
        }
        this.charset = charset;
        return this;
    }

    public String getLengthUnit() {
        if(getmap && null != update) {
            return update.getLengthUnit();
        }
        return type.getLengthUnit();
    }

    public Column setLengthUnit(String lengthUnit) {
        if(setmap && null != update) {
            update.setLengthUnit(lengthUnit);
            return this;
        }
        type.setLengthUnit(lengthUnit);
        return this;
    }

    public String getCollate() {
        if(getmap && null != update) {
            return update.collate;
        }
        return collate;
    }

    public Column setCollate(String collate) {
        if(setmap && null != update) {
            update.setCollate(collate);
            return this;
        }
        this.collate = collate;
        return this;
    }
    public Column setBefore(String before) {
        if(setmap && null != update) {
            update.setBefore(before);
            return this;
        }
        this.before = before;
        return this;
    }
    public boolean equals(Column column) {
        return equals(column, true);
    }
    
    public boolean equals(Column column, boolean ignoreCase) {
        if(null == column) {
            return false;
        }
        if (!BasicUtil.equals(name, column.getName(), ignoreCase)) {
            return false;
        }
        //是否相同的数据库
        //不同数据库 的数据类型对比 只对比其对应的标准类型 不细比,避免 int 与int4 不相等
        boolean sameDataBase = true;
        DatabaseType db1 = this.getDatabaseType();
        DatabaseType db2 = column.getDatabaseType();
        if(null != db1 && null != db2 && !db1.equals(db2)) {
            sameDataBase = false;
        }
        TypeMetadata columnTypeMetadata = column.getTypeMetadata();
        TypeMetadata origin = null;
        TypeMetadata columnOrigin = null;
        TypeMetadata typeMetadata = getTypeMetadata();
        if(null != typeMetadata) {
            origin = typeMetadata.getOrigin();
        }
        if(null != columnTypeMetadata) {
            columnOrigin = columnTypeMetadata.getOrigin();
        }
        if(sameDataBase){
            if(!BasicUtil.equals(typeMetadata, columnTypeMetadata, ignoreCase)
                    && !BasicUtil.equals(typeMetadata, columnOrigin, ignoreCase)
                    && !BasicUtil.equals(origin, columnTypeMetadata, ignoreCase)
                    && !BasicUtil.equals(origin, columnOrigin, ignoreCase)
            ) {
                return false;
            }
        }else{
            if(null != typeMetadata && null != columnTypeMetadata && !typeMetadata.getCategory().equals(columnTypeMetadata.getCategory())) {
                return false;
            }
        }
        if(sameDataBase || ((column.ignoreLength() == this.ignoreLength()))){
            if(null == typeMetadata || TypeMetadata.NONE == typeMetadata || 0 == typeMetadata.ignoreLength()) {
                if (!BasicUtil.equals(getLength(), column.getLength())) {
                    return false;
                }
            }
        }
        if(sameDataBase || ((column.ignorePrecision() == this.ignorePrecision()))) {
            if (null == typeMetadata || TypeMetadata.NONE == typeMetadata || 0 == typeMetadata.ignorePrecision()) {
                if (!BasicUtil.equals(getPrecision(), column.getPrecision())) {
                    return false;
                }
            }
        }
        if(sameDataBase || ((column.ignoreScale() == this.ignoreScale()))) {
            if (null == typeMetadata || TypeMetadata.NONE == typeMetadata || 0 == typeMetadata.ignoreScale()) {
                if (!BasicUtil.equals(getScale(), column.getScale())) {
                    return false;
                }
            }
        }

        if(!BasicUtil.equals(getDefaultValue(), column.getDefaultValue())) {
            return false;
        }
        if(!BasicUtil.equals(BasicUtil.evl(getComment()), BasicUtil.evl(column.getComment()))) {
            return false;
        }
        if(!BasicUtil.equals(getNullable(), column.getNullable())) {
            return false;
        }
        Boolean isAutoIncrement = getAutoIncrement();
        if(isAutoIncrement == null){
            isAutoIncrement = false;
        }
        Boolean colAutoIncrement = column.getAutoIncrement();
        if(colAutoIncrement == null){
            colAutoIncrement = false;
        }
        if(!isAutoIncrement.equals(colAutoIncrement)) {
            return false;
        }
        if(sameDataBase) {
            if (!BasicUtil.equals(getCharset(), column.getCharset(), ignoreCase)) {
                return false;
            }
        }
        if(!BasicUtil.equals(getPrimaryKey(), column.getPrimaryKey())) {
            return false;
        }
        if(sameDataBase) {
            if (null != table && table.isSort()) {
                if (!BasicUtil.equals(getPosition(), column.getPosition())) {
                    return false;
                }
            }
        }
        return true;
    }

    public TypeMetadata getTypeMetadata() {
        if(getmap && null != update) {
            return update.getTypeMetadata();
        }
        return type.getTypeMetadata();
    }

    public TypeMetadata.CATEGORY getTypeCategory() {
        return type.getTypeCategory();
    }

    public Column setTypeMetadata(TypeMetadata typeMetadata) {
        if(setmap && null != update) {
            update.setTypeMetadata(typeMetadata);
            return this;
        }
        type.setTypeMetadata(typeMetadata);
        return this;
    }

    public Column setNewName(String newName, boolean setmap, boolean getmap) {
        if(null == update) {
            update(setmap, getmap);
        }
        update.setName(newName);
        Table table = getTable();
        if(null != table) {
            //修改主键列名
            LinkedHashMap<String, Column> pks = table.getPrimaryKeyColumns();
            if(null != pks && pks.containsKey(this.getName().toUpperCase())) {
                pks.remove(this.getName().toUpperCase());
                pks.put(newName.toUpperCase(), update);
            }
        }
        return update;
    }

    public JavaType getJavaType() {
        if(getmap && null != update) {
            return update.getJavaType();
        }
        return type.getJavaType();
    }

    public Column setJavaType(JavaType javaType) {
        if(setmap && null != update) {
            update.setJavaType(javaType);
            return this;
        }
        type.setJavaType(javaType);
        return this;
    }

    public Integer getSrid() {
        if(getmap && null != update) {
            return update.getSrid();
        }
        return type.getSrid();
    }

    public Column setSrid(Integer srid) {
        if(setmap && null != update) {
            update.setSrid(srid);
            return this;
        }
        type.setSrid(srid);
        return this;
    }

    public Column getReference() {
        if(getmap && null != update) {
            return update.reference;
        }
        return reference;
    }

    public Column setReference(Column reference) {
        if(setmap && null != update) {
            update.setReference(reference);
            return this;
        }
        this.reference = reference;
        return this;
    }

    public ColumnFamily getFamily() {
        return family;
    }

    public Column setFamily(ColumnFamily family) {
        this.family = family;
        return this;
    }

    public void ignoreLength(int ignoreLength) {
        type.ignoreLength(ignoreLength);
    }

    public void maxLength(int maxLength) {
        type.maxLength(maxLength);
    }
    public void ignorePrecision(int ignorePrecision) {
        type.ignorePrecision();
    }
    public void maxPrecision(int maxPrecision) {
        type.maxPrecision(maxPrecision);
    }

    public void ignoreScale(int ignoreScale) {
        type.ignoreScale(ignoreScale);
    }
    public void maxScale(int maxScale) {
        type.maxScale(maxScale);
    }
    public int ignoreScale(DatabaseType database) {
        return type.ignoreScale(database);
    }
    public String formula(DatabaseType database) {
            return type.formula(database);
    }
    
    /**
     * 是否需要指定精度 主要用来识别能取出精度，但DDL不需要精度的类型
     * 精确判断通过adapter
     * @return boolean
     */
    public int ignoreLength() {
        return type.ignoreLength();
    }
    public int ignoreLength(DatabaseType database) {
        return type.ignoreLength(database);
    }

    public int maxLength() {
        return type.maxLength();
    }
    public int maxLength(DatabaseType database) {
        return type.maxLength(database);
    }

    /**
     * 是否需要指定精度 主要用来识别能取出精度，但DDL不需要精度的类型
     * 精确判断通过adapter
     * @return boolean
     */
    public int ignorePrecision() {
        return type.ignorePrecision();
    }

    public int ignorePrecision(DatabaseType database) {
        return type.ignorePrecision(database);
    }

    public int maxPrecision() {
        return type.maxPrecision();
    }

    public int maxPrecision(DatabaseType database) {
        return type.maxPrecision(database);
    }

    public String getFinalType() {
        return type.getFinalType();
    }

    public Column setFinalType(String finalType) {
        type.setFinalType(finalType);
        return this;
    }

    /**
     * 是否需要指定精度 主要用来识别能取出精度，但DDL不需要精度的类型
     * 精确判断通过adapter
     * @return boolean
     */
    public int ignoreScale() {
        return type.ignoreScale();
    }
    public int maxScale() {
        return type.maxScale();
    }
    public int maxScale(DatabaseType database) {
        return type.maxScale(database);
    }

    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append(name).append(" ");
        builder.append(getFullType());
        if(BasicUtil.isNotEmpty(defaultValue)) {
            builder.append(" default ").append(defaultValue);
        }
        return builder.toString();
    }
    public String keyword() {
        return this.keyword;
    }

/* ********************************* field refer ********************************** */
    public static final String FIELD_TYPE_CATEGORY_CONFIG          = "TYPE_CATEGORY_CONFIG";
    public static final String FIELD_KEYWORD                       = "KEYWORD";
    public static final String FIELD_DIMS                          = "DIMS";
    public static final String FIELD_CLASS_NAME                    = "CLASS_NAME";
    public static final String FIELD_DISPLAY_SIZE                  = "DISPLAY_SIZE";
    public static final String FIELD_CHILD_TYPE_NAME               = "CHILD_TYPE_NAME";
    public static final String FIELD_CHILD_TYPE_METADATA           = "CHILD_TYPE_METADATA";
    public static final String FIELD_JAVA_TYPE                     = "JAVA_TYPE";
    public static final String FIELD_JDBC_TYPE                     = "JDBC_TYPE";
    public static final String FIELD_DATE_SCALE                    = "DATE_SCALE";
    public static final String FIELD_NULLABLE                      = "NULLABLE";
    public static final String FIELD_CASE_SENSITIVE                = "CASE_SENSITIVE";
    public static final String FIELD_CURRENCY                      = "CURRENCY";
    public static final String FIELD_SIGNED                        = "SIGNED";
    public static final String FIELD_AUTO_INCREMENT                = "AUTO_INCREMENT";
    public static final String FIELD_AUTO_INCREMENT_CHECK          = "AUTO_INCREMENT_CHECK";
    public static final String FIELD_AUTO_INCREMENT_CHECK_VALUE    = "AUTO_INCREMENT_CHECK_VALUE";
    public static final String FIELD_INCREMENT_SEED                = "INCREMENT_SEED";
    public static final String FIELD_INCREMENT_STEP                = "INCREMENT_STEP";
    public static final String FIELD_PRIMARY                       = "PRIMARY";
    public static final String FIELD_PRIMARY_CHECK                 = "PRIMARY_CHECK";
    public static final String FIELD_PRIMARY_CHECK_VALUE           = "PRIMARY_CHECK_VALUE";
    public static final String FIELD_PRIMARY_TYPE                  = "PRIMARY_TYPE";
    public static final String FIELD_UNIQUE                        = "UNIQUE";
    public static final String FIELD_GENERATED                     = "GENERATED";
    public static final String FIELD_DEFAULT_VALUE                 = "DEFAULT_VALUE";
    public static final String FIELD_DEFAULT_CONSTRAINT            = "DEFAULT_CONSTRAINT";
    public static final String FIELD_CHARSET                       = "CHARSET";
    public static final String FIELD_COLLATE                       = "COLLATE";
    public static final String FIELD_AGGREGATION                   = "AGGREGATION";
    public static final String FIELD_WITH_TIME_ZONE                = "WITH_TIME_ZONE";
    public static final String FIELD_WITH_LOCAL_TIME_ZONE          = "WITH_LOCAL_TIME_ZONE";
    public static final String FIELD_SRID                          = "SRID";
    public static final String FIELD_ARRAY                         = "ARRAY";
    public static final String FIELD_ARRAY_CHECK                   = "ARRAY_CHECK";
    public static final String FIELD_ARRAY_CHECK_VALUE             = "ARRAY_CHECK_VALUE";
    public static final String FIELD_IS_KEY                        = "IS_KEY";
    public static final String FIELD_IS_KEY_CHECK                  = "IS_KEY_CHECK";
    public static final String FIELD_IS_KEY_CHECK_VALUE            = "IS_KEY_CHECK_VALUE";
    public static final String FIELD_POSITION                      = "POSITION";
    public static final String FIELD_ORDER                         = "ORDER";
    public static final String FIELD_AFTER                         = "AFTER";
    public static final String FIELD_BEFORE                        = "BEFORE";
    public static final String FIELD_ON_UPDATE                     = "ON_UPDATE";
    public static final String FIELD_ON_UPDATE_CHECK               = "ON_UPDATE_CHECK";
    public static final String FIELD_ON_UPDATE_CHECK_VALUE         = "ON_UPDATE_CHECK_VALUE";
    public static final String FIELD_VALUE                         = "VALUE";
    public static final String FIELD_DEFAULT_CURRENT_DATE_TIME     = "DEFAULT_CURRENT_DATE_TIME";
    public static final String FIELD_DEFAULT_CURRENT_DATE_TIME_CHECK = "DEFAULT_CURRENT_DATE_TIME_CHECK";
    public static final String FIELD_DEFAULT_CURRENT_DATE_TIME_CHECK_VALUE = "DEFAULT_CURRENT_DATE_TIME_CHECK_VALUE";
    public static final String FIELD_INDEX                         = "INDEX";
    public static final String FIELD_INDEX_CHECK                   = "INDEX_CHECK";
    public static final String FIELD_INDEX_CHECK_VALUE             = "INDEX_CHECK_VALUE";
    public static final String FIELD_STORE                         = "STORE";
    public static final String FIELD_STORE_CHECK                   = "STORE_CHECK";
    public static final String FIELD_STORE_CHECK_VALUE             = "STORE_CHECK_VALUE";
    public static final String FIELD_ANALYZER                      = "ANALYZER";
    public static final String FIELD_SEARCH_ANALYZER               = "SEARCH_ANALYZER";
    public static final String FIELD_IGNORE_ABOVE                  = "IGNORE_ABOVE";
    public static final String FIELD_COERCE                        = "COERCE";
    public static final String FIELD_COPY_TO                       = "COPY_TO";
    public static final String FIELD_DOC_VALUES                    = "DOC_VALUES";
    public static final String FIELD_DYNAMIC                       = "DYNAMIC";
    public static final String FIELD_EAGER_GLOBAL_ORDINALS         = "EAGER_GLOBAL_ORDINALS";
    public static final String FIELD_ENABLED                       = "ENABLED";
    public static final String FIELD_FORMAT                        = "FORMAT";
    public static final String FIELD_IGNORE_MALFORMED              = "IGNORE_MALFORMED";
    public static final String FIELD_INDEX_OPTIONS                 = "INDEX_OPTIONS";
    public static final String FIELD_INDEX_PHRASES                 = "INDEX_PHRASES";
    public static final String FIELD_INDEX_PREFIXES                = "INDEX_PREFIXES";
    public static final String FIELD_META                          = "META";
    public static final String FIELD_FIELDS                        = "FIELDS";
    public static final String FIELD_NORMALIZER                    = "NORMALIZER";
    public static final String FIELD_NORMS                         = "NORMS";
    public static final String FIELD_NULL_VALUE                    = "NULL_VALUE";
    public static final String FIELD_POSITION_INCREMENT_GAP        = "POSITION_INCREMENT_GAP";
    public static final String FIELD_PROPERTY                     = "PROPERTY";
    public static final String FIELD_SIMILARITY                    = "SIMILARITY";
    public static final String FIELD_SUB_OBJECTS                   = "SUB_OBJECTS";
    public static final String FIELD_TERM_VECTOR                   = "TERM_VECTOR";
    public static final String FIELD_PARSE_LVL                     = "PARSE_LVL";
    public static final String FIELD_FIELD_FAMILY                  = "FAMILY ";
}