#!/usr/bin/env python
#
#   Copyright (C) 2006 by Patrick Stinson and Jonathan Saggau             
#   patrickkidd@gmail.com   saggau@gmail.com                              
#                                                                         
#   This program 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.                                   
#                                                                         
#   This program 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 this program; if not, write to the                         
#   Free Software Foundation, Inc.,                                       
#   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.  
#
 
"""
Control an sc server.
"""
 
import time
import socket
import Queue
import tools
import listener
 
 
class Controller:
    """ Communicates to an osc server.
    Refer to the OSC spec for method arguments.
 
    NOTE: A method like quitServer() that sends /quit should go in a
    'convenience' class, as this class focuses exclusively on
    primitive communication.
    """
 
    _timeout = 2
 
    def __init__(self, addr, verbose=True, spew=False):
        self.serverip, self.serverport = addr
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.socket.settimeout(self._timeout)
 
        self.incoming = Queue.Queue()
        self.listener = listener.Listener(self.socket)
        self.listener.register(None, self.incoming.put)
        if verbose:
            self.listener.register(None, tools.print_message)
        self.listener.start()
        self.spew = spew
 
    def __del__(self):
        self.listener.quit(wait=True)
 
    def _send(self, bin):
        self.socket.sendto(bin, (self.serverip, self.serverport))
 
    def sendMsg(self, *args):
        if self.spew:
            print args
        oscmessage = tools.OSCMessage()
        for arg in args:
            oscmessage.append(arg)
        self._send(oscmessage.getBinary())
 
    def sendBundle(self, fromnow, messages):
        if self.spew:
            print 'bundle:', fromnow
            for msg in messages:
                print '   ', tuple(msg)
        self.sendBundleAbs(time.time() + fromnow, messages)
 
    def sendBundleAbs(self, abs, messages):
        if self.spew:
            print 'bundle', abs
            for msg in messages:
                print '   ',tuple(msg)
        bin = tools.build_bundle(abs, messages)
        self._send(bin)
 
    def receive(self, *keys):
        """ Return the first message, or the first message that
        matches a key in keys.
 
        Should old messages expire and be removed somehow to avoid
        excessive cleanup here?
        """
        while True:
            try:
                msg = self.incoming.get(timeout=self._timeout)
                if not keys or msg[0] in keys:
                    return msg
            except Queue.Empty, e:
                raise IOError('timeout waiting for reply')