package com.temenos.interaction.example.note;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Query;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;

import org.odata4j.core.OFunctionParameter;
import org.odata4j.core.OProperties;
import org.odata4j.edm.EdmDataServices;
import org.odata4j.edm.EdmEntityContainer;
import org.odata4j.edm.EdmFunctionImport;
import org.odata4j.edm.EdmFunctionParameter;
import org.odata4j.edm.EdmSchema;
import org.odata4j.edm.EdmSimpleType;
import org.odata4j.producer.BaseResponse;
import org.odata4j.producer.ODataProducer;
import org.odata4j.producer.ODataProducerDelegate;
import org.odata4j.producer.QueryInfo;
import org.odata4j.producer.Responses;
import org.odata4j.producer.jpa.JPAProducer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.temenos.interaction.core.command.NotSupportedCommand;

/**
 * A producer delegate that implements a simple new functions for testing.
 */
public class NewFunctionProducer extends ODataProducerDelegate {
	private final Logger logger = LoggerFactory.getLogger(NewFunctionProducer.class);

    private final EntityManagerFactory emf;
    private final String odataNamespace;
	private final JPAProducer producer;

    public NewFunctionProducer(EntityManagerFactory emf, String odataNamespace, JPAProducer jpaProducer) {
    	this.emf = emf;
    	this.odataNamespace = odataNamespace;
        producer = jpaProducer;
        extendModel();
    }
    
    // implement Delegate<ODataProducer>
    public ODataProducer getDelegate() {
        return producer;
    }
    
    @Override
    public BaseResponse callFunction(EdmFunctionImport function, java.util.Map<String, OFunctionParameter> params, QueryInfo queryInfo) {
        if (function.getName().equals("NEW")) {
          return createNewDomainObjectID(function, params, queryInfo);
        } else {
        	logger.error("Unknown function");
    	    throw new WebApplicationException(Response.status(NotSupportedCommand.HTTP_STATUS_NOT_IMPLEMENTED).entity(NotSupportedCommand.HTTP_STATUS_NOT_IMPLEMENTED_MSG).build());
        }

    }
    
    private BaseResponse createNewDomainObjectID(EdmFunctionImport function, java.util.Map<String, OFunctionParameter> params, QueryInfo queryInfo) {
    	// perform update to database ID table
    	EntityManager em = emf.createEntityManager();
    	em.getTransaction().begin();
    	Query update = em.createQuery("UPDATE ID x SET x.LastId=x.LastId+1 WHERE DomainObjectName = 'NOTE'");
    	update.executeUpdate();
    	Query query = em.createQuery("SELECT x.LastId FROM ID x WHERE DomainObjectName = 'NOTE'");
    	Long value = (Long) query.getSingleResult();
    	em.getTransaction().commit();

        return Responses.property(OProperties.int64("LastId", value));
    }
    
    private void extendModel() {
        // add some functions to the edm
        EdmDataServices ds = this.getMetadata();
        
        // Add functions to our own namespace
        EdmSchema schema = ds.findSchema(odataNamespace + "Container");
        EdmEntityContainer container = schema.findEntityContainer(odataNamespace + "Entities");
        
        /*
         * Add 'createNewDomainObjectID' function
         */
        List<EdmFunctionParameter.Builder> params = new ArrayList<EdmFunctionParameter.Builder>(1);
        EdmFunctionParameter.Builder efp = EdmFunctionParameter.newBuilder().setName("DOMAIN_OBJECT_NAME").setType(EdmSimpleType.STRING).setMode(EdmFunctionParameter.Mode.In);
        params.add(efp);
        
        EdmFunctionImport.Builder f = EdmFunctionImport.newBuilder().setName("NEW").setReturnType(EdmSimpleType.INT64).setHttpMethod("POST").addParameters(params);
        container.getFunctionImports().add(f.build());
    }
}

@@ -450,24 +450,61 @@
 yContainer;%0A
+import org.odata4j.edm.EdmEntitySet;%0A
 import org.o
@@ -533,16 +533,16 @@
 Import;%0A
-
 import o
@@ -1386,16 +1386,51 @@
 roducer;
+%0A%09private EdmDataServices metadata;
 %0A%0A    pu
@@ -1622,24 +1622,72 @@
 paProducer;%0A
+        metadata = getDelegate().getMetadata();%0A
         exte
@@ -3282,24 +3282,26 @@
 ontainer%22);%0A
+//
         EdmE
@@ -3380,24 +3380,24 @@
 Entities%22);%0A
-
         %0A   
@@ -3952,53 +3952,438 @@
     
-container.getFunctionImports().add(f.build())
+%0A        // replace metadata service?%0A        EdmEntityContainer.Builder newContainer = EdmEntityContainer.newBuilder()%0A        %09%09.addFunctionImports(f);%0A        EdmSchema.Builder newSchema = EdmSchema.newBuilder()%0A        %09%09.addEntityContainers(newContainer);%0A        metadata = EdmDataServices.newBuilder(ds).addSchemas(newSchema).build();%0A    %7D%0A    %0A    @Override%0A    public EdmDataServices getMetadata() %7B%0A    %09return metadata
 ;%0A  

Fix a minor issue with NewFunctionProducer. Prior to this change the list of immutable function imports was being modified, causing an error when starting notes example.