/*
 * @(#)SellerConversation.java	1.4
 *
 * Copyright 2000 by Sun Microsystems, Inc.,
 * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
 * All rights reserved.
 *
 * This software is the confidential and proprietary information
 * of Sun Microsystems, Inc. ("Confidential Information").  You
 * shall not disclose such Confidential Information and shall use
 * it only in accordance with the terms of the license agreement
 * you entered into with Sun.
 */

package com.sun.ebxml.test;

import java.io.*;
import java.net.*;
import java.util.Enumeration;
import java.util.Hashtable;
import javax.xml.transform.*;
import javax.xml.transform.stream.*;
//import javax.xml.messaging.*;
import javax.mail.*;
import javax.mail.internet.*;

import com.sun.ebxml.soapmsh.*;
import com.sun.ebxml.common.Utils;
import com.sun.xml.messaging.common.Logger;

import org.apache.soap.*;
import org.apache.soap.rpc.*;
import org.apache.soap.util.mime.*;

/**
 * SellerConversation is an abstract class that implements the 
 * "BSI" for a given collaboration. This class represents
 * the state of a given conversation instance and should
 * implement methods that enforce the rules of the collaboration
 * as specified in the Business Process Specification Schema
 * that is identified in the CPA of the parent ConversationManager.
 *
 * @author <a href="mailto:chris.ferris@east.sun.com">Chris Ferris</a>
 * @version 1.3 - 03/14/01 19:41:57
 */
