package gov.wisconsin.wijis.services.warrant;

import gov.wisconsin.wijis.schemas.wijisservice.WijisErrorSeverityType;
import gov.wisconsin.wijis.schemas.wijisservice.WijisServiceResponseErrorItemType;
import gov.wisconsin.wijis.schemas.wijisservice.WijisServiceResponseErrorItemsType;
import gov.wisconsin.wijis.services.warrant.NotificationResponseType;
import gov.wisconsin.wijis.services.warrant.SubmitFaultMessage;
import gov.wisconsin.wijis.services.warrant.Warrant;

import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Unmarshaller;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;

import org.w3c.dom.Document;

import warrant.issue.gov.ojp.it.jxdm._3_0_3.AddressType;
import warrant.issue.gov.ojp.it.jxdm._3_0_3.ChargeType;
import warrant.issue.gov.ojp.it.jxdm._3_0_3.TextType;
import warrant.issue.gov.wisconsin.wijis.specs.schemas.court_docs.warrant.v1_1._2007_09_10.codes.WarrantCodeType;
import warrant.issue.gov.wisconsin.wijis.specs.schemas.court_docs.warrant.v1_1._2007_09_10.document.WarrantDocumentType;
import warrant.issue.gov.wisconsin.wijis.specs.schemas.court_docs.warrant.v1_1._2007_09_10.document.WarrantSubjectType;
import warrant.issue.gov.wisconsin.wijis.specs.schemas.court_docs.warrant.v1_1._2007_09_10.document.WarrantType;

import com.sun.org.apache.xerces.internal.dom.ElementNSImpl;

/**
 * This class is the implementation of the Warrant Interface.  It contains to
 * Web Service methods: submit and notify.  These services work together as a pair.
 * The local agency provides the submit method as a service and is a client to the
 * notify method.  In this example implementation, the notify method will throw a Soap fault
 * since the agency will not provide this service
 * 
 * The WIJIS Worflow Engine will recieve a warrant from CCAP and will submit it to the
 * local agency.  The agency will then parse the warrant sent by CCAP and send a response message
 * back to the Workflow Engine indicating that they have successfully received and processed
 * the incoming warrant.
 * 
 * The WSDL provides an xs:any interface.  That means the incoming and response message can both
 * be any valid XML.  The incoming message is received by the submit method as an object and then
 * unmarshalled using JaxB.  Once validated, the submit method will provide an example of how to 
 * access all elements and attributes in the message.  It will then create a schema valid response
 * message that will be sent back to the workflow engine.
 * 
 * Due to the nature of GJXDM, the issue, response and service message all have their own extension
 * schemas.  When the JaxB objects are auto-generated, there are package name collisions because many elements
 * in the extension schema have the same namespace and name.  WIJIS has seperated all of these auto-generated
 * objects into their own packages to avoid these collisions.  This means that when accessing objects
 * in the extension schema you have to explicitly referece what package they are from.  For example if you
 * want to access the AddressType of the issue and response message in the same class, one of these objects
 * will need the package name explicitly defined.  To make it easier, we have seperated the utility methods
 * for issue and repsonse messages into seperate classes to avoid confusion in the code.  This paragraph will
 * be repeated in the Javadocs for the issue and response helper methods. 
 * 
 * This example has been validated against a handful of incoming messages.  It is likely that a Warrant message
 * from CCAP will cause an exception and the developer will have to modify the code to add additional null and
 * safety checks. 
 * 
 * This class does not handle any X509 certificate validation or security.  That is handled separately
 * by an input interceptor.  WIJIS is available to assist you with this implementation and to do a code walk
 * through so you can familiarize yourself with this code example.
 * 
 * This example implementation was done using Apache CXF and JaxB. 
 * @author Yogesh Chawla ()
 */
public class WarrantServiceImpl implements Warrant
{
    public WarrantServiceImpl()
    {
    }

	/**
	 * {@inheritDoc}
	 */
	public NotificationResponseType notify(Object notifyParameters) {
		throw new UnsupportedOperationException("This service is not implemented in this distribution");
	}

