package cn.enilu.flash.code;


import org.nutz.lang.Strings;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 属性（数据库列）基本信息描述<br>
 * 作者: zhangtao <br>
 * 创建日期: 16-7-5<br>
 */
public class ColumnDescriptor {
    private static Map<String, Class<?>> typeMapping = new HashMap<String, Class<?>>();

    static {
        typeMapping.put("varchar", String.class);
        typeMapping.put("enum", String.class);
        typeMapping.put("bigint", Long.class);
        typeMapping.put("long", Long.class);
        typeMapping.put("integer", Integer.class);
        typeMapping.put("float", Float.class);
        typeMapping.put("double", Double.class);
        typeMapping.put("int", Integer.class);
        typeMapping.put("timestamp", Integer.class);
        typeMapping.put("datetime", Integer.class);
        typeMapping.put("boolean", boolean.class);
        typeMapping.put("tinyint", boolean.class);
        typeMapping.put("bool", boolean.class);
        typeMapping.put("decimal", BigDecimal.class);
    }
//	private static Map<String, Class<?>> validationRules = new HashMap<String,Class<?>>();

    static {

    }

    private static Map<String, String> labelMapping = new HashMap<String, String>();

    static {

        labelMapping.put("id", "ID");
        labelMapping.put("opAt", "操作时间");
        labelMapping.put("opBy", "操作人");
        labelMapping.put("delFlag", "删除标记");
    }

    public static class Validation {
        public final Class<?> klass;
        private final String annotation;

        public Validation(Class<?> klass, String annotation) {
            this.klass = klass;
            this.annotation = annotation;
        }

        public String getAnnotation() {
            return annotation;
        }
    }

    private static Pattern COLUMN_TYPE_PATTERN = Pattern
            .compile("^(\\w+)(?:\\((\\d+)\\))?");
    private static Pattern ENUM_PATTERN = Pattern.compile("enum\\((.+)\\)");

    public String columnName;
    private String label;
    public boolean primary;
    public String dataType;

    public String columnType;
    public int size;

    public boolean nullable;
    private Object defaultValue;
    private String comment;
    private String fieldName;

    private List<String> enumValues = new ArrayList<String>();

    private List<Validation> validations = new ArrayList<Validation>();
    private boolean validationBuilt = false;

    private String queryOperator;


    private boolean containsValidation(Class<?> klass) {
        for (Validation v : validations) {
            if (v.klass == klass) {
                return true;
            }
        }
        return false;
    }

    public boolean hasLabel() {
        return label != null;
    }

    public void setLabel(String label) {
        this.label = label;
    }

    public String getLabel() {
        if (label != null) {
            return label;
        }
        String defaultLabel = labelMapping.get(columnName);
        if (defaultLabel != null) {
            return defaultLabel;
        }
        return label;
    }

    public String getComment() {
        return comment;
    }

    public void setComment(String comment) {
        this.comment = comment;
        if (comment == null) {
            return;
        }

        extractLabel(comment);
        extractSearchable(comment);
    }

    Pattern labelPattern = Pattern.compile("label:\\s*([^,;，]+)");

    private void extractLabel(String comment) {
        Matcher m = labelPattern.matcher(comment);
        if (m.find()) {
            this.label = m.group(1);
        }
    }

    public String getQueryOperator() {
        return queryOperator;
    }

    Pattern queryPattern = Pattern.compile("searchable:\\s*(\\w+)");

    private void extractSearchable(String comment) {
        // searchable: eq
        Matcher m = queryPattern.matcher(comment);
        if (m.find()) {
            queryOperator = m.group(1);
        }
    }

    public String getColumnName() {
        return columnName;
    }

    public String getFieldName() {
        if (Strings.isBlank(fieldName)) {
            return Utils.lowerCamel(columnName);
        }
        return fieldName;
    }

    public void setFieldName(String fieldName) {
        this.fieldName = fieldName;
    }

    public List<String> getEnumValues() {
        return enumValues;
    }

    public void setColumnType(String columnType) {
        Matcher m = ENUM_PATTERN.matcher(columnType);
        if (m.find()) {
            this.columnType = "enum";

            String s = m.group(1);
            for (String v : s.split(",")) {
                v = v.trim().replaceAll("'", "");
                enumValues.add(v);
            }
            return;
        }

        m = COLUMN_TYPE_PATTERN.matcher(columnType);
        if (m.find()) {
            if (m.group(2) != null) {
                this.size = Integer.parseInt(m.group(2));
            }
            this.columnType = m.group(1);
        } else {
            throw new IllegalArgumentException();
        }
    }

    public String getJavaType() {
        if ("tinyint".equalsIgnoreCase(dataType) && size == 1) {
            return boolean.class.getName();
        }
        if ("enum".equalsIgnoreCase(dataType)) {
            return getUpperJavaFieldName();
        }
        Class<?> type = typeMapping.get(dataType);
        if (type != null) {
            return type.getName();
        }

        return String.class.getName();
    }

    public String getSimpleJavaTypeName() {
        return getJavaType().replaceFirst("^.*\\.", "");
    }

    public boolean isEnum() {
        return "enum".equalsIgnoreCase(dataType);
    }

    public boolean isBoolean() {
        return boolean.class.getName().equals(getJavaType());
    }

    public boolean isTimestamp() {
        return "timestamp".equalsIgnoreCase(dataType);
    }

    public String getUpperJavaFieldName() {
        return Utils.lowerCamel(columnName);
//		return CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.upperCamel,
//				columnName);
    }

    public String getGetterMethodName() {
        if (isBoolean()) {
            return "is" + getUpperJavaFieldName();
        }
        return "get" + getUpperJavaFieldName();
    }

    public String getSetterMethodName() {
        return "set" + getUpperJavaFieldName();
    }

    public String getColumnAnnotation() {
        if (primary) {
//			return "@Id";
            return "@Name\r\n	@Prev(els = {@EL(\"uuid()\")})";
        }
        return "@Column";
    }

    public void setDefaultValue(Object v) {
        this.defaultValue = v;
    }

    public Object getDefaultValue() {
        return defaultValue;
    }

    public String getDefaultValueCode() {
        if (isEnum()) {
            return getSimpleJavaTypeName() + "." + defaultValue;
        }
        if (isBoolean()) {
            if ("1".equals(defaultValue.toString())) {
                return "true";
            } else {
                return "false";
            }
        }
        if (isTimestamp()) {
            if (("0000-00-00 00:00:00".equals(defaultValue) || "CURRENT_TIMESTAMP"
                    .equals(defaultValue))) {
                return "DateTime.now()";
            }
        }
        if (defaultValue != null && Long.class.getName().equals(getJavaType())) {
            return defaultValue + "L";
        }
        if (defaultValue != null && BigDecimal.class.getName().equals(getJavaType())) {
            return "new BigDecimal(\"" + defaultValue.toString() + "\")";
        }
        return "\"" + getDefaultValue().toString() + "\"";
    }

    public String getValidationFormClass() {
        return "";
    }

}
