//-----------------------------------------------------------------------------
// Copyright (c) 1994,1995 Southeastern Universities Research Association,
//                         Continuous Electron Beam Accelerator Facility
//
// This software was developed under a United States Government license
// described in the NOTICE file included as part of this distribution.
//
// Jefferson Lab HPC Group, 12000 Jefferson Ave., Newport News, VA 23606
//-----------------------------------------------------------------------------
//
// Description:
//      rsvcDataOutputStream that converts a rsvcData into byte stream
//
// Author:  
//      Jie Chen
//      Jefferson Lab HPC Group
//
// Revision History:
//   $Log: rsvcDataOutputStream.java,v $
//   Revision 1.1.1.1  2000/05/23 15:12:50  pal
//   cdev_psi_1.7.2
//
//   Revision 1.1  1999/10/18 17:12:41  chen
//   *** empty log message ***
//
//
//
import java.io.*;

public class rsvcDataOutputStream
{
    // for 32 bit machine
    public static final int _RSVC_STREAM_BYTE_UNIT = 4;
    
    /**
     * Return a long word (32 bit) aligned size from original size
     */
    public static final int _RSVC_RNDUP (int x)
    {
	return ((x + _RSVC_STREAM_BYTE_UNIT - 1)/_RSVC_STREAM_BYTE_UNIT)
	    * _RSVC_STREAM_BYTE_UNIT;
    }

    /**
     * Return size information for a single byte 
     */
    public static int streamSize (byte c)
    {
	return rsvcDataOutputStream._RSVC_RNDUP ((int)1);
    }

    /**
     * Return size information for a short
     */
    public static int streamSize (short c)
    {
	return rsvcDataOutputStream._RSVC_RNDUP ((int)2);
    }

    /**
     * Return size information for a int 
     */
    public static int streamSize (int c)
    {
	return rsvcDataOutputStream._RSVC_RNDUP ((int)4);
    }

    /**
     * Return size information for a long
     */
    public static int streamSize (long c)
    {
	return rsvcDataOutputStream._RSVC_RNDUP ((int)8);
    }

    /**
     * Return size information for a float
     */
    public static int streamSize (float c)
    {
	return rsvcDataOutputStream._RSVC_RNDUP ((int)4);
    }
    
    /**
     * Return size information for a double
     */
    public static int streamSize (double c)
    {
	return rsvcDataOutputStream._RSVC_RNDUP ((int)8);
    }

    /**
     * Return size information for a string
     */
    public static int streamSize (String c)
    {
	return rsvcDataOutputStream.streamSize ((int)4) + 
	    rsvcDataOutputStream._RSVC_RNDUP ((int)(c.length() + 1));
    }

    /**
     * Return size information for a fix buffer of string
     */
    public static int streamSize (String str, int buflen)
    {
	return rsvcDataOutputStream.streamSize (buflen) +
	    rsvcDataOutputStream._RSVC_RNDUP(buflen);
    }


    /**
     * Return size information for a double
     */
    public static int streamSize (rsvcTimeStamp ts)
    {
	return 2*rsvcDataOutputStream._RSVC_RNDUP ((int)4);
    }


    // underlying data output stream
    private DataOutputStream out = null;

    /**
     * Construct a data output stream
     */
    public rsvcDataOutputStream (OutputStream stream)
    {
	try {
	    out = new DataOutputStream (stream);
	}catch (Exception e) {
	    e.printStackTrace();
	}
    }

    /**
     * Return how many bytes have been written to this stream
     */
    public final int size ()
    {
	return out.size ();
    }


    /**
     * Write a single byte char to stream
     */
    public void write (char c) throws IOException
    {
	int tmp = (int)c;
	try {
	    out.writeInt (tmp);
	}catch (IOException e) {
	    throw e;
	}
    }

    /**
     * Write a value of short to stream
     */
    public void write (short c) throws IOException
    {
	int tmp = (int)c;
	try {
	    out.writeInt (tmp);
	}catch (IOException e) {
	    throw e;
	}
    }

    /**
     * Write a value of int to stream
     */
    public void write (int c) throws IOException
    {
	try {
	    out.writeInt (c);
	}catch (IOException e) {
	    throw e;
	}
    }


    /**
     * Write a value of float to stream
     */
    public void write (float c) throws IOException
    {
	try {
	    out.writeFloat (c);
	}catch (IOException e) {
	    throw e;
	}
    }


