/*


    @author DanielD

    ========== licence begin GPL
    Copyright (C) 2002-2003 SAP AG

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end


*/

package com.sap.dbtech.procserver;

import java.net.*;
import java.io.*;
import com.sap.dbtech.util.*;
import com.sap.dbtech.rte.comm.RTEException;
import com.sap.dbtech.rte.comm.JdbcCommunication;

/**
 *
 */
public class SocketComm
    extends JdbcCommunication
{
    private Socket socket;
    private InputStream instream;
    private OutputStream outstream;
    private StructuredMem sendBuf;
    int packetSize;
    /**
     * creates a new SocketComm
     */
    public 
    SocketComm (
        int port,
        int packetSize)
    throws RTEException
    {
        try {
            this.socket = new Socket ("localhost", port);
            this.instream = this.socket.getInputStream();
            this.outstream = this.socket.getOutputStream();
        }
        catch (UnknownHostException uhExc) {
            throw new RTEException (uhExc.getMessage ());
        }
        catch (IOException ioExc) {
            throw new RTEException (ioExc.getMessage ());
        }
        this.packetSize = packetSize;
    }
    /**
     *
     */
    void 
    close ()
    {
        if (this.socket != null) {
            try {
                this.socket.close ();
            }
            catch (IOException ioExc) {
            }
            this.socket = null;
        }
    }
    
    /**
     *
     */
    public void 
    finalize ()
    {
        this.close ();
    }
    
    /**
     *
     */
    void 
    send (
        byte [] buf,
        int buflen)
    throws IOException
    {
        byte [] lenbuf = new byte [4];        
        
        Log.log ("send'ing " + buflen + " bytes");
        /*
         * send 4 byte length
         */
        if(buflen == 0) {
            lenbuf [0] = lenbuf [1] = lenbuf [2] = lenbuf [3] = 0;
            return;
        }
        else {
            for (int i = 3; i >= 0; --i) {
                lenbuf[i] = (byte) (buflen & 0xff);
                buflen >>= 8;
            }
        }
        this.outstream.write (lenbuf);
        /*
         * send real data
         */
        this.outstream.write (buf);
    }
    /**
     *
     */
    void 
    send (
        byte [] buf)
    throws IOException
    {
        this.send (buf, buf.length);
    }
    /**
     *
     */
    void 
    sendString (
        String text)
    throws IOException
     {
        this.send (text.getBytes ());
    }
    /**
     *
     */
    public byte [] 
    recv ()
    throws IOException
    {                
        /*
         * read length bytes
         */
        byte [] lenbuf = this.recvBytes (4);
        int bytesToRead = 0;
        
        for (int i = 0; i < 4; ++i) {
            int oneByte = lenbuf[i];
            if (oneByte < 0) {
                oneByte += 256;
            }
            bytesToRead = (bytesToRead * 256) + oneByte;
        }
        /*
         * read real data
         */
        byte [] result = this.recvBytes (bytesToRead);
        return result;
    }
    /**
     *
     */
    public String 
    recvString ()
    throws IOException
    {
        byte [] raw = this.recv ();
        return new String (raw);
    }
    /**
     *
     */
    private byte [] 
    recvBytes (
        int len)
    throws IOException
    {
        byte [] result = new byte [len];
        int pos = 0;
        
        while (pos < len) {
            pos += this.instream.read (result, pos, len - pos);
        }
        return result;
    }
    /**
     *
     */
    public void 
    cancel ()
    throws java.sql.SQLException
    {
    }
    /**
     * gets a new request packet.
     * @return StructuredMem
     */
    public StructuredMem getRequestPacket ()
    {
        StructuredMem result;
        if (this.sendBuf != null) {
            result = this.sendBuf;
            this.sendBuf = null;
        }
        else {
            result = new StructuredBytes (this.packetSize);
        }
        return result;
    }
    /**
     * test whether the connection is still valid.
     * @return boolean
     */
    public boolean isConnected ()
    {
        return this.socket != null;
    }
    /**
     * blocks while waiting for a reply
     * @return StructuredMem
     * @exception RTEException.
     */
    public StructuredMem receive () 
    throws RTEException
    {
        try {
            return new StructuredBytes (this.recv ());
        }
        catch (IOException exc) {
            throw new RTEException (exc.getMessage());
        }
    }
    /**
     * closes the connection.
     */
    public void release ()
    {
        this.close ();
    }
    /**
     * send a new request to the server.
     * @param userPacket StructuredMem
     * @param len int
     * @exception com.sap.dbtech.rte.comm.RTEException.
     */
    public void request (
        StructuredMem userPacket, 
        int len) 
    throws RTEException
    {
        this.sendBuf = userPacket;
        StructuredBytes sbytes = (StructuredBytes) userPacket;
        try {
            this.send (sbytes.bytes (), len);            
        }
        catch (IOException exc) {
            throw new RTEException (exc.getMessage());
        }
    }
}