public class SellerConversation
		extends Conversation {
	private ConversationManager mgr;
	private String id;
    private long expiration;
	private AppEndpointImpl destination;
	private static final Logger logger = Logger.getLogger("SellerConversation");
	private static final int INITIAL = 0;
	private static final int ORDERMESSAGE_RECD = 1;
	private static final int SUCCESS = 2;
	private static final String ORDERSERVICE = "OrderProcessing";
	private static final String NEWORDERACTION = "ProcessNewOrder";
	private static final String CONFIRMACTION = "OrderConfirm";
	private int state = 0; // initial state
	private String[] states = {
		"Initial State", "Order Message Received", 
		"OrderConfirm Message Sent"
	};
	private byte[] confXsl;
	private String confXslFileName = "transforms/confirm-hrf.xsl";
	private TransformerFactory tFactory;

	/**
	 * Default constructor
	 */
	public SellerConversation() {
		setState(SellerConversation.INITIAL);
	}

	public void init(String id) {
		super.init(id);
        try {
            InputStream str = getResourceAsStream(confXslFileName);
            confXsl = readFully(str);
        }
        catch (IOException x) {
            x.printStackTrace(System.err);
            throw new RuntimeException("Could not resolve stylesheet: " + confXslFileName);
        }
	}

	private void setState(int next) {
		state = next;
		setState(states[next]);
	}

	/**
	 * Called by the ConversationManager
	 * upon receipt of a SOAPMessageImpl to be processed.
	 *
	 * @param message the SOAPMessageImpl to be processed
	 */
	public void onMessage(SOAPMessageImpl message)
			throws SOAPException {
		try {
			//
			// if the message has already been processed, 
			// ignore (super class will resend previous response
			//
			if (processMessage(message) == false) return;

			String service
				= message.getProperty(com.sun.ebxml.soapmsh.Constants.SERVICE);
			String action
				= message.getProperty(com.sun.ebxml.soapmsh.Constants.ACTION);
			System.err.println("Conversation.onMessage(): id: " + id + " received message: " + service + "/" + action);
			if (SellerConversation.ORDERSERVICE.equals(service)
					&& SellerConversation.NEWORDERACTION.equals(action)
					&& state == SellerConversation.INITIAL) {
				setState(SellerConversation.ORDERMESSAGE_RECD);
				// do some processing
				message.acknowledge();
				System.err.println("onMessage(): acknowledged message!");
				System.out.println("print rec'd SOAPContext:");
				SOAPContext ctx = message.getRequestSOAPContext();
				int pidx = 0;
				MimeBodyPart part = ctx.getBodyPart(pidx);
				while(null != part) {
					InputStream is = part.getInputStream();
					ByteArrayOutputStream baos = new ByteArrayOutputStream();
					byte[] b = new byte[1024];
					int l = 0;
					while ((l = is.read(b)) != -1) {
						baos.write(b, 0, l);
					}
					System.err.println("part: " + Integer.toString(pidx));
					System.err.println(new String(baos.toByteArray()));
					pidx++;
					part = ctx.getBodyPart(pidx);
				}
				message.acknowledge();
			}
			else {
				logger.logInfo("Invalid message received!");
				throw new SOAPException(org.apache.soap.Constants.FAULT_CODE_CLIENT, "Invalid message received!");
			}
		}
		catch (Exception x) {
			x.printStackTrace();
			throw new SOAPException(org.apache.soap.Constants.FAULT_CODE_CLIENT, x.getMessage(), x);
		}
	}

	/**
	 * create a new SOAPMessageImpl for this Conversation
	 * @return the created SOAPMessageImpl object
	 * @throws SOAPException if there is any error
	 */
    public SOAPMessageImpl confirmOrder(SOAPMessageImpl request, byte[] payload)
			throws SOAPException {
		if (state != SellerConversation.ORDERMESSAGE_RECD)
			throw new SOAPException(org.apache.soap.Constants.FAULT_CODE_CLIENT,
				"Choreography error: ");
		String service = ORDERSERVICE;
		String action = CONFIRMACTION;
		String refmsgid = request.getProperty(com.sun.ebxml.soapmsh.Constants.MSGID);

		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		StreamResult res = new StreamResult(baos);
		Hashtable params = new Hashtable();
		params.put("ConversationId", request.getProperty("convid"));
		try {
			transform(new ByteArrayInputStream(payload), res, confXsl, params);
		}
		catch (TransformerException x) {
			x.printStackTrace(System.err);
			throw new SOAPException(org.apache.soap.Constants.FAULT_CODE_CLIENT, 
					"unable to transform confirmation!");
		}
		SOAPMessageImpl msg = send(service, action, refmsgid,
			"confirm.xml", payload, "confirm.html", baos.toByteArray());
		setState(SellerConversation.SUCCESS);
		return msg;
    }

	protected SOAPMessageImpl send(String service,
            String action, String refmsgid, String loc, byte[] payload,
            String loc2, byte[] payload2)
                throws SOAPException {
        try {
			byte [] payloadBytes = Utils.prettyPrint(payload);

            InternetHeaders hdrs = new InternetHeaders();
            hdrs.addHeader("Content-Type", "application/xml");
            hdrs.addHeader("Content-Location", loc);
			String _cid = MimeUtils.getUniqueValue();
			String cid = '<' + _cid + '>';
            hdrs.addHeader("Content-ID", cid);
            MimeBodyPart payloadPart = new MimeBodyPart(hdrs, payloadBytes);
            SOAPMessageImpl msg = createMessage(service, action,
				refmsgid, _cid);
            msg.addBodyPart(payloadPart);

            InternetHeaders hdrs2 = new InternetHeaders();
            hdrs2.addHeader("Content-Type", "text/html");
            hdrs2.addHeader("Content-Location", loc2);
			String cid2 = '<' + MimeUtils.getUniqueValue() + '>';
            hdrs2.addHeader("Content-ID", cid2);
            payloadPart = new MimeBodyPart(hdrs2, payload2);
            msg.addBodyPart(payloadPart);
            msg.send();
            return msg;
        }
        catch (Exception x) {
            x.printStackTrace();
            throw new SOAPException(org.apache.soap.Constants.FAULT_CODE_CLIENT, x.getMessage(), x);
        }
    }

   private byte[] readFully(InputStream is)
            throws IOException {
        byte[] buf = new byte[1024];
        int num = 0;
        ByteArrayOutputStream bout = new ByteArrayOutputStream();

        while( (num = is.read(buf)) != -1) {
            bout.write(buf, 0, num);
        }

        return bout.toByteArray();
    }

    private void transform(InputStream header,
        Result result, byte[]xsl, Hashtable params)
            throws TransformerException {

		if (null == tFactory) {
        	tFactory = TransformerFactory.newInstance();
		}
        Transformer transformer
            = tFactory.newTransformer(
                new StreamSource(new ByteArrayInputStream(xsl)));
        if (null != params) {
            Enumeration keys = params.keys();
            while (keys.hasMoreElements()) {
                String key = (String)keys.nextElement();
                String value = (String)params.get(key);
                transformer.setParameter(key, value);
            }
        }
        transformer.transform(new StreamSource(header), result);
    }
}

