/////////////////////////////////////////////////////////////////////////
//
// © University of Southampton IT Innovation Centre, 2004
//
// Copyright in this library belongs to the IT Innovation Centre of
// 2 Venture Road, Chilworth Science Park, Southampton, SO16 7NP, UK.
//
// This software may not be used, sold, licensed, transferred, copied
// or reproduced in whole or in part in any manner or form or in or
// on any media by any person other than in accordance with the terms
// of the Licence Agreement supplied with the software, or otherwise
// without the prior written consent of the copyright owners.
//
// This software is distributed WITHOUT ANY WARRANTY, without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE, except where stated in the Licence Agreement supplied with
// the software.
//
//      Created by:             Darren Marvin
//      Created date:           2003/09/16
//      Created for project:    GEMSS
//
/////////////////////////////////////////////////////////////////////////
//
//      Dependencies: None
//
/////////////////////////////////////////////////////////////////////////
//
//      Last commit info:       $Author: $
//                              $Date: $
//                              $Revision: $
//
/////////////////////////////////////////////////////////////////////////

package uk.ac.soton.itinnovation.gemss.transportmessaging.servicedescription.interfacetypes;

import eu.gemss.components.transport.servicedescription.*;
import eu.gemss.components.transport.servicedescription.interfacetypes.*;
import java.io.*;
import java.util.logging.*;
import org.apache.axis.utils.*;
import org.w3c.dom.*;
import org.xml.sax.*;

/**
 * WSDL11InterfaceImp implements the WSDLInterface and WSDL11Interface interfaces and
 * thereby provides information about the WSDL interface for a WSDL service
 */
public class WSDL11InterfaceImp implements WSDL11Interface {

	public static final String THIS_URI = "#";
	private static Logger mLogger = Logger.getLogger("uk.ac.soton.itinnovation.gemss.transportmessaging.servicedescription.interfacetypes.WSDL11InterfaceImp");

	private static InterfaceTypeDescriptor mDescriptorForThis = null;

	private String mWSDLURI = null;
	private String mOperationName = null;
	private String mPortTypeName = null;
	private String mBindingName = null;
	private Document mWSDLDocument = null;


    /**
     * Constructor creates a WSDLInterface holder that will attempt to retrieve the WSDL document from
     * a remote location using the supplied URI.
     * @param wsdlURI location of WSDL document
     * @param operationName operation name for service required
     * @param portTypeName portType name for the service required
     * @param bindingName binding name for the binding required
     * @throws ServiceDescriptionException
     */
	public WSDL11InterfaceImp(String wsdlURI,String operationName, String portTypeName, String bindingName) throws ServiceDescriptionException {
		// check parameters
		if(wsdlURI==null || wsdlURI.equals("")) {
			mLogger.log(Level.SEVERE,"Supplied WSDL URI is invalid");
			throw new ServiceDescriptionException("Supplied WSDL URI is invalid");
		}
		if(operationName==null || operationName.equals("")) {
			mLogger.log(Level.SEVERE,"Supplied WSDL operation name is invalid");
			throw new ServiceDescriptionException("Supplied WSDL operation name is invalid");
		}
		if(portTypeName==null || portTypeName.equals("")) {
			mLogger.log(Level.SEVERE,"Supplied WSDL portType name is invalid");
			throw new ServiceDescriptionException("Supplied WSDL portType name is invalid");
		}
		if(bindingName==null || bindingName.equals("")) {
			mLogger.log(Level.SEVERE,"Supplied WSDL binding name is invalid");
			throw new ServiceDescriptionException("Supplied WSDL binding name is invalid");
		}

		// set member data
		mWSDLURI = wsdlURI;
		mOperationName = operationName;
		mPortTypeName = portTypeName;
		mBindingName = bindingName;

		//would like to obtain the WSDL document and cache it here, but no security context can be obtained, yet.
	}

    /**
     * Constructor allows supply of WSDL document directly, no remote retrieval is required.
     * @param wsdlDoc WSDL Document
     * @param operationName operation name for service required
     * @param portTypeName portType name for the service required
     * @param bindingName binding name for the service required
     * @throws ServiceDescriptionException
     */
	public WSDL11InterfaceImp(Document wsdlDoc,String operationName, String portTypeName, String bindingName) throws ServiceDescriptionException {
		// check args
		if(wsdlDoc==null) {
			mLogger.log(Level.SEVERE,"Supplied WSDL Document is invalid");
			throw new ServiceDescriptionException("Supplied WSDL Document is invalid");
		}
		if(operationName==null || operationName.equals("")) {
			mLogger.log(Level.SEVERE,"Supplied WSDL operation name is invalid");
			throw new ServiceDescriptionException("Supplied WSDL operation name is invalid");
		}
		if(portTypeName==null || portTypeName.equals("")) {
			mLogger.log(Level.SEVERE,"Supplied WSDL portType name is invalid");
			throw new ServiceDescriptionException("Supplied WSDL portType name is invalid");
		}
		if(bindingName==null || bindingName.equals("")) {
			mLogger.log(Level.SEVERE,"Supplied WSDL binding name is invalid");
			throw new ServiceDescriptionException("Supplied WSDL binding name is invalid");
		}

		// set member data
		mWSDLURI = THIS_URI;
		mWSDLDocument = wsdlDoc;
		mOperationName = operationName;
		mPortTypeName = portTypeName;
		mBindingName = bindingName;
    }

