/*****************************************************************************
 *                                                                           *
 *         Licensed Materials - Property of IBM                              *
 *                                                                           *
 *         "Restricted Materials of IBM"                                     *
 *                                                                           *
 *         5799-QRY                                                          *
 *                                                                           *
 *         (C) Copyright IBM Corp. 1998                                      *
 *                                                                           *
 *****************************************************************************/
package com.ibm.devtools.SIPNoTE;

import java.io.*;
import java.util.*;

/**
 * This class represents an transform which can change a SIP message into
 * a Jephyr message, and vice versa.  It is responsible for filling in
 * all of the necessary datafields in the corresponding message to make
 * sure that it is valid.  It however, does not validate the message
 * semantically.  </p>
 *
 * If you wish to change the protocol that is used to transfer messages
 * before they enter into this SIP realm, this is one of the few places
 * that needs to be changed. </p>
 *
 * @author Bill Nagy
 * @version 1.0
 * @see JMessage
 * @see SIPMessage
 */
public class JephyrSIPTransform
{
  SIPMessage sipmsg;
  JMessage jmsg;

  /**
   * Constructs a transform for a given SIP message.
   *   
   * @param msg The SIP message that you wish to convert.
   */
  JephyrSIPTransform(SIPMessage msg)
  {
    sipmsg = msg;
    jmsg = new JMessage();
  }

  /**
   * Constructs a transform for a given Jephyr message.
   *   
   * @param msg The Jephyr message that you wish to convert.
   */
  JephyrSIPTransform(JMessage msg)
  {
    sipmsg = new SIPMessage();
    jmsg = msg;
  }

  /**
   * Applies the transform to the SIP message and creates a
   * Jephyr message.  The content-type of the SIP message must
   * be application/jephyr in order for this to succeeed.
   *
   * @return The newly constructed Jephyr message.
   */
  public JMessage SIPToJephyr()
  {
    ByteArrayInputStream bais =
      new ByteArrayInputStream(sipmsg.getMessageBody());
    BufferedReader br = new BufferedReader(new InputStreamReader(bais));
    String messagelines[] = new String[20];
    String recipientlist[];
    int currentline = 0;

    if (!sipmsg.getContentType().equalsIgnoreCase("application/jephyr"))
      {
	System.err.println("Unsupported content type: "+sipmsg.getContentType());
	jmsg = new JMessage();
	return null;
      }

    try
      {
	String recipientstring = br.readLine();

	if (DebugDefine.DEBUG)
	  System.out.println("SIPToJephyr: (Recipientstring)"+recipientstring);
	
	StringTokenizer st = new StringTokenizer(recipientstring);

	recipientlist = new String[st.countTokens()];
	
	for (currentline = 0; currentline<recipientlist.length; currentline++)
	  {
	    try
	      {
		recipientlist[currentline] = st.nextToken();
	      }
	    catch (NoSuchElementException e)
	      {
		System.err.println("countTokens in error --> "+e);
		jmsg = new JMessage();
		return null;
	      }
	  }
	
	jmsg.setRecipientList(recipientlist);

	jmsg.setSender(br.readLine());
      }
    catch (IOException e)
      {
	e.printStackTrace(System.err);
	jmsg = new JMessage();
	return null;
      }

    currentline = 0;
    
    while(true)
      {
	try
	  {
	    messagelines[currentline] = br.readLine();
	  }
	catch (IOException e)
	  {
	    e.printStackTrace(System.err);
	    jmsg = new JMessage();
	    return null;
	  }
	  
	  if (messagelines[currentline] == null)
	    break;

	  currentline++;
	  if (currentline == messagelines.length) /* Need to increase array */
	    {
	      String [] tmpVar = new String[messagelines.length + 20];
	      System.arraycopy(messagelines, 0, tmpVar, 0,
			       messagelines.length);
	      messagelines = tmpVar;
	    }
      }

    String [] tmpVar = new String[currentline];
    System.arraycopy(messagelines, 0, tmpVar, 0, currentline);
    messagelines = tmpVar;

    jmsg.setMessage(messagelines);

    return jmsg;
  }
  
