
package oracle.fusion.pts.restService;


import com.oracle.xmlns.apps.sales.opptymgmt.opportunities.opportunityservice.ObjectFactory;
import com.oracle.xmlns.apps.sales.opptymgmt.opportunities.opportunityservice.Opportunity;

import com.oracle.xmlns.apps.sales.opptymgmt.revenues.revenueservice.Revenue;

import com.sun.xml.bind.v2.runtime.XMLSerializer;
import com.sun.xml.ws.developer.WSBindingProvider;

import oracle.fusion.pts.restService.types.RESTActivityList;

import java.io.File;
import java.io.IOException;

import java.io.InputStream;
import java.io.OutputStream;

import java.io.StringWriter;

import java.math.BigDecimal;

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

import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;

import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;

import javax.ws.rs.QueryParam;

import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;

import javax.xml.bind.JAXBException;


import oracle.demo.pts.fusionproxy.opportunities.ServiceException;
import oracle.demo.pts.fusionservices.FusionOpportunityService;

import oracle.fusion.pts.restService.exceptions.FusionGenericException;
import oracle.fusion.pts.restService.types.DMLOperation;

import oracle.fusion.pts.restService.types.RESTOpportunityList;


import oracle.fusion.pts.restService.utils.RESTfulFusionService;


@Path("/opportunity")

public class RESTfulOpportunityService extends RESTfulFusionService {
    FusionOpportunityService objectService = new FusionOpportunityService();
    String fusionEndpointName = "fusionCRMOpportunityEndpoint";
    ObjectFactory oppObjFactory = new ObjectFactory();


    /**
     * @param pHttpHeaders
     * @param pInputStream
     * @return
     * @throws JAXBException
     */
    @POST
    @Path("/xmlquery")
    @Produces( { "application/xml", "application/json" })
    public RESTOpportunityList findXMLQuery(@Context
        HttpHeaders pHttpHeaders,
        InputStream pInputStream) throws JAXBException {
        return (find(pHttpHeaders, "", "", "", pInputStream));
    }

    // FIND Methods

    /**
     * @param pHttpHeaders
     * @param pAttributes
     * @param pQuery
     * @param pInputStream
     * @return
     * @throws JAXBException
     */
    @GET
    @Produces( { "application/xml", "application/json" })
    public RESTOpportunityList find(@Context
        HttpHeaders pHttpHeaders, @QueryParam("attributes")
        String pAttributes, @QueryParam("query")
        String pQuery, @QueryParam("conjunction")
        String pConjunction, InputStream pInputStream) throws JAXBException {
        String xmlQuery = convertStreamToString(pInputStream);
        // Initialise the connections
        processRESTServiceHeaders(pHttpHeaders);
        this.logMessage("findOpportunities called attributes[" + pAttributes +
                        "] query=[" + pQuery + "]");
        objectService.initialiseConnection(this.getFusionJWTToken(),
                                           getFusionUsername(),
                                           getFusionPassword(),
                                           getFusionEndpointURL(fusionEndpointName),
                                           this.getFetchSize(),
                                           this.getFetchStart());

        List<Opportunity> ops = null;
        try {
            ops =
objectService.find(xmlQuery, pAttributes, pQuery, pConjunction);
        } catch (com.sun.xml.ws.client.ClientTransportAccessException ctae) {
            throw new WebApplicationException(Response.Status.UNAUTHORIZED);
        } catch (Exception e) {
            logMessage("exception @ findOpportunity");
            e.printStackTrace();
            throw new FusionGenericException(e.getLocalizedMessage());
        }
        logMessage("Number of Opportunities found " + ops.size());
        // Add the resulting List of opportunities to the RESTOpportunityList object
        // this will ensure the JAX-WS JAXB parser will produce a nice list
        RESTOpportunityList ro2 = new RESTOpportunityList();
        ro2.setOpportunityList(ops);
        return ro2;
    }

    // Get Methods

