import java.util.*;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNamespace;
import org.apache.axiom.om.impl.builder.StAXOMBuilder;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.ConfigurationContextFactory;
import org.apache.neethi.Policy;
import org.apache.neethi.PolicyEngine;
import org.apache.rampart.RampartMessageData;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.Name;
import javax.xml.soap.Node;
import javax.xml.namespace.QName;


import org.apache.axiom.soap.SOAPBody;
import org.apache.axis2.client.async.AsyncResult;
import org.apache.axis2.client.async.Callback;
import org.apache.axis2.transport.http.HTTPConstants;
import org.apache.axis2.transport.http.HttpTransportProperties.ProxyProperties;


public class CurrencyServiceClient {

    public static void convertCurrency(String amount, String currency, SOAPElement samlToken) throws Exception {
                
     try {

        float f = Float.parseFloat(amount);

        //ConfigurationContext ctx = ConfigurationContextFactory.createConfigurationContextFromFileSystem("./client_repo", null);
        ConfigurationContext ctx = ConfigurationContextFactory.createConfigurationContextFromFileSystem("./client_repo", "./client_repo/conf/axis2.xml");  
        ServiceClient client = new ServiceClient(ctx, null);
  
        //  client.engageModule("rampart");
	  client.engageModule("addressing");
	  client.engageModule("sandesha2");

        Options options = new Options();
        options.setAction("urn:exchange");
        options.setTo(new EndpointReference("http://localhost:9973/axis2/services/CurrencyService"));
  	  options.setUseSeparateListener(true);
        client.setOptions(options);
/*        
ProxyProperties pp = new ProxyProperties();
pp.setProxyName("localhost"); pp.setProxyPort(9973);
client.getOptions().setProperty(HTTPConstants.PROXY,pp);
*/
	  System.out.println("Engaged Sandesha2... !! ");


	  /* Line Number: XYZ */
	  client.addHeader(getHeader(samlToken));

	  System.out.println("About to invoke sendReceive on client...");

	  options.setProperty("Sandesha2LastMessage", "false");

	  // OMElement response = client.sendReceive(getPayload(amount, currency)); 
        // System.out.println(response);
	
	  client.sendReceiveNonBlocking(getPayload(amount, currency), new TestCallback("Callback1"));
	  
	  System.out.println("*****************************");
	  System.out.println("Done with the FIRST RM CALL... ");
	  System.out.println("Making FINAL RM CALL... ");
	  System.out.println("*****************************");  

	  options.setProperty("Sandesha2LastMessage", "true");

        // response = client.sendReceive(getPayload(amount, currency)); 
	  // System.out.println(response);

        Callback cb2 = new TestCallback("Callback2");

	
	  client.sendReceiveNonBlocking(getPayload(amount, currency), cb2);
	  
	  System.out.println("*****************************");
	  System.out.println("Done with FINAL RM CALL... ");
	  System.out.println("*****************************");


	  while(!cb2.isComplete()) {
		System.out.println("Waiting for cb2 to be done...");
	      Thread.sleep(2000);
        } 

	  Thread.sleep(20000);

	  System.out.println("Given enough time for RM threads to complete");
	  System.out.println("About to exit...");
	  System.exit(0);

      }
      catch (Exception ex) {
        System.out.println("CurrencyServiceClient caught Exception: " + ex);
 	  ex.printStackTrace();
      }        
    }
    
    private static Policy loadPolicy(String xmlPath) throws Exception {
        StAXOMBuilder builder = new StAXOMBuilder(xmlPath);
        return PolicyEngine.getPolicy(builder.getDocumentElement());
    }

    private static OMElement getHeader(SOAPElement samlToken) {
       OMFactory factory = OMAbstractFactory.getOMFactory();
       OMNamespace ns = factory.createOMNamespace("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd","ns2");
       OMElement headerElem = factory.createOMElement("Security", ns);

	 /* Line Number: PQR */
	 headerElem.addAttribute("soapenv:mustunderstand", "1", null);
      

	 OMElement convertedSaml = convertSaml(samlToken);
       headerElem.addChild(convertedSaml);

       return headerElem;

    }

    
    private static OMElement getPayload(String amount, String currency) {
        OMFactory factory = OMAbstractFactory.getOMFactory();
        OMNamespace ns = factory.createOMNamespace("http://ws.apache.org/axis2/xsd","ns2");
        OMElement elem = factory.createOMElement("exchange", ns);

        OMNamespace ns1 = factory.createOMNamespace("http://ws.apache.org/axis2/xsd", null);
        OMElement childElem = factory.createOMElement("param0", ns1);
        childElem.setText(amount);
        elem.addChild(childElem);

        OMNamespace ns2 = factory.createOMNamespace("http://ws.apache.org/axis2/xsd", null);
        OMElement childElem1 = factory.createOMElement("param1", ns2);
        childElem1.setText(currency);
        elem.addChild(childElem1);
        
        return elem;
    }


    private static OMElement convertSaml (SOAPElement samlToken) {

	  OMFactory factory = OMAbstractFactory.getOMFactory();
	  OMNamespace samlNS = factory.createOMNamespace("urn:oasis:names:tc:SAML:1.0:assertion", "saml");
	  OMElement samlRoot = factory.createOMElement(samlToken.getElementName().getLocalName(), samlNS);
	  samlRoot = loopAndAddAttributes(samlToken, samlRoot);
    
	  return samlRoot;
    }

    private static OMElement loopAndAddAttributes(SOAPElement elem, OMElement omElem) {
     try{ 
        Iterator attribItor = elem.getAllAttributes();	 
	  while (attribItor.hasNext()) {
           Name attrName = (Name) attribItor.next();
           String attrValue = (String) elem.getAttributeValue(attrName);
           omElem.addAttribute(attrName.getLocalName(), attrValue, null);
	  }
	  
	  Iterator elemItor = null;
	  elemItor = elem.getChildElements();

	  Node n = null;

	  while (elemItor.hasNext()) {
	    boolean textElemFlag = false;
	    SOAPElement e = null;
	    Object tempObj = elemItor.next();
	    try {
             e = (SOAPElement) tempObj;
          }
          catch (ClassCastException cce) {
		// MUST BE A TEXT NODE.. Just get the name and value 
            // ADD an OMElement and move on...
		
		textElemFlag = true;
            n = (Node) tempObj;
	      
          }

	    if (textElemFlag==false) {
	       Name eName = e.getElementName();
	       String localName = eName.getLocalName();
	       String prefix = eName.getPrefix();
	       String uri = eName.getURI();
	       OMFactory factory = OMAbstractFactory.getOMFactory();
	       OMNamespace samlNS = factory.createOMNamespace(uri, prefix);
             OMElement omEl = factory.createOMElement(localName, samlNS);
             omEl=loopAndAddAttributes(e, omEl); 
	       omElem.addChild(omEl);
          }
	    else {
		String textNodeValue = n.getValue();
		omElem.setText(textNodeValue);
          }
        }
	  return omElem;
     }
     catch (Exception ex) {
        System.out.println("loopAndAddAttributes: caught exception " + ex);
	  ex.printStackTrace();
     }
     return omElem;
    }    


    static class TestCallback extends Callback {

                String name = null;
                public TestCallback (String name) {
                        this.name = name;
                }
                
                public void onComplete(AsyncResult result) {
                        
				System.out.println("Result is : (" + this.name + ") \n" +  result);
                }

                public void onError (Exception e) {
                        System.out.println("Error reported for test call back");
                        e.printStackTrace();
                }
    }

}

