/**
 * @author cramakrishnan
 *
 * Copyright (C) 2004, C. Ramakrishnan / Illposed Software
 * All rights reserved.
 * 
 * See license.txt (or license.rtf) for license information.
 * 
 * 
 * OSCPortIn is the class that listens for OSC messages.
 *     
 * To receive OSC, you need to construct the OSCPort with a 
 *
 * An example based on com.illposed.osc.test.OSCPortTest::testReceiving() :
 
        receiver = new OSCPort(OSCPort.defaultSCOSCPort());
        OSCListener listener = new OSCListener() {
            public void acceptMessage(java.util.Date time, OSCMessage message) {
                System.out.println("Message received!");
            }
        };
        receiver.addListener("/message/receiving", listener);
        receiver.startListening();
        
 * Then, using a program such as SuperCollider or sendOSC, send a message
 * to this computer, port 57110 (defaultSCOSCPort), with the address /message/receiving
 */

package com.illposed.osc;

import java.net.*;
import java.io.IOException;
import com.illposed.osc.utility.OSCByteArrayToJavaConverter;
import com.illposed.osc.utility.OSCPacketDispatcher;

public class OSCPortIn extends OSCPort implements Runnable {

    // state for listening
    protected boolean isListening;
    protected OSCByteArrayToJavaConverter converter = new OSCByteArrayToJavaConverter();
    protected OSCPacketDispatcher dispatcher = new OSCPacketDispatcher();
    
    /**
     * Create an OSCPort that listens on port
     * @param port
     * @throws SocketException
     */
    public OSCPortIn(int port) throws SocketException {
        socket = new DatagramSocket(port);
        this.port = port;
    }

    /**
     * @see java.lang.Runnable#run()
     */
    public void run() {
        //maximum UDP packet size
        byte[] buffer = new byte[65536];
        DatagramPacket packet = new DatagramPacket(buffer, 65536);
        while (isListening) {
            try {
                packet.setLength(65536);
                socket.receive(packet);
                OSCPacket oscPacket = converter.convert(buffer, packet.getLength());
                dispatcher.dispatchPacket(oscPacket);
            } catch (java.net.SocketException e) {
                if (isListening) e.printStackTrace();
            } catch (IOException e) {
                if (isListening) e.printStackTrace();
            } 
        }
    }
    
    /**
     * Start listening for incoming OSCPackets
     */
    public void startListening() {
        isListening = true;
        Thread thread = new Thread(this);
        thread.start();
    }
    
    /**
     * Stop listening for incoming OSCPackets
     */
    public void stopListening() {
        isListening = false;
    }
    
    /**
     * Am I listening for packets?
     */
    public boolean isListening() {
        return isListening;
    }
    
    /**
     * Register the listener for incoming OSCPackets addressed to an Address
     * @param anAddress  the address to listen for
     * @param listener   the object to invoke when a message comes in
     */
    public void addListener(String anAddress, OSCListener listener) {
        dispatcher.addListener(anAddress, listener);
    }
    
    /**
     * Close the socket and free-up resources. It's recommended that clients call
     * this when they are done with the port.
     */
    public void close() {
        socket.close();
    }

}
