package sharin.sql.generator;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Table;

public class EntityInfo {

    private final Class<?> entityClass;

    private final String tableName;

    private final Map<String, String> columnNameMap;

    private final String idColumnName;

    private final String[] propertyNames;

    public EntityInfo(Class<?> entityClass) {
        this(entityClass, null, null, null);
    }

    public EntityInfo(Class<?> entityClass, String tableName,
            Map<String, String> columnNameMap, String idColumnName) {

        this.entityClass = entityClass;

        /* tableName */

        if (tableName == null || tableName.length() == 0) {
            Table table = entityClass.getAnnotation(Table.class);

            if (table != null) {
                tableName = table.name();

            } else {
                tableName = entityClass.getSimpleName();
            }
        }

        this.tableName = tableName;

        /* columnNameMap */

        if (columnNameMap == null) {
            columnNameMap = new HashMap<String, String>();

        } else {
            columnNameMap = new HashMap<String, String>(columnNameMap);
        }

        Class<?> clazz = entityClass;

        while (true) {

            if (clazz == Object.class) {
                break;
            }

            for (Field field : clazz.getDeclaredFields()) {

                if ((field.getModifiers() & (Modifier.STATIC | Modifier.TRANSIENT)) != 0) {
                    continue;
                }

                String fieldName = field.getName();
                Column column = field.getAnnotation(Column.class);

                if (!columnNameMap.containsKey(fieldName)) {

                    if (column != null) {
                        columnNameMap.put(fieldName, column.name());

                    } else {
                        columnNameMap.put(fieldName, fieldName);
                    }
                }

                if (idColumnName == null) {
                    Id id = field.getAnnotation(Id.class);

                    if (id != null) {
                        idColumnName = (column == null) ? fieldName : column
                                .name();
                    }
                }
            }

            clazz = clazz.getSuperclass();
        }

        this.columnNameMap = columnNameMap;

        /* idColumnName */

        if (idColumnName == null || idColumnName.length() == 0) {
            idColumnName = "id";
        }

        this.idColumnName = idColumnName;

        /* propertyNames */

        propertyNames = columnNameMap.keySet().toArray(
                new String[columnNameMap.size()]);
        Arrays.sort(propertyNames);
    }

    public boolean hasColumnName(String propertyName) {
        return columnNameMap.containsKey(propertyName);
    }

    public String getColumnName(String propertyName) {
        return columnNameMap.get(propertyName);
    }

    public Class<?> getEntityClass() {
        return entityClass;
    }

    public String getTableName() {
        return tableName;
    }

    public String getIdColumnName() {
        return idColumnName;
    }

    public String[] getPropertyNames() {
        return propertyNames;
    }
}
