/*
 *
 *  Copyright (C) 1999, Institute for MicroTherapy
 *
 *  This software and supporting documentation were developed by
 *
 *    University of Witten/Herdecke
 *    Department of Radiology and MicroTherapy
 *    Institute for MicroTherapy
 *    Medical computer science
 *    
 *    Universitaetsstrasse 142
 *    44799 Bochum, Germany
 *    
 *    http://www.microtherapy.de/go/cs
 *    mailto:computer.science@microtherapy.de
 *
 *  THIS SOFTWARE IS MADE AVAILABLE,  AS IS,  AND THE INSTITUTE MAKES  NO 
 *  WARRANTY REGARDING THE SOFTWARE, ITS PERFORMANCE, ITS MERCHANTABILITY
 *  OR FITNESS FOR ANY PARTICULAR USE, FREEDOM FROM ANY COMPUTER DISEASES 
 *  OR ITS CONFORMITY TO ANY SPECIFICATION. THE ENTIRE RISK AS TO QUALITY 
 *  AND PERFORMANCE OF THE SOFTWARE IS WITH THE USER.
 *
 *  Author :      $Author: kleber $
 *  Last update : $Date: 2001/06/06 10:32:30 $
 *  Revision :    $Revision: 1.1.1.1 $
 *  State:        $State: Exp $
*/


package processCommunication;

import J2Ci.*;
import java.io.*;
import java.net.*;
import java.util.*;

/**
 * This class handles the communication with the 
 * DICOMscope processes. 
 * 
 * @author Klaus Kleber
 * @since 16.10.2000
 */
public class ProcessCommunicationHandler extends java.lang.Thread
{   
    /**
    * Date/Time format: YYYY-MM-Dd:HH-mm-ss:SSSSSS 
    */ 
    public static final java.text.SimpleDateFormat dateTimeFormaterString = new java.text.SimpleDateFormat("yyyy-MM-dd, HH:mm:ss.SSSSSS");
    
    
    /**
    * Socket
    */
    private Socket socket;
    /**
    * InputStream
    */
    DataInputStream in;
    
    /** 
    * OutputStream
    */
    DataOutputStream out;
    
    
    /**
    * Counter for the applicationID
    */
    private static int processIDCounter = 0;
    
   
    
    /**
    * Constuctor with the specified Socket.
    * @param socket Communication socket
    */
    public ProcessCommunicationHandler(Socket socket)
    {
        this.socket = socket;
    }
    /**
    * Contains the avilable processes. For each processID you can get the name of the process
    */
    private static Hashtable processList = new Hashtable();
    /**
    * Open the Input/OutputStream and waits for messages. Each received message will be
    * answered. This function stops if the skocket will be closed.
    */
    public void run()
    {
        
        try
        {
            in = new DataInputStream(socket.getInputStream());
            out = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
        }
        catch(IOException e)
        {
            System.err.println(e);
        }
        try
        {
            while(true)
            {
                handleMessage();
            }
        }
        catch(IOException e)
        {
            //System.err.println(e);
            
        }
        
    }
    /**
    * Receives the message and answered it. 
    * For each received message a DicomScopeMessage will
    * be fired.
    */
    private  void handleMessage() throws IOException
    {
            int processId=-1;
            String text = null;
            
            int messageId  = in.readInt();
            String messageName = ProcessMessageIDs.getMessageName(messageId);
            
            
            int payload = in.readInt();
            int statusId = 0;
            
            switch(messageId)
            {
                case ProcessMessageIDs.REQUEST_APPLICATION_IDENTIFICATIONNUMBER:
                        processId = giveNewProcessID();
                        int processType = in.readInt();
                        statusId = in.readInt();
                        text = readText(in);
                        out.writeInt(ProcessMessageIDs.ASSIGN_APPLICATION_IDENTIFICATION_NUMBER);
                        out.writeInt(4);
                        out.writeInt(processId);
                        insertProcess(processId, processType);
                        break;
                case ProcessMessageIDs.APPLICATION_TERMINATES: 
                        processId = in.readInt();
                        statusId = in.readInt();
                        out.writeInt(ProcessMessageIDs.RESPOND_OK);
                        out.writeInt(0);
                        //  The processId of the process will be removed at the end of this function         
                        
                        break;
                case ProcessMessageIDs.RECEIVED_UNENCRYPTED_DICOM_CONNECTION:
                        processId = in.readInt();
                        statusId = in.readInt();
                        text = readText(in);
                        out.writeInt(ProcessMessageIDs.RESPOND_OK);
                        out.writeInt(0);
                       break;
                case ProcessMessageIDs.RECEIVED_ENCRYPTED_DICOM_CONNECTION:
                        processId = in.readInt();
                        statusId = in.readInt();
                        text = readText(in);
                        out.writeInt(ProcessMessageIDs.RESPOND_OK);
                        out.writeInt(0);
                       break;
                case ProcessMessageIDs.DICOM_CONNECTION_CLOSED:
                        processId = in.readInt();
                        statusId = in.readInt();
                        out.writeInt(ProcessMessageIDs.RESPOND_OK);
                        out.writeInt(0);
                       break;
                case ProcessMessageIDs.DICOM_CONNECTION_ABORDED:
                        processId = in.readInt();
                        statusId = in.readInt();
                        text = readText(in);
                        out.writeInt(ProcessMessageIDs.RESPOND_OK);
                        out.writeInt(0);
                       break;
                case ProcessMessageIDs.REQUESTED_UNENCRYPTED_DICOM_CONNECTION:
                        processId = in.readInt();
                        statusId = in.readInt();
                        text = readText(in);
                        out.writeInt(ProcessMessageIDs.RESPOND_OK);
                        out.writeInt(0);
                       break;
                case ProcessMessageIDs.REQUESTED_ENCRYPTED_DICOM_CONNECTION:
                        processId = in.readInt();
                        statusId = in.readInt();
                        text = readText(in);
                        out.writeInt(ProcessMessageIDs.RESPOND_OK);
                        out.writeInt(0);
                       break;
                case ProcessMessageIDs.RECEIVED_DICOM_OBJECT:
                        processId = in.readInt();
                        statusId = in.readInt();
                        text = readText(in);
                        out.writeInt(ProcessMessageIDs.RESPOND_OK);
                        out.writeInt(0);
                       break;
                case ProcessMessageIDs.SENT_DICOM_OBJECT:
                        processId = in.readInt();
                        statusId = in.readInt();
                        text = readText(in);
                        out.writeInt(ProcessMessageIDs.RESPOND_OK);
                        out.writeInt(0);
                       break;
            }
            out.flush();
            if (text == null) text = "";
            String processTypeName = getProcessName(processId);
            int processType= getProcessType(processId);
            String date = getCurrentDateString();
            String statusName = ProcessStatusIDs.getStatusName(statusId);
            
            //  Remove the messageID if process Terminates         
            if (messageId == ProcessMessageIDs.APPLICATION_TERMINATES) removeProcess(processId);
            ProcessController.instance().fireProcessLog(new DicomScopeMessage(  messageId,
                                                                                messageName,
                                                                                processId, 
                                                                                processType,
                                                                                processTypeName,
                                                                                date,
                                                                                statusId,
                                                                                statusName,
                                                                                text));
    
    }
    