    /**
     * Retrieve the type description for this interface
     * @return type description
     */
    public InterfaceTypeDescriptor getTypeDescriptor()  {
	    if(mDescriptorForThis==null)
	          mDescriptorForThis = new WSDL11TypeDescriptor();
          return mDescriptorForThis;
    }

    /**
     * Retrieve the URI string for the WSDL definition document
     * @return URI string
     */
    public String getWSDLURI() {
        return mWSDLURI;
    }

    /**
     * Retrieve the WSDL document
     * @return WSDL document
     */
    public Document getWSDLDocument() throws ServiceDescriptionException {
        if(mWSDLDocument == null)
            throw new ServiceDescriptionException("Tried to obtain cached WSDL document when it does not exist, you need to pass in the document at '" + getWSDLURI() + "'");
        return mWSDLDocument;
    }

    /**
     * Retrieve the operation name required for the invocation
     * @return operation name can be null if not set yet, use WSDLDocCached() to check
     */
    public String getOperationName() {
      return mOperationName;
    }

    /**
     * Retrieve the binding required for the invocation
     * @return binding name can be null if not set yet, use WSDLDocCached() to check
     */
    public String getWSDLBinding() {
        return mBindingName;
    }


    /**
     * Retrieve the portType name for the required service
     * @return portType name can be null if not set yet, use WSDLDocCached() to check
     */
    public String getPortType() {
        return mPortTypeName;
    }

    /**
     * Test whether the service required uses RPC or Document SOAP
     * @return true if RPC service, false otherwise
     */
    public boolean isRPC() {
        //This information can be obtained from the WSDL document, uses WSDL4J to find out
        //for now say no so the code throws exception and reminds me to implement this.
        return true;
    }

    /**
     * Test to see if WSDL document is cached
     * @return true if cached, false otherwise
     */
    public boolean WSDLDocCached() {
        if(mWSDLDocument == null)
            return false;
        else
            return true;
    }

    /**
     * Set the WSDL Document, overwrites any existing cached document
     * @param wsdlDoc WSDL Document
     */
    public void setWSDLDocument(org.w3c.dom.Document wsdlDoc) {
        mWSDLDocument = wsdlDoc;
    }

    private void writeObject(java.io.ObjectOutputStream out) throws IOException {
	    String strXML;
	    StringBuffer strBuffer;

	    try {
		    out.writeObject(this.mWSDLURI);
		    out.writeObject(this.mOperationName);
		    out.writeObject(this.mPortTypeName);
		    out.writeObject(this.mBindingName);
		    //writing out the WSDL doc requires a bit of work
		    if(mWSDLDocument != null) {
			    out.writeBoolean(true);
			    strXML = XMLUtils.DocumentToString( mWSDLDocument );
			    strBuffer = new StringBuffer( strXML );
			    out.writeObject( strBuffer );
			    mLogger.log(Level.INFO,"###write WSDL interface written");
		    }
		    else out.writeBoolean(false);
	    }
	    catch( Exception ex ) {
		    mLogger.log(Level.SEVERE,"writeObject failed ",ex );
		    throw new IOException("WSDL11InterfaceImp writeObject failed");
	    }
    }

    private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
	    boolean wsdlDocExists;
	    InputSource inSource;
	    StringBuffer strBuffer;

	    try {
		    // read objects
		    this.mWSDLURI = (String) in.readObject();
		    this.mOperationName = (String) in.readObject();
		    this.mPortTypeName = (String) in.readObject();
		    this.mBindingName = (String) in.readObject();

		    //read in the WSDL doc
		    wsdlDocExists = in.readBoolean();
		    if(wsdlDocExists) {
			    strBuffer = (StringBuffer) in.readObject();
			    inSource = new InputSource( new StringReader( strBuffer.toString() ) );
			    mWSDLDocument = XMLUtils.newDocument( inSource );
		    }
		    else mWSDLDocument = null;
	    }
	    catch( Exception ex ) {
		    //try to obtain from remote address
		    //log an error and throw an IOException
		    mLogger.log(Level.SEVERE,"readObject failed ",ex );
		    throw new IOException("WSDL11InterfaceImp readObject failed");
	    }
    }

}
