package gov.grants.apply.applicant.v2;

import java.io.File;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.log4j.Logger;

import com.ximpleware.VTDNav;

import gov.grants.apply.services.applicantwebservices_v2.ApplicantWebServicesPortType;
import gov.grants.apply.services.applicantwebservices_v2.AuthenticateAORExpandedRequest;
import gov.grants.apply.services.applicantwebservices_v2.AuthenticateAORExpandedResponse;
import gov.grants.apply.services.applicantwebservices_v2.SubmitApplicationAsThirdPartyExpandedRequest;
import gov.grants.apply.services.applicantwebservices_v2.SubmitApplicationAsThirdPartyExpandedResponse;
import gov.grants.apply.support.bizobj.CommonConstants;
import gov.grants.apply.system.grantscommonelements_v1.Attachment;
import gov.grants.apply.system.grantscommonelements_v1.Token;
import gov.grants.apply.system.grantscommonelements_v1.TokenInfo;
import gov.grants.apply.system.grantscommontypes_v1.AORStatusType;
import gov.grants.commons.CommonsGlobals;
import gov.grants.commons.util.FileUtil;

public class SubmitApplicationAsThirdPartyExpandedClient extends BaseApplicantClient {

	private static final String CLASSNAME = SubmitApplicationAsThirdPartyExpandedClient.class.getSimpleName();
	private static final Logger log = Logger.getLogger( CLASSNAME );
	
	
	/**
	 * @param args
	 */
	public static void main( String[] args ) {
		log.debug( "Begin " + CLASSNAME );
		
		try {
			SubmitApplicationAsThirdPartyExpandedClient client = new SubmitApplicationAsThirdPartyExpandedClient();
			
			log.debug( "args length: " + args.length );
			client.init( args );
			
			client.makeServiceCall();
			log.debug( "\n\nSUCCESS: " + CLASSNAME + " successfully completed" );

		} catch ( Exception e ) {
			log.error( "\n\nException: " + e.getMessage() );
		}// try-catch
		
	}// main
	
	
	public void makeServiceCall() throws Exception {
		try {
			
			SubmitApplicationAsThirdPartyExpandedRequest request = new SubmitApplicationAsThirdPartyExpandedRequest();
			
			String aorUserId = null;
			String aorPassword = null;
			String aorDuns = null;
			String aorUei = null;
			
			
			// Get the ApplicantPort (MTOM Enabled).
			ApplicantWebServicesPortType port = super.getApplicantPort();
			
			String configXml = getArgMap().get( Globals.CONFIG_XML_CMD_LINE_KEY );
			loadConfigXmlDoc( configXml );
			configVN.toElement( VTDNav.FIRST_CHILD, CLASSNAME );// navigate to client element
			
			log.debug( "prepare authenticateAORExpanded service call" );
			
			
			if ( configVN.toElement( VTDNav.FIRST_CHILD, Globals.AOR_USER_ID_ELEMENT_NAME )) {
				aorUserId = configVN.toNormalizedString2( configVN.getText() );
				log.debug( "AOR user ID: " + aorUserId );
				configVN.toElement( VTDNav.PARENT );
			}
			
			if ( configVN.toElement( VTDNav.FIRST_CHILD, Globals.AOR_PASSWORD_ELEMENT_NAME )) {
				aorPassword = configVN.toNormalizedString2( configVN.getText() );
				log.debug( "AOR password: " + aorPassword );
				configVN.toElement( VTDNav.PARENT );
			}
			
			if( configVN.toElement( VTDNav.FIRST_CHILD, Globals.AOR_DUNS_ELEMENT_NAME )) {
				aorDuns = configVN.toNormalizedString( configVN.getText() );
				log.debug( "aorDuns: " + aorDuns );
				configVN.toElement( VTDNav.PARENT );
			} else {
				log.debug( "Optional AOR DUNS is not specified!");
			}
			
			if( configVN.toElement( VTDNav.FIRST_CHILD, Globals.AOR_UEI_ELEMENT_NAME )) {
				aorUei = configVN.toNormalizedString( configVN.getText() );
				log.debug( "aorUei: " + aorUei );
				configVN.toElement( VTDNav.PARENT );
			} else {
				log.debug( "Optional AOR UEI is not specified!");
			}
			
			//R16.3 Changes: Added the optional previous Grants.Gov Tracking number to the Request.
			if( configVN.toElement( VTDNav.FIRST_CHILD, Globals.PREV_GG_TRACKING_NUM)) {
				String prevGGTrackingNum = configVN.toNormalizedString( configVN.getText() );
				log.debug( "previous Grants.Gov Tracking Number: " + prevGGTrackingNum );
				request.setGrantsGovTrackingNumber(prevGGTrackingNum);
				configVN.toElement( VTDNav.PARENT );
			} else {
				log.debug( "Optional previous Grants.Gov Tracking Number was not provided on configuration!");
			}
			
			configVN.toElement( VTDNav.FIRST_CHILD, Globals.SUBMISSION_DIR_ELEMENT_NAME );
			String submissionDir = configVN.toNormalizedString2( configVN.getText() );
			log.debug( "submission dir: " + submissionDir );
			configVN.toElement( VTDNav.PARENT );

			configVN.toElement( VTDNav.FIRST_CHILD, Globals.SUBMISSION_XML_ELEMENT_NAME );
			String xmlFileName = configVN.toNormalizedString2( configVN.getText() );
			log.debug( "xmlFileName: " + xmlFileName );
			
			
			if ( StringUtils.isBlank( submissionDir ) || StringUtils.isBlank( xmlFileName ) ) {
				String s = "submission-dir and submission-xml elements in the config xml cannot be blank";
				log.error( s );
				throw new Exception( s );
			}// if
			
			log.debug( "make AuthenticateAOR service call" );
			TokenInfo tokenInfo  = authenticateAORExpanded( port, aorUserId, aorPassword, aorDuns, aorUei);
			
			log.debug( "prepare to submitApplicationAsThirdPartyExpanded service call" );
			request.setTokenInfo( tokenInfo);
			
			byte[] fileBytes = null;
			String fileName = null;
			String cid = null;
			String contentType = null;
			log.debug( "load attachment(s)" );
			File att = null;
			
			while ( configVN.toElement( VTDNav.NS, Globals.ATTACHMENT_ELEMENT_NAME ) ) {
				
				configVN.toElement( VTDNav.FIRST_CHILD, Globals.FILE_NAME_ELEMENT_NAME );
				fileName = configVN.toNormalizedString2( configVN.getText() );
				log.debug( "attachment file name: " + fileName );
				//log.debug( configVN.toNormalizedString( configVN.getCurrentIndex() ) + ": " + fileName );
				
				
				att = new File( submissionDir + fileName );
				log.debug( "try to load: " + att.getCanonicalPath() );
				if ( !att.exists() ) {
					log.warn( "File does not exist: " + att.getCanonicalPath() );
					att = new File( fileName );
					log.debug( "try to load: " + att.getCanonicalPath() );
					if ( !att.exists() ) {
						log.error( "File does not exist: " + att.getCanonicalPath() );
						throw new Exception( "File does not exist: " + att.getCanonicalPath() );
					}// if
				}// if

				contentType = new javax.activation.MimetypesFileTypeMap().getContentType( att );
				log.debug( "content type: " + contentType );
				
				configVN.toElement( VTDNav.PARENT );
				configVN.toElement( VTDNav.FIRST_CHILD, Globals.CID_ELEMENT_NAME );
				cid = configVN.toRawString( configVN.getText() );
				log.debug( "cid: " + cid );
				//log.debug( configVN.toNormalizedString2( configVN.getCurrentIndex() ) + ": " + cid );

				// Create Attachment Object for each Large File.
				Attachment attachment = new Attachment();
				// Create Data Handler for each file.
				attachment.setFileDataHandler(new DataHandler(new FileDataSource(submissionDir+fileName)));
				// Assign the CID
				attachment.setFileContentId(cid);
				// Add the Attachment to the List of Attachments to be streamed.
				request.getAttachment().add( attachment);
				configVN.toElement( VTDNav.PARENT );
				
			}// while
						
			// Load the GrantsApplication XML (The usual way no streaming).
			log.debug( "load submission xml" );
			fileBytes = FileUtil.readFile( submissionDir + xmlFileName );
			log.debug( "xml bytes: " + fileBytes.length );
			log.debug( "xml size: " + new String( fileBytes ).length() );
			request.setApplicationXML( new String( fileBytes,CommonsGlobals.PREFERRED_ENCODING ) );
			SubmitApplicationAsThirdPartyExpandedResponse response = port.submitApplicationAsThirdPartyExpanded( request );
			String ggTrackingNum = response.getGrantsGovTrackingNumber();
			String receivedDateTime = formatDate( response.getReceivedDateTime().toGregorianCalendar().getTime(), yyyyMMddHHmmss );
			StringBuilder sb = new StringBuilder();
			sb.append( "\n\nGG Tracking Number: " ).append( ggTrackingNum );
			sb.append( "\nReceived Date/Time: " ).append( receivedDateTime );
			sb.append( "\n\n" );
			log.debug( sb );
			
		} catch ( Exception e ) {
			log.error( "Exception: " + e.getMessage() );
			e.printStackTrace();
			throw e;
		}// try-catch
		
	}// makeServiceCall
	
	
	private TokenInfo authenticateAORExpanded( 
			ApplicantWebServicesPortType port, 
			String aorUserId, 
			String aorPassword,
			String aorDuns,
			String aorUei) 
	throws Exception {
		
		TokenInfo tokenInfo = null;
		try {
			
			AuthenticateAORExpandedRequest request = new AuthenticateAORExpandedRequest();
			request.setAORUserID( aorUserId );
			request.setAORPassword( aorPassword );
			request.setDUNS( aorDuns);
			request.setUEI( aorUei);
			
			AuthenticateAORExpandedResponse response = port.authenticateAORExpanded( request );
			if (  response.getAORStatus() == AORStatusType.UNAUTHORIZED) {
				String s = "### aorUserId [" + aorUserId + "] is " +  AORStatusType.UNAUTHORIZED.toString();
				log.error( s );
				throw new Exception( s );
			} else {
				tokenInfo = response.getTokenInfo();
			}
		} catch ( Exception e ) {
			String s = "Exception caught authenticating AOR Expanded [" + aorUserId + "]: " + e.getMessage();
			log.error( s );
			throw new Exception( s );
		}// try-catch

		log.debug( "returning Token Info: " + ToStringBuilder.reflectionToString( tokenInfo ) );
		return tokenInfo;
		
	}// authenticateAOR
	

}