    /**
    * Reads a String from the specified DataInputStream. The length of the String
    * will be readed first (int). A String is teminated with one or more Null bytes
    * Thes null bytes will be eleminated.
    * @return The readed String without null-bytes.
    */
    private String readText(DataInputStream in) throws IOException 
    {
        int length = in.readInt();
        byte b[] = new byte[length];
        in.read(b);
        int lastIndex = length;
        while((lastIndex > 0)&& (b[lastIndex-1] == 0x00)) lastIndex--;
        return new String(b, 0,lastIndex);
    }
    
    
    
    /**
    * Removes the process specified by the Id.
    * @param processId Specifies the process to be removed.
    */
    private void removeProcess(int processId)
    {
        processList.remove(new Integer(processId));
    }
    
    /**
    * Insert a process
    * @param processId Unique ID identifying a process.
    * @param processType Id for the process type
    */
    private static synchronized  void insertProcess(int processId,int processType)
    {
        processList.put(new Integer(processId),new Integer(processType) );
        
    }
    
    /**
    * Gets the type of a process with the specified Id.
    * @param processId Id of the process
    * @return The type of the process.
    */
    private static synchronized int getProcessType(int processId)
    {
         return ((Integer) processList.get(new Integer(processId))).intValue();
    }
    
    
    /**
    * Gets the name of a process with the specified Id.
    * @param processId Id of the process
    * @return The name of the process.
    */
    private static synchronized String getProcessName(int processId)
    {
       return  ProcessTypeIDs.getProcessName(getProcessType(processId));
    }
    
    /**
    * Calculates a new unique process id:
    * @return Returns the new process id
    */
    public synchronized static int giveNewProcessID()
    {
        return processIDCounter++;
    }
    
    /**
    * Returns a String with the current date in ISO format.
    * (Date/Time format: YYYY-MM-Dd:HH-mm-ss:SSSSSS )
    * @return String with the current date in ISO format.
    */
    public String getCurrentDateString()
    {
    	Calendar calendar = new GregorianCalendar ();
	return dateTimeFormaterString.format(calendar.getTime());
        
    }
    
}

/*
 *  CVS Log
 *  $Log: ProcessCommunicationHandler.java,v $
 *  Revision 1.1.1.1  2001/06/06 10:32:30  kleber
 *  Init commit for DICOMscope 3.5
 *  Create new CVS
 *
*/