    /**
     * Write a value of double to stream
     */
    public void write (double c) throws IOException
    {
	try {
	    out.writeDouble (c);
	}catch (IOException e) {
	    throw e;
	}
    }

    /**
     * Write a value of long to stream
     */
    public void write (long c) throws IOException
    {
	try {
	    out.writeLong (c);
	}catch (IOException e) {
	    throw e;
	}
    }

    /**
     * Write a string as series of byte using default encoding
     */
    public void write (String str) throws IOException
    {
	byte []barray = str.getBytes();
	int  len = barray.length + 1;
	int  rlen = rsvcDataOutputStream._RSVC_RNDUP (len);
	
	// first write out how many bytes that follow
	try {
	    out.writeInt (rlen);
	}catch (IOException e) {
	    throw e;
	}
	
	// write out string as bytes
	try {
	    out.writeBytes (str);
	}catch (IOException e) {
	    throw e;
	}

	// write out remainder as 0 
	for (int i = 0; i < rlen - len + 1; i++) {
	    try {
		out.writeByte (0);
	    }catch (IOException e) {
		throw e;
	    }
	}
    }


    /**
     * Write a string as series of byte using default encoding
     * to a maximum length len
     */
    public void write (String str, int len) throws IOException
    {
	if (len % rsvcDataOutputStream._RSVC_STREAM_BYTE_UNIT != 0) {
	    throw new IOException ("Fix buffer len is not long word aligned");
	}

	byte []barray = str.getBytes();
	if (barray.length >= len) {
	    // need last 0 for out string buffer
	    throw new IOException ("Overflow fix buffer");
	}
	
	// first write out how many bytes that follow
	try {
	    out.writeInt (len);
	}catch (IOException e) {
	    throw e;
	}
	
	// write out string as bytes
	try {
	    out.writeBytes (str);
	}catch (IOException e) {
	    throw e;
	}

	// write out remainder as 0 
	for (int i = 0; i < len - barray.length; i++) {
	    try {
		out.writeByte (0);
	    }catch (IOException e) {
		throw e;
	    }
	}
    }

    /**
     * Write a series of byte
     */
    public void write (byte[] c) throws Exception
    {
	if (c == null) throw new NullPointerException();
	
	int len = c.length;
	int rlen = rsvcDataOutputStream._RSVC_RNDUP (len);

	try {
	    out.writeInt (rlen);
	}catch (IOException e){
	    throw e;
	}

	try {
	    out.write (c, 0, len);
	}catch (IOException e){
	    throw e;
	}

	for (int i = 0; i < rlen - len; i++) {
	    try {
		out.writeByte (0);
	    }catch (IOException e){
		throw e;
	    }
	}
    }
    
    /**
     * Write out a time stamp to the stream
     */
    public void write (rsvcTimeStamp ts) throws IOException
    {
	try {
	    out.writeInt (ts.secPastEpoch);
	}catch (IOException e) {
	    throw e;
	}

	try {
	    out.writeInt (ts.nsec);
	}catch (IOException e) {
	    throw e;
	}
    }


    /**
     * Write out Byte to the stream
     */
    public void write (Byte c) throws IOException
    {
	try {
	    write (c.byteValue());
	}catch (IOException e) {
	    throw e;
	}
    }

    /**
     * Write out Short to the stream
     */
    public void write (Short c) throws IOException
    {
	try {
	    write (c.shortValue());
	}catch (IOException e) {
	    throw e;
	}
    }

    /**
     * Write out Integer to the stream
     */
    public void write (Integer c) throws IOException
    {
	try {
	    write (c.intValue());
	}catch (IOException e) {
	    throw e;
	}
    }

    /**
     * Write out Float to the stream
     */
    public void write (Float c) throws IOException
    {
	try {
	    write (c.floatValue());
	}catch (IOException e) {
	    throw e;
	}
    }

    /**
     * Write out Double to the stream
     */
    public void write (Double c) throws IOException
    {
	try {
	    write (c.doubleValue());
	}catch (IOException e) {
	    throw e;
	}
    }

    /**
     * Flush data out calling underlying real data stream flush method
     */
    public final void flush () throws IOException
    {
	try {
	    out.flush ();
	}catch (IOException e) {
	    throw new IOException (e.toString());
	}
    }

}