  /**
   * Applies the transform to the Jephyr message and creates a
   * SIP message.  If the Jephyr message was a command message, then
   * we set the appropriate SIP message type, otherwise this becomes
   * a SIP message type of MESSAGE.
   *
   * @param localhost The name of this client machine.
   * @param localport The port on which this client listens.
   * @param servername The name of the SIPNoTE server.
   * @param serverport The port on which the SIPNoTE server listens.
   *
   * @return The newly constructed SIP message.
   */
  public SIPMessage JephyrToSIP(String localhost, int localport,
				String servername, int serverport)
  {
    ByteArrayOutputStream baos = new ByteArrayOutputStream(255);
    DataOutputStream dos = new DataOutputStream(baos);
    String[] recipientlist;
    String[] messagebody;
    int cnt;
    SIPurl[] requestURIs;
    ViaEntity via = new ViaEntity();
    ToEntity[] tolist;
    byte[] messagebytes;
    
    via.setHost(localhost);
    via.setPort(localport);
	

    if (jmsg.isCommandMessage())
      {
	messagebody = jmsg.getMessage();
	if (messagebody[0].equalsIgnoreCase("LOCATE"))
	  {
	    sipmsg.setMethod(sipmsg.LOCATE);
	    recipientlist = jmsg.getRecipientList();
	    
	    requestURIs = new SIPurl[recipientlist.length];
	    tolist = new ToEntity[recipientlist.length];
	    for (cnt = 0; cnt < recipientlist.length; cnt++)
	      {
		requestURIs[cnt] = new SIPurl();
		requestURIs[cnt].setHost(servername);    
		requestURIs[cnt].setPort(serverport);
		requestURIs[cnt].setUser(recipientlist[cnt]);
		
		tolist[cnt] = new ToEntity();
		tolist[cnt].setURL(requestURIs[cnt]);
	      }
	    
	    sipmsg.setRequestURI(requestURIs);
	    
	    sipmsg.setMessageType(sipmsg.REQUEST);
	    
	  }
	else
	  {
	    if (messagebody[0].equalsIgnoreCase("REGISTER"))
	      {
		sipmsg.setMethod(sipmsg.REGISTER);

		/*Add subscription information*/
		try
		  {
		    BufferedReader br = new BufferedReader(new FileReader(".jsubs"));
		    String subline;
		    
		    while ((subline = br.readLine()) != null)
		      {
			if (subline.length() != 0)
			  sipmsg.addSubscription(subline);
		      }
		    
		    br.close();
		  }
		catch (FileNotFoundException e)
		  {
		  }
		catch (IOException e)
		  {
		    System.err.println("Error reading .jsubs file. --> "+e);
		  }
		catch (MalformedMessageException e)
		  {
		    e.printStackTrace(System.err);
		    sipmsg = new SIPMessage();
		    return null;
		  }
	      }
	    else
	      if (messagebody[0].equalsIgnoreCase("UNREGISTER"))
		sipmsg.setMethod(sipmsg.UNREGISTER);

	    requestURIs = new SIPurl[1];
	    requestURIs[0] = new SIPurl();
	    
	    requestURIs[0].setHost(servername);    
	    requestURIs[0].setPort(serverport);
	    requestURIs[0].setUser(jmsg.getSender());
	    
	    tolist = new ToEntity[1];
	    tolist[0] = new ToEntity();
	    tolist[0].setURL(requestURIs[0]);
	    
	    sipmsg.setMessageType(sipmsg.REQUEST);
	    
	    sipmsg.setRequestURI(requestURIs);
	  }
 
	try
	  {
	    sipmsg.addVia(via);
	    sipmsg.addTo(tolist);
	  }
	catch (MalformedMessageException e)
	  {
	    e.printStackTrace(System.err);
	    sipmsg = new SIPMessage();
	    return null;
	  }	
      }
    else
      {

	/*This is an actual message*/
        recipientlist = jmsg.getRecipientList();
	
	requestURIs = new SIPurl[recipientlist.length];
	tolist = new ToEntity[recipientlist.length];
	for (cnt = 0; cnt < recipientlist.length; cnt++)
	  {
	    requestURIs[cnt] = new SIPurl();
	    requestURIs[cnt].setHost(servername);    
	    requestURIs[cnt].setPort(serverport);
	    requestURIs[cnt].setUser(recipientlist[cnt]);

	    tolist[cnt] = new ToEntity();
	    tolist[cnt].setURL(requestURIs[cnt]);
	  }
	
	sipmsg.setMessageType(sipmsg.REQUEST);
	sipmsg.setMethod(sipmsg.MESSAGE);
	sipmsg.setRequestURI(requestURIs);
	
	try
	  {
	    sipmsg.addVia(via);
	    sipmsg.addTo(tolist);
	  }
	catch (MalformedMessageException e)
	  {
	    e.printStackTrace(System.err);
	    sipmsg = new SIPMessage();
	    return null;
	  }	
	
	
	/*Transferring in Unicode is actually a little wasteful, since
	  it takes 2 bytes for every character.  Do we want to support
	  this?  (Yes, for now.)*/
	try
	  {
	    for (cnt = 0; cnt < recipientlist.length; cnt++)
	      {
		dos.writeBytes(recipientlist[cnt]);
		dos.writeByte(' ');
	      }
	    dos.writeByte('\n');
	    dos.writeBytes(jmsg.getSender());
	    dos.writeByte('\n');
	    messagebody = jmsg.getMessage();
	    for (cnt = 0; cnt < messagebody.length; cnt++)
	      {
		dos.writeBytes(messagebody[cnt]);
	      }
	    dos.flush();
	  }
	catch (IOException e)
	  {
	    e.printStackTrace(System.err);
	    sipmsg = new SIPMessage();
	    return null;
	  }
	
	messagebytes = baos.toByteArray();
	
	/*Make sure that we set the content-type, otherwise
	  we won't be able to decode this.*/
	sipmsg.setContentType("application/jephyr");
	sipmsg.setMessageBody(messagebytes);
      }
    
    return sipmsg;
  }
}

