/*=====================================================================*/
/*    .../prgm/project/bigloo/runtime/Jlib/input_socket_port.java      */
/*    -------------------------------------------------------------    */
/*    Author      :  Manuel Serrano                                    */
/*    Creation    :  Tue Dec  5 11:53:13 2000                          */
/*    Last change :  Tue Nov  6 10:09:46 2001 (serrano)                */
/*    Copyright   :  2000-01 Manuel Serrano                            */
/*    -------------------------------------------------------------    */
/*    JVM Socket input ports implementation.                           */
/*=====================================================================*/
using System;
using System.Net.Sockets;
using System.IO;

namespace bigloo
{
  /*---------------------------------------------------------------------*/
  /*    INPUT_SOCKET_PORT                                                */
  /*---------------------------------------------------------------------*/
  public sealed class input_socket_port: input_port 
  {
    /*--- private fields --------------------------------------------------*/
    private readonly Socket _socket;

    /*--- constructors ----------------------------------------------------*/
    public input_socket_port( Socket  _socket,
                              bool    b )
      : base( "[socket]", (b ? (int)bigloo.foreign.default_io_bufsiz : 1) )
    {
      this._socket= _socket;
    }

    /*--- public methods --------------------------------------------------*/
    public override void close()
    {
      eof= true;
      buffer= null;
      _socket.Close();
    }

    public override bool rgc_charready() 
    {
      try
      { 
        return (0 < _socket.Available);
      } 
      catch (Exception)
      {
        return false;
      }
    }

    public override bool rgc_fill_buffer()
    {
      int          bufsize= this.bufsiz;
      int          abufsize= this.abufsiz;
      int          matchstart= this.matchstart;

      // if the buffer is not full, we fill it
      if (abufsize < bufsize)
        return rgc_size_fill_con_buffer( abufsize, bufsize-abufsize );

      if (0 < matchstart) 
      {
        // we shift the buffer left and we fill the buffer
        byte[]     buffer= this.buffer;
        int        movesize= abufsize-matchstart;

        for ( int i= 0 ; i < movesize ; ++i)
          buffer[i]= buffer[matchstart + i];
        abufsize -= matchstart;
        this.matchstart= 0;
        this.matchstop-= matchstart;
        this.forward-= matchstart;
        this.lastchar= buffer[matchstart-1];

        return rgc_size_fill_con_buffer( abufsize, bufsize-abufsize );
      }

      // we current token is too large for the buffer
      // we have to enlarge it.                      
      rgc_double_buffer();

      return rgc_fill_buffer();
    }
    
    bool rgc_size_fill_con_buffer( int  abufsize,
                                   int  size )
    {
      // we start reading at ABUFSIZE - 1 because we have
      // to remove the '\0' sentinel that ends the buffer
      byte[]       buffer= this.buffer;
      int          nbread= _socket.Receive( buffer, abufsize-1, size, SocketFlags.None );

      if (nbread == 0)
        eof= true;
      else
        abufsize+= nbread;

      buffer[abufsize-1]= (byte)'\0';
      this.abufsiz= abufsize;

      return (0 < abufsiz);
    }
  }
}
