/*
 * Copyright (C) 2005 Luca Veltri - University of Parma - Italy
 * 
 * This file is part of MjSip (http://www.mjsip.org)
 * 
 * MjSip 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.
 * 
 * MjSip 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 MjSip; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * 
 * Author(s):
 * Luca Veltri (luca.veltri@unipr.it)
 */

package org.zoolu.net;


import java.io.IOException;
import java.io.InterruptedIOException;


/** UdpProvider provides an UDP send/receive service.
  * On the receiver side it waits for UDP datagrams and passes them
  * to the UdpProviderListener.
  * <p> If the attribute <i>alive_time</i> has a non-zero value, the UdpProvider stops
  * after <i>alive_time</i> milliseconds of inactivity.
  * <p> When a new packet is received, the onReceivedPacket(UdpProvider,DatagramPacket)
  * method is fired.
  * <p> Method onServiceTerminated(UdpProvider) is fired when the the UdpProvider stops 
  * receiving packets.
  */
public class UdpProvider extends Thread
{
   /** The reading buffer size */
   public static final int BUFFER_SIZE=65535;
     
   /** Default value for the maximum time that the UDP receiver can remain active after been halted (in milliseconds) */
   public static final int DEFAULT_SOCKET_TIMEOUT=2000; // 2sec 

   /** UDP socket */
   UdpSocket socket;  

   /** Maximum time that the UDP receiver can remain active after been halted (in milliseconds) */
   int socket_timeout;

   /** Maximum time that the UDP receiver remains active without receiving UDP datagrams (in milliseconds) */
   long alive_time; 

   /** Minimum size for received packets. Shorter packets are silently discarded. */
   int minimum_length; 

   /** Whether it has been halted */
   boolean stop; 

   /** Whether it is running */
   boolean is_running; 

   /** UdpProvider listener */
   UdpProviderListener listener;   

       
   /** Creates a new UdpProvider */ 
   public UdpProvider(UdpSocket socket, UdpProviderListener listener)
   {  init(socket,0,listener);
      start();
   }


   /** Creates a new UdpProvider */ 
   public UdpProvider(UdpSocket socket, long alive_time, UdpProviderListener listener)
   {  init(socket,alive_time,listener);
      start();
   }


   /** Inits the UdpProvider */ 
   private void init(UdpSocket socket, long alive_time, UdpProviderListener listener)
   {  this.listener=listener;
      this.socket=socket;
      this.socket_timeout=DEFAULT_SOCKET_TIMEOUT;
      this.alive_time=alive_time;
      this.minimum_length=0; 
      this.stop=false; 
      this.is_running=true; 
   }


   /** Gets the UdpSocket */ 
   public UdpSocket getUdpSocket()
   {  return socket;
   }


   /** Sets a new UdpSocket */ 
   /*public void setUdpSocket(UdpSocket socket)
   {  this.socket=socket;
   }*/


   /** Whether the service is running */
   public boolean isRunning()
   {  return is_running;
   }


   /** Sets the maximum time that the UDP service can remain active after been halted */
   public void setSoTimeout(int timeout)
   {  socket_timeout=timeout;
   }


   /** Gets the maximum time that the UDP service can remain active after been halted */
   public int getSoTimeout()
   {  return socket_timeout;
   }


   /** Sets the minimum size for received packets.
     * Packets shorter than that are silently discarded. */
   public void setMinimumReceivedDataLength(int len)
   {  minimum_length=len;
   }


   /** Gets the minimum size for received packets.
     * Packets shorter than that are silently discarded. */
   public int getMinimumReceivedDataLength()
   {  return minimum_length;
   }


   /** Sends a UdpPacket */      
   public void send(UdpPacket packet) throws IOException
   {  if (!stop) socket.send(packet);
   }


   /** Stops running */
   public void halt()
   {  stop=true;
   }


   /** The main thread */
   public void run()
   {  
      byte[] buf=new byte[BUFFER_SIZE];
      UdpPacket packet=new UdpPacket(buf, buf.length);
               
      Exception error=null;
      long expire=0;
      if (alive_time>0) expire=System.currentTimeMillis()+alive_time;
      try   
      {  socket.setSoTimeout(socket_timeout);
         // loop
         while(!stop)
         {  try
            {  socket.receive(packet);           
            }
            catch (InterruptedIOException ie)
            {  if (alive_time>0 && System.currentTimeMillis()>expire) halt();
               continue;
            }
            if (packet.getLength()>=minimum_length)
            {  if (listener!=null) listener.onReceivedPacket(this,packet);
               if (alive_time>0) expire=System.currentTimeMillis()+alive_time;
            }
            packet=new UdpPacket(buf, buf.length);
         }
      }
      catch (Exception e)
      {  error=e;
         stop=true;
      } 
      is_running=false;
      if (listener!=null) listener.onServiceTerminated(this,error);
      listener=null;
   }

   
   /** Gets a String representation of the Object */
   public String toString()
   {  return "udp:"+socket.getLocalAddress()+":"+socket.getLocalPort();
   }

}
