package com.github.nrudenko.dora.compiler.model;

import com.github.nrudenko.dora.TextUtils;
import com.github.nrudenko.dora.annotation.DbSkipField;
import com.github.nrudenko.dora.annotation.Table;
import com.github.nrudenko.dora.commons.DbType;
import com.github.nrudenko.dora.commons.FieldType;
import com.github.nrudenko.dora.compiler.exception.AbsentConstructorException;
import com.github.nrudenko.dora.compiler.exception.UnknownFieldType;

import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.PackageElement;
import javax.lang.model.util.ElementFilter;
import java.lang.reflect.Modifier;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

public class TableModel {

    public final String modelName;
    public final String modelPackage;
    public final Set<TableColumn> columns = new LinkedHashSet<>();
    public final String tableName;

    public TableModel(Element classElement) throws AbsentConstructorException, UnknownFieldType {
        assertHasEmptyConstructor(classElement);

        PackageElement packageElement = (PackageElement) classElement.getEnclosingElement();
        this.modelPackage = packageElement.getQualifiedName().toString();

        this.tableName = getTableName(classElement);
        this.modelName = classElement.getSimpleName().toString();

        fillColumns(classElement);
    }

    private void fillColumns(Element classElement) throws UnknownFieldType {
        TableColumn _idColumn = new TableColumn(null, "int", "_id",
                tableName, DbType.INT,
                FieldType.INTEGER, "PRIMARY KEY AUTOINCREMENT", false, null);
        columns.add(_idColumn);

        List<? extends Element> classFields = classElement.getEnclosedElements();
        for (Element classField : classFields) {
            if (shouldSkipElement(classField)) continue;
            TableColumn tableColumn = new TableColumn(classField, tableName);
            if (!tableColumn.name.equals("_id")) {
                columns.add(tableColumn);
            }
        }
    }

    public String getTableName(Element typeElement) {
        Table table = typeElement.getAnnotation(Table.class);
        String tableName;
        if (table.name().trim().length() > 0) {
            tableName = table.name();
        } else {
            tableName = typeElement.getSimpleName().toString();
        }
        return TextUtils.toUnderscore(tableName).toLowerCase();
    }

    private void assertHasEmptyConstructor(Element classElement) throws AbsentConstructorException {
        for (ExecutableElement cons :
                ElementFilter.constructorsIn(classElement.getEnclosedElements())) {
            if (cons.getParameters().isEmpty()) {
                return;
            }
        }
        throw new AbsentConstructorException();
    }

    private boolean shouldSkipElement(Element schemaField) {
        return !(schemaField.getKind().isField() &&
                !schemaField.getModifiers().contains(Modifier.STATIC) &&
                schemaField.getAnnotation(DbSkipField.class) == null);
    }

}

@@ -1384,20 +1384,23 @@
         
-fill
+prepare
 Columns(
@@ -1442,12 +1442,15 @@
 oid 
-fill
+prepare
 Colu
@@ -2491,32 +2491,296 @@
 rCase();%0A    %7D%0A%0A
+    private boolean shouldSkipElement(Element schemaField) %7B%0A        return !(schemaField.getKind().isField() &&%0A                !schemaField.getModifiers().contains(Modifier.STATIC) &&%0A                schemaField.getAnnotation(DbSkipField.class) == null);%0A    %7D%0A%0A
     private void
@@ -3143,270 +3143,6 @@
  %7D%0A%0A
-    private boolean shouldSkipElement(Element schemaField) %7B%0A        return !(schemaField.getKind().isField() &&%0A                !schemaField.getModifiers().contains(Modifier.STATIC) &&%0A                schemaField.getAnnotation(DbSkipField.class) == null);%0A    %7D%0A%0A
 %7D%0A

Reorder methods in TableModel