package io.github.ibuildthecloud.dstack.core.dao.impl;

import io.github.ibuildthecloud.dstack.core.constants.CommonStatesConstants;
import io.github.ibuildthecloud.dstack.core.dao.GenericMapDao;
import io.github.ibuildthecloud.dstack.object.jooq.utils.JooqUtils;
import io.github.ibuildthecloud.dstack.object.meta.ObjectMetaDataManager;
import io.github.ibuildthecloud.dstack.object.meta.Relationship;
import io.github.ibuildthecloud.gdapi.factory.SchemaFactory;

import java.util.List;
import java.util.Map;

import javax.inject.Inject;

import org.jooq.Table;
import org.jooq.TableField;
import org.jooq.UpdatableRecord;

public class GenericMapDaoImpl extends AbstractCoreDao implements GenericMapDao {

    SchemaFactory schemaFactory;
    ObjectMetaDataManager metaDataManager;

    @Override
    public <T> List<? extends T> findNonRemoved(Class<T> mapType, Class<?> resourceType, long resourceId) {
        String type = schemaFactory.getSchemaName(mapType);

        @SuppressWarnings("unchecked")
        Table<? extends T> table = (Table<? extends T>)getTable(mapType);

        Relationship reference = getRelationship(mapType, resourceType);
        TableField<?, Object> removed = JooqUtils.getTableField(metaDataManager, type, ObjectMetaDataManager.REMOVED_FIELD);
        TableField<?, Object> referenceField = JooqUtils.getTableField(metaDataManager, type, reference.getPropertyName());

        if ( removed == null || referenceField == null ) {
            throw new IllegalArgumentException("Type [" + mapType + "] is missing required removed or reference column");
        }

        return create()
                .selectFrom(table)
                .where(
                        removed.isNull()
                        .and(referenceField.eq(resourceId)))
                .fetch();
    }


    @Override
    public <T> T findNonRemoved(Class<T> mapType, Class<?> leftResourceType, long leftResourceId,
            Class<?> rightResourceType, long rightResourceId) {
        String type = schemaFactory.getSchemaName(mapType);

        @SuppressWarnings("unchecked")
        Table<? extends T> table = (Table<? extends T>)getTable(mapType);

        Relationship leftReference = getRelationship(mapType, leftResourceType);
        Relationship rightReference = getRelationship(mapType, rightResourceType);
        TableField<?, Object> removed = JooqUtils.getTableField(metaDataManager, type, ObjectMetaDataManager.REMOVED_FIELD);
        TableField<?, Object> leftReferenceField = JooqUtils.getTableField(metaDataManager, type, leftReference.getPropertyName());
        TableField<?, Object> rightReferenceField = JooqUtils.getTableField(metaDataManager, type, rightReference.getPropertyName());

        if ( removed == null || leftReferenceField == null || rightReferenceField == null ) {
            throw new IllegalArgumentException("Type [" + mapType + "] is missing required removed or references column");
        }

        return create()
                .selectFrom(table)
                .where(
                        removed.isNull()
                        .and(leftReferenceField.eq(leftResourceId))
                        .and(rightReferenceField.eq(rightResourceId)))
                .fetchOne();
    }


    @Override
    public <T> List<? extends T> findToRemove(Class<T> mapType, Class<?> resourceType, long resourceId) {
        String type = schemaFactory.getSchemaName(mapType);

        @SuppressWarnings("unchecked")
        Table<? extends T> table = (Table<? extends T>)getTable(mapType);

        Relationship reference = getRelationship(mapType, resourceType);
        TableField<?, Object> removed = JooqUtils.getTableField(metaDataManager, type, ObjectMetaDataManager.REMOVED_FIELD);
        TableField<?, Object> referenceField = JooqUtils.getTableField(metaDataManager, type, reference.getPropertyName());
        TableField<?, Object> state = JooqUtils.getTableField(metaDataManager, type, ObjectMetaDataManager.STATE_FIELD);

        if ( removed == null || referenceField == null || state == null ) {
            throw new IllegalArgumentException("Type [" + mapType + "] is missing required removed, reference, or state column");
        }

        return create()
                .selectFrom(table)
                .where(
                        referenceField.eq(resourceId)
                        .and(
                                removed.isNull()
                                .or(state.eq(CommonStatesConstants.REMOVING))))
                .fetch();
    }