	/**
	 * {@inheritDoc}
	 */
	public Object submit(Object submitParameters) throws SubmitFaultMessage
	{
	    JAXBElement<WarrantDocumentType> warrantInputDocument = null;
	    
		try
		{
		    //Create a new JaxB instance and set up an unmarshaller
		    JAXBContext jc = JAXBContext.newInstance("warrant.issue.gov.wisconsin.wijis.specs.schemas.court_docs.warrant.v1_1._2007_09_10.document");
			Unmarshaller unmarshaller = jc.createUnmarshaller() ;

			//Unmarshall the input paramater into a WarrantInputDocument
			warrantInputDocument = unmarshaller.unmarshal(((ElementNSImpl) submitParameters).getFirstChild(), 
	                WarrantDocumentType.class);

	        //Get the warrant out of the warrant input document
			WarrantType warrantInput = new WarrantType();
	        warrantInput = warrantInputDocument.getValue().getWarrant();

	        //Get the Warrant ID attribute
	        System.out.println("Warrant ID: " + warrantInput.getId());
	        
	        //START Warrant CourtOrderDesignatedLocation Processing
	        //Since this XML element allows for max occurrences greater than 1, JaxB maps it to a list
	        //The list is iterated in a for loop and all the elements are printed out.  This patters in repeated
	        //for other unbounded XML elements.
	        List<AddressType> addressTypeList = warrantInput.getCourtOrderDesignatedLocation().getLocationAddress();
	        System.out.println("Court Order Designated Location:");
	        
	        for (AddressType addressType : addressTypeList) {
	        	System.out.println("County Name: " + addressType.getLocationCountyName().getValue());
	        	System.out.println("Location County Code: " + addressType.getLocationCountyCode().getValue());
	        }
	        //END Warrant CourtOrderDesignatedLocation
	        
	        //START Warrant CourtOrderIssuingJudicialOfficial Processing
	        System.out.println("Judicial Official Name:");
	        //Multiple person names are processed throughout the code so a helper method processes the name
	        WarrantServiceHelperMethodsIssue.processPersonName(warrantInput.getCourtOrderIssuingJudicialOfficial().getPersonName());
	        //END Warrant CourtOrderIssuingJudicialOfficial
	        
	        //START Warrant CourtOrderIssuingDate Processing
	        XMLGregorianCalendar issuingDate = warrantInput.getCourtOrderIssuingDate().getValue();
	        System.out.println("Issuing Date:");
	        //Multiple dates are processed throughout the code a helper method processes the date 
	        WarrantServiceHelperMethodsIssue.processDate(issuingDate);
	        //END Warrant CourtOrderIssuingDate
	        
	        //START Warrant WarrantExtraditionLimitationText Processing
	        System.out.println("Bail Amount: " + warrantInput.getWarrantAppearanceBail().getBailSetAmount().getValue().intValue());
	        //END Warrant WarrantExtraditionLimitationText
	        
	        //START WarrantExtraditionLimitationText Processing
	        for (TextType text : warrantInput.getWarrantExtraditionLimitationText()) {
	        	System.out.println("Bail Amount: " + text.getValue());
	        }
	        //END WarrantExtraditionLimitationText
	        
	        //START CASE CaseDocketID Processing
	        System.out.println("Case Docket ID: " + warrantInput.getCase().getCaseDocketID().getID());
	        //END CaseDocketID
	        
	        //START WarrantActionStatus Processing
	        //The field below is an enumeration with values defined in the schema
	        System.out.println("Warrant Action: " + warrantInput.getWarrantActionStatus().getWarrantAction().toString());
	        System.out.println("Warrant Action Description: " + warrantInput.getWarrantActionStatus().getWarrantActionDescription().getValue());
	        
	        XMLGregorianCalendar warrantActionDate = warrantInput.getWarrantActionStatus().getWarrantActionDate();
	        System.out.println("Warrant Action Date:");
	        WarrantServiceHelperMethodsIssue.processDate(warrantActionDate);
	        //END WarrantActionStatus
	        
	        //START WarrantCode Processing
	        //The field below is an enumeration with values defined in the schema
	        System.out.println("Warrant Code: " + warrantInput.getWarrantCode().value());
	        //This is an example of how to create a local instance of the WarrantCodeType enumeration
	        WarrantCodeType warrantCodeType = WarrantCodeType.valueOf(warrantInput.getWarrantCode().value());
	        //END WarrantCode
	        
	        //START WarrantCodeDescription
	        System.out.println("Warrant Code Description: " + warrantInput.getWarrantCodeDescription().getValue());
	        //END WarrantCodeDescription
	        
	        //START WarrantSubject
	        WarrantSubjectType warrantSubject = warrantInput.getWarrantSubject();
	        WarrantServiceHelperMethodsIssue.processWarrantSubject(warrantSubject);
	        //END 	WarrantSubject
	        
	        //START Charge
	        List<ChargeType> charges = warrantInput.getCharge();
	        WarrantServiceHelperMethodsIssue.processCharges(charges);
	        //END 	Charge
	        
	        //START WarrantGeographicRestrictionCode 
	        //The field below is an enumeration with values defined in the schema
	        if (warrantInput.getWarrantGeographicRestrictionCode() != null)
	        {	
	        	System.out.println("Warrant Geographic Restriction Code: " + warrantInput.getWarrantGeographicRestrictionCode().toString());
	        }	
	        //END WarrantGeographicRestrictionCode
	        
	        //START WarrantGeographicRestrictionDescription
	        if (warrantInput.getWarrantGeographicRestrictionDescription() != null)
	        {	
	        	System.out.println("Warrant Geographic Restriction Description: " + warrantInput.getWarrantGeographicRestrictionDescription().getValue());
	        }	
	        //END WarrantGeographicRestrictionDescription
	        
	        //START WarrantDocument
	        WarrantServiceHelperMethodsIssue.processWarrantDocument(warrantInput.getWarrantDocument());
	        //END WarrantDocument
		} catch (Exception e) {
			//Any exceptions thrown will be caught and returned as soap faults
			e.printStackTrace();
			SubmitFaultMessage sfm = new SubmitFaultMessage("Message submission failed, please try again.",e);
		}
		
		//Call a helper method that helps creates the response document
		Document document = WarrantServiceHelperMethodsResponse.createResponseMessage(warrantInputDocument.getValue());
		
		return document.getDocumentElement();
	}
	

}