    /**
     * @param pHttpHeaders
     * @param pId
     * @return
     * @throws JAXBException
     */
    @GET
    @Path("{id}")
    @Produces( { "application/xml", "application/json" })
    public RESTOpportunityList get(@Context
        HttpHeaders pHttpHeaders, @PathParam("id")
        Long pId, @QueryParam("attributes")
        String pAttributes) throws JAXBException {
        this.logMessage("getOpportunity called id[" + pId + "]");
        // Initialise the connections
        processRESTServiceHeaders(pHttpHeaders);

        objectService.initialiseConnection(this.getFusionJWTToken(),
                                           this.getFusionUsername(),
                                           this.getFusionPassword(),
                                           this.getFusionEndpointURL(fusionEndpointName),
                                           this.getFetchSize(),
                                           this.getFetchStart());
        // Find specific opportunity

        List<Opportunity> ops = null;
        try {
            String seperator = objectService.getDefaultMinorQuerySeperator();
            ops =
objectService.find("", pAttributes, "OptyId" + seperator + "=" + seperator +
                   +pId, "");

        } catch (NumberFormatException e) {
            // Error in opportunityid?
            throw new FusionGenericException("NumberFormatException, received " +
                                             pId + " for OptyId");
        } catch (com.sun.xml.ws.client.ClientTransportAccessException ctae) {
            throw new WebApplicationException(Response.Status.UNAUTHORIZED);
        } catch (Exception e) {
            logMessage("exception @ getOpportunity");
            e.printStackTrace();
            throw new FusionGenericException(e.getLocalizedMessage());

        }
        if (ops.size() < 1) {
            // No opportunity found
            throw new WebApplicationException(Response.Status.NOT_FOUND);
        }
        logMessage("Result of getOpportunity " + ops.get(0).getName());
        // Wrap it up so JAX-RS is happy
        // ArrayList<Opportunity> aoo = new ArrayList<Opportunity>();

        RESTOpportunityList rol2 = new RESTOpportunityList();
        rol2.setOpportunityList(ops);
        return rol2;
    }


    // Find Opp Interaactions

    /**
     * @param pHttpHeaders
     * @param pOptyId
     * @param pAttributes
     * @return
     * @throws JAXBException
     */
    @GET
    @Path("{optyid}/activity")
    @Produces( { "application/xml", "application/json" })
    public RESTActivityList findOppActivity(@Context
        HttpHeaders pHttpHeaders, @PathParam("optyid")
        Long pOptyId, @QueryParam("attributes")
        String pAttributes) throws JAXBException {
        // Find Specific Opportunity Interactions
        this.logMessage("findOppActivity [" + pOptyId + "]");
        RESTfulActivityService r = new RESTfulActivityService();
        return r.getActivity4Opportunity(pHttpHeaders, pOptyId, pAttributes);
    }


    // DML Methods

    /**
     * createSimpleOpportunity
     *
     * @param pHttpHeaders
     * @param simpleOpportunity
     * @return
     *
     * TODO : Needs to be expanded to include real life usecases of creating opportunity
     */
    @POST
    @Path("/simplecreate")
    @Produces( { "application/xml", "application/json" })
    public RESTOpportunityList createSimple(@Context
        HttpHeaders pHttpHeaders, @QueryParam("name")
        String pName, @QueryParam("salesaccountid")
        Long pSalesAccountPartyId, @QueryParam("keycontactid")
        Long pKeyContactPartyId, @QueryParam("winprob")
        BigDecimal winProb, @QueryParam("currencycode")
        String pCurrencyCode) {

        // Check all mandatory parameters are present
        if (pName == null || pKeyContactPartyId == null ||
            pSalesAccountPartyId == null) {
            throw new FusionGenericException("createOpportunity : Name,PrimaryContact, SalesAccountPartyId are mandatory");
        }


        Opportunity newOpportunity = oppObjFactory.createOpportunity();
        newOpportunity.setName(pName);
        newOpportunity.setTargetPartyId(oppObjFactory.createOpportunityTargetPartyId(pSalesAccountPartyId));
        newOpportunity.setKeyContactId(oppObjFactory.createOpportunityKeyContactId(pKeyContactPartyId));
        newOpportunity.setWinProb(oppObjFactory.createOpportunityWinProb(winProb));
        newOpportunity.setCurrencyCode(pCurrencyCode);
        // Wrap it up
        ArrayList<Opportunity> aoo = new ArrayList<Opportunity>();
        aoo.add((Opportunity)newOpportunity);
        RESTOpportunityList rol2 = new RESTOpportunityList();
        rol2.setOpportunityList(aoo);
        RESTOpportunityList result;
        result = this.doDMLXML(pHttpHeaders, rol2, DMLOperation.CREATE);

        return result;

    }


