
// ClientInfo.java
// Andrew Davison, April 2005, ad@fivedots.coe.psu.ac.th

/* Podrobné údaje o jediném klientovi a metody pro jejich získání
   a odesílání řetězců tomuto klientovi.

   Protože vstup klienta je neblokující, neznamená příchod dat vždy
   doručení kompletní zprávy.
  
   Postupující zprává je udržována v objektu inBuffer dokud není
   detekován znak '\n', načež se vrátí kompletní řetězec.
*/


import java.io.*;
import java.net.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;
// import java.util.*;


public class ClientInfo
{
  private static final int BUFSIZ = 1024;  // max. velikost zprávy

  private SocketChannel channel;
  private SelectScoreServer ss;
  private ByteBuffer inBuffer;

  private Charset charset;     // pro dekódování bajtů --> řetězec
  private CharsetDecoder decoder;


  public ClientInfo(SocketChannel chan, SelectScoreServer ss)
  {
    channel = chan;
    this.ss = ss;
    inBuffer = ByteBuffer.allocateDirect(BUFSIZ);
    inBuffer.clear();

    charset = Charset.forName("ISO-8859-1");
    decoder = charset.newDecoder();

    showClientDetails();
  } // konec metody: ClientInfo()



  private void showClientDetails()
  // zobrazí údaje o klientovi. dále se nepoužívá
  {
    Socket sock = channel.socket();
    InetAddress iaddr = sock.getInetAddress();
    System.out.println("Adresa klienta: " + iaddr.getHostAddress() );
    System.out.println("Jméno klienta: " + iaddr.getHostName() );
    System.out.println("Port klienta: " + sock.getPort() );
  }  // konec metody: showClientDetails()


  public void closeDown()
  {
    try {
      channel.close();
    }
    catch(IOException e)
    { System.out.println(e); }
  }



  public String readMessage()
  /* Volá se, když čakjí nějaké bajty na přečtení, ovšem 
     nemusí se ještě jednat o kompletní zprávu.
     Zpráva je uložena do objektu inBuffer dokud není detekován
     znak '\n'.
  */
  { 
    String inputMsg = null;
    try {
      int numBytesRead = channel.read(inBuffer);
      if (numBytesRead == -1) {     // kanál je pryč
        channel.close();
        ss.removeChannel(channel); // oznam objektu typu SelectScoreServer
      }
      else
        inputMsg = getMessage(inBuffer);
    }
    catch (IOException e)
    {  System.out.println("rm: " + e); 
       ss.removeChannel(channel); // oznam objektu typu SelectScoreServer
    }

    return inputMsg;
  }  // konec metody: readMessage()



  private String getMessage(ByteBuffer buf)
  {
    String msg = null;
    int posn = buf.position();   // aktuální velikost bufferu
    int limit = buf.limit();
    // System.out.println("Position: " + posn + ";  limit: " + limit);

    buf.position(0);    // nastav rozsah bajtů v bufferu pro překlad
    buf.limit(posn);
    try {
      CharBuffer cb = decoder.decode(buf);
      msg = cb.toString();
    }
    catch(CharacterCodingException cce)
    { System.out.println( cce );  }

    System.out.println("Aktuální zpráva: " + msg);
    buf.limit(limit);    // vynulujuj buffer na plný rozsah bajtů
    buf.position(posn);
    
    if (msg.endsWith("\n")) {    // předpokládáme, že '\n' je posledním znakem
      buf.clear();
      return msg;
    }
    return null;
  }  // konec metody: getMessage()



  public boolean sendMessage(String msg)
  {
    String fullMsg = msg + "\r\n";

    ByteBuffer outBuffer = ByteBuffer.allocateDirect(BUFSIZ);
    outBuffer.clear();
    outBuffer.put( fullMsg.getBytes() );
    outBuffer.flip();

    boolean msgSent = false;
    try {
      // odešli data, nepředpokládej, že se pošlou všechna naráz
      while( outBuffer.hasRemaining() )
        channel.write(outBuffer);
      msgSent = true;
    }
    catch(IOException e)
    { System.out.println(e);  
      ss.removeChannel(channel); // oznam objektu typu SelectScoreServer
    }
    
    return msgSent;
  }  // konec metody: sendMessage()


}  // konec třídy: ClientInfo