    protected <T> Table<? extends T> getTable(Class<?> mapType) {
        Class<UpdatableRecord<?>> record = JooqUtils.getRecordClass(schemaFactory, mapType);
        @SuppressWarnings("unchecked")
        Table<? extends T> table = (Table<? extends T>)JooqUtils.getTable(record);

        return table;
    }

    protected Relationship getRelationship(Class<?> mapType, Class<?> resourceType) {
        Map<String,Relationship> rels = metaDataManager.getLinkRelationships(schemaFactory, schemaFactory.getSchemaName(mapType));
        Relationship reference = null;
        for ( Map.Entry<String,Relationship> entry : rels.entrySet() ) {
            Relationship rel = entry.getValue();
            if ( rel.getRelationshipType() == Relationship.RelationshipType.REFERENCE && resourceType.isAssignableFrom(rel.getObjectType())) {
                reference = rel;
                break;
            }
        }

        if ( reference == null ) {
            throw new IllegalArgumentException("Failed to find reference relationship from [" + mapType + "] to [" + resourceType + "]");
        }

        return reference;
    }

    public SchemaFactory getSchemaFactory() {
        return schemaFactory;
    }

    @Inject
    public void setSchemaFactory(SchemaFactory schemaFactory) {
        this.schemaFactory = schemaFactory;
    }

    public ObjectMetaDataManager getMetaDataManager() {
        return metaDataManager;
    }

    @Inject
    public void setMetaDataManager(ObjectMetaDataManager metaDataManager) {
        this.metaDataManager = metaDataManager;
    }

}

@@ -778,16 +778,51 @@
 nager;%0A%0A
+    @SuppressWarnings(%22unchecked%22)%0A
     @Ove
@@ -819,32 +819,32 @@
 )%0A    @Override%0A
-
     public %3CT%3E L
@@ -1008,94 +1008,25 @@
     
-@SuppressWarnings(%22unchecked%22)%0A        Table%3C? extends T%3E table = (Table%3C? extends T%3E)
+Table%3C?%3E table = 
 getT
@@ -1563,32 +1563,51 @@
 %0A        return 
+(List%3C? extends T%3E)
 create()%0A       
@@ -1786,32 +1786,67 @@
 etch();%0A    %7D%0A%0A%0A
+    @SuppressWarnings(%22unchecked%22)%0A
     @Override%0A  
@@ -2078,94 +2078,25 @@
     
-@SuppressWarnings(%22unchecked%22)%0A        Table%3C? extends T%3E table = (Table%3C? extends T%3E)
+Table%3C?%3E table = 
 getT
@@ -2902,32 +2902,35 @@
 %0A        return 
+(T)
 create()%0A       
@@ -3194,24 +3194,59 @@
 ();%0A    %7D%0A%0A%0A
+    @SuppressWarnings(%22unchecked%22)%0A
     @Overrid
@@ -3426,94 +3426,25 @@
     
-@SuppressWarnings(%22unchecked%22)%0A        Table%3C? extends T%3E table = (Table%3C? extends T%3E)
+Table%3C?%3E table = 
 getT
@@ -4135,16 +4135,35 @@
  return 
+(List%3C? extends T%3E)
 create()
@@ -4494,26 +4494,16 @@
  Table%3C?
- extends T
 %3E getTab
@@ -4630,94 +4630,15 @@
     
-@SuppressWarnings(%22unchecked%22)%0A        Table%3C? extends T%3E table = (Table%3C? extends T%3E)
+return 
 Jooq
@@ -4664,31 +4664,8 @@
 rd);
-%0A%0A        return table;
 %0A   

Fix compilation error on openjdk6