    /**
     * createXML
     * @param pHttpHeaders
     * @param p_newOpp
     * @param operation
     * @return
     */
    @POST
    @Produces( { "application/xml", "application/json" })
    @Consumes( { "application/xml" })
    public RESTOpportunityList createXML(@Context
        HttpHeaders pHttpHeaders, RESTOpportunityList p_newOpp) {
        return (this.doDMLXML(pHttpHeaders, p_newOpp, DMLOperation.CREATE));
    }


    /**
     * mergeXML
     *
     * @param pHttpHeaders
     * @param p_opportunity
     * @param operation
     * @return
     */
    @PUT
    @Produces( { "application/xml", "application/json" })
    @Consumes( { "application/xml" })
    public RESTOpportunityList mergeXML(@Context
        HttpHeaders pHttpHeaders, RESTOpportunityList p_opportunity) {
        return (this.doDMLXML(pHttpHeaders, p_opportunity,
                              DMLOperation.MERGE));
    }


    /**
     * deleteXML
     *
     * @param pHttpHeaders
     * @param pOptyId
     */
    @Path("{optyid}")
    @DELETE
    @Produces( { "application/xml", "application/json" })
    public void deleteXML(@Context
        HttpHeaders pHttpHeaders, @PathParam("optyid")
        Long pOptyId) {
        if (pOptyId == null || pOptyId < 1)
            throw new FusionGenericException("OptyId not set");


        Opportunity deleteOpp = this.oppObjFactory.createOpportunity();
        deleteOpp.setOptyId(pOptyId);
        // Wrap it up
        ArrayList<Opportunity> aoo = new ArrayList<Opportunity>();
        aoo.add((Opportunity)deleteOpp);
        RESTOpportunityList rol2 = new RESTOpportunityList();
        rol2.setOpportunityList(aoo);
        this.doDMLXML(pHttpHeaders, rol2, DMLOperation.DELETE);
    }


    /**
     * doDMLXML
     *
     * Main Guts for Create/Merge Opportunity
     *
     * @param pHttpHeaders
     * @param pOptyId
     */
    private RESTOpportunityList doDMLXML(HttpHeaders pHttpHeaders,
                                         RESTOpportunityList p_opportunity,
                                         DMLOperation operation) {
        // Initialise Proxy endpoint
        processRESTServiceHeaders(pHttpHeaders);
        objectService.initialiseConnection(this.getFusionJWTToken(),
                                           getFusionUsername(),
                                           getFusionPassword(),
                                           getFusionEndpointURL(fusionEndpointName),
                                           this.getFetchSize(),
                                           this.getFetchStart());

        Opportunity opportunity;
        if (p_opportunity.getOpportunityList() == null) {
            throw new WebApplicationException(Response.Status.BAD_REQUEST);
        }
        // Extract out the opportunity, assume its the first one
        opportunity = p_opportunity.getOpportunityList().iterator().next();
        Opportunity result = null;

        try {
            if (operation == DMLOperation.CREATE)
                result =
                        objectService.getService().createOpportunity(opportunity);
            else if (operation == DMLOperation.MERGE)
                // must be UPDATE
                result =
                        objectService.getService().mergeOpportunity(opportunity);
            else if (operation == DMLOperation.DELETE) {
                objectService.getService().deleteOpportunity(opportunity);
            } else
                throw new WebApplicationException(Response.Status.BAD_REQUEST);

        } catch (ServiceException e) {
            throw new FusionGenericException(e.getLocalizedMessage());

        }
        // Wrap it up so JAX-RS is happy
        ArrayList<Opportunity> aoo = new ArrayList<Opportunity>();
        aoo.add((Opportunity)result);
        RESTOpportunityList rol2 = new RESTOpportunityList();
        rol2.setOpportunityList(aoo);

        return rol2;
    }
}
