/// SocketMessageManager.java
// SocketMessageManager is a class for objects capable of managing
// communications with a message server.
package org.dyndns.fishyu.messenger.sockets.client;

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

import org.dyndns.fishyu.messenger.*;

public class SocketMessageManager implements MessageManager {   
   private SocketChannel socketChannel;
   private MessageListener messageListener;
   private String serverAddress;
   private ReceivingThread receiveMessage;
   private boolean connected;
   private Charset charSet = Charset.forName( "UTF-8" );
   private ByteBuffer writeBuffer;
   private ByteBuffer readBuffer = ByteBuffer.allocate( 512 );

   public SocketMessageManager( String host )
   {
      serverAddress = host;
      connected = false;
   }
   
   // connect to message server and start receiving message
   public void connect( MessageListener listener )
   {
      messageListener = listener;

      // connect to server and start thread to receive message
      try {

         // create SocketChannel to make connection to server
         socketChannel = SocketChannel.open();
         socketChannel.connect( new InetSocketAddress(
               InetAddress.getByName( serverAddress ), 12345 ) );

         // start ReceivingThread to receive messages sent by server
         receiveMessage = new ReceivingThread();
         receiveMessage.start();

         connected = true;
      }
	  catch ( Exception exception ) {
         exception.printStackTrace();
      }
   }
   
   // disconnect from message server and stop receiving message
   public void disconnect( MessageListener listener )
   {
      if ( connected ) {

         // send disconnect request and stop receiving
         try {
             
            //sendChannelMessage( "", "Disconnect" ,"" + 1 /*¥ý­°*/ , "#ChannelSend#" + "Disconnect" );

            connected = false;

            // send interrupt signal to receiving thread
            receiveMessage.interrupt();
         }
	     catch ( Exception exception ) {
            exception.printStackTrace();
         }
      }
   }
   
   // send message to message server
   public void sendPhotoMessage( String userName, int type, String code )
   {
   	    String message = userName + "" + type + "" + code;
   	    try {
         writeBuffer = charSet.encode( message );
         socketChannel.write( writeBuffer );
      }
      catch ( IOException ioException ) {
         ioException.printStackTrace();

         try {
            socketChannel.close();
         }
         catch ( IOException exception ) {
            exception.printStackTrace();
         }
      }

   } // end method sendPhotoMessage
   
   public void sendChannelMessage( String userName, String messageBody, String ChannelAndChannelSendCode ) 
   {
      String message = userName + messageBody + ChannelAndChannelSendCode;
 								  
      // send message to server
      try {
         writeBuffer = charSet.encode( message );
         socketChannel.write( writeBuffer );
      }
      catch ( IOException ioException ) {
         ioException.printStackTrace();

         try {
            socketChannel.close();
         }
         catch ( IOException exception ) {
            exception.printStackTrace();
         }
      }

   } // end method sendChannelMessage
   
   public void sendCommand( String command )
   {
   	  try 
   	  {
          writeBuffer = charSet.encode( command  );
          socketChannel.write( writeBuffer );
      }
      catch ( IOException ioException ) {
         ioException.printStackTrace();

         try {
            socketChannel.close();
         }
         catch ( IOException exception ) {
            exception.printStackTrace();
         }
      }
   }
   
   public void sendMessage( int infoStyle, String info )
   {
       String stringToWrite = "";
      // send message to server
      try {
          
          switch ( infoStyle )
          {
              case 1:
                  stringToWrite = "|*?+CaSe_1" + info; // add userlist
                  break;
              case 2:
                  stringToWrite = "|*?+CaSe_2" + info; // del userlist
                  break;
              case 3:
                  stringToWrite = "|*?+CaSe_3" + info; // 
                  break;
              case 4:
                  stringToWrite = "|*?+CaSe_4" + info;
                  break;
              default:
                  break;
          }
          writeBuffer = charSet.encode( stringToWrite );
         socketChannel.write( writeBuffer );
      }
      catch ( IOException ioException ) {
         ioException.printStackTrace();

         try {
            socketChannel.close();
         }
         catch ( IOException exception ) {
            exception.printStackTrace();
         }
      }

   } // end method sendInfoMessage
   
      public void sendPrivateMessage( String from, String to, String message, String PriSendCode )
   {
       String stringToWrite = from + to + message + PriSendCode; // PriSendCode = '#PriSend#"
      // send message to server
      try {
          
 
          writeBuffer = charSet.encode( stringToWrite );
         socketChannel.write( writeBuffer );
         
      }
      catch ( IOException ioException ) {
         ioException.printStackTrace();

         try {
            socketChannel.close();
         }
         catch ( IOException exception ) {
            exception.printStackTrace();
         }
      }

   } // end method sendMessage PriSend
   
   

   public class ReceivingThread extends Thread 
   {
      public void run() 
      {
         int messageLength = 0;
         String message = "";

         // read messages until server close the connection
         try {

            // process messages sent from server
            while ( true )
            {
               readBuffer.clear();
               socketChannel.read( readBuffer );
               readBuffer.flip();
               CharBuffer charMessage = charSet.decode( readBuffer );
               message = charMessage.toString().trim();

               if( message.indexOf( "|*?+CaSe_1" ) >= 0 || message.indexOf( "|*?+CaSe_2" ) >= 0 )
               {
                   messageListener.UserlistMessageReceived( message );
               }
               
               if( message.indexOf( "#ChannelSend#" ) >= 0 )
               {
               	   int code = message.indexOf( "#ChannelSend#" );
               	   StringTokenizer tokenizer = 
                      new StringTokenizer( message, "`" );
                   messageListener.ChannelMessageReceived( tokenizer.nextToken(),  
                         tokenizer.nextToken(), message.charAt( code - 1 ) );
               }
               
               if( message.indexOf( "#PriSend#" ) >= 0 )
               {
                   // tokenize message to retrieve user name and message body
                   StringTokenizer tokenizer = 
                      new StringTokenizer( message, "`" );
                      messageListener.PriMessageReceived( 
                         tokenizer.nextToken(),   // from
                         tokenizer.nextToken(),   // to
                         tokenizer.nextToken() ); // message body
               }
                                            
               if( message.indexOf( "#ChannelSendConnectMode#" ) >= 0 || 
                         message.indexOf( "#ChannelSendDisconnectMode#" ) >= 0 )
               {
               	System.out.println( "\n" + message + "received" );
                      messageListener.ChannelUserlistReceived( message );
               }
               
               if( message.indexOf( "#never#" ) >= 0 )
               {
               	   System.out.println( "\n" + message + "received" );
               	   messageListener.killMessageReceived( message );
               }
               
               if( message.indexOf( "#SET_PHOTO#" ) >= 0 )
               {
               	   System.out.println( "\n" + message + "received" );
               	   messageListener.photoMessageReceived( message );
               }
              

            }   // keep receiving messages

         } // end try

         // catch problems reading from server
         catch ( IOException ioException ) {
            if ( ioException instanceof ClosedByInterruptException )
               System.out.println( "socket channel closed" );
            else {
               ioException.printStackTrace();

               try {
                  socketChannel.close();
                  System.out.println( "socket channel closed" );
               }
               catch ( IOException exception ) {
                  exception.printStackTrace();
               }
            }

         } // end catch

      } // end method run

   } // end inner class ReceivingThread

} // end class SocketMessageManager2



