//////////////////////////////////////////////////////////////////////////// 
// 
// Copyright (C) DSTC Pty Ltd (ACN 052 372 577) 1993, 1994, 1995.
// Unpublished work.  All Rights Reserved.
// 
// The software contained on this media is the property of the
// DSTC Pty Ltd.  Use of this software is strictly in accordance
// with the license agreement in the accompanying LICENSE.DOC 
// file. If your distribution of this software does not contain 
// a LICENSE.DOC file then you have no rights to use this 
// software in any manner and should contact DSTC at the address 
// below to determine an appropriate licensing arrangement.
// 
//      DSTC Pty Ltd
//      Level 7, GP South
//      University of Queensland
//      St Lucia, 4072
//      Australia
//      Tel: +61 7 3365 4310
//      Fax: +61 7 3365 4311
//      Email: jcsi@dstc.qut.edu.au
// 
// This software is being provided "AS IS" without warranty of
// any kind.  In no event shall DSTC Pty Ltd be liable for
// damage of any kind arising out of or in connection with
// the use or performance of this software.
// 
//////////////////////////////////////////////////////////////////////////// 

package com.dstc.security.ssl;

import java.io.IOException;
import java.io.OutputStream;
import java.io.FilterOutputStream;

import javax.net.ssl.SSLHandshakeException;

/**
 * An output stream for application data
 *
 * @author Ming Yung
 */
class SSLDataOutputStream extends FilterOutputStream
{
  private ProtocolUnitOutputStream os;
  private Object writeLock, readLock;
  private HandShaker handShaker;

  SSLDataOutputStream(OutputStream os, Object writeLock, Object readLock,
                      SSLContext ctx)
  {
    super(os);

    this.os = (ProtocolUnitOutputStream)os;
    this.writeLock = writeLock;
    this.readLock = readLock;
    this.handShaker = ctx.getHandShaker();
  }

  public void close() throws IOException
  {
    super.close();
    //System.out.println("outclose");
  }

  public void write(int b) throws IOException
  {
    write(new byte[]{(byte)(b & 0xff)});
  }

  public void write(byte[] data) throws IOException
  {
    write(data, 0, data.length);
  }

  public void write(byte[] data, int offset, int length) throws IOException
  {
    if (this.handShaker.handShakeNotYetBegun())
    {
      synchronized (writeLock)
      {
        if (this.handShaker instanceof ClientHandShaker)
          this.handShaker.startHandShake();
        writeLock.notifyAll();

        synchronized (readLock)
        {
          readLock.notifyAll();
        }
      }
    }

    synchronized (writeLock)
    {
      try
      {
        while (!this.handShaker.handShakeCompleted())
          writeLock.wait();

        if (this.handShaker.badCompletion())
          throw new SSLHandshakeException("Handshake failure");
      }
      catch (InterruptedException e)
      {
        //wake up
      }

      ApplicationData appData = new ApplicationData(data, offset, length);
      os.writeProtocolUnit(appData);

      if (Debug.debug >= Debug.DEBUG_RECORD)
        Debug.debug("Sent something");
    }
  }
}
