#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# The Purity library for Pure Data dynamic patching.
#
# Copyright 2009 Alexandre Quessy
# <alexandre@quessy.net>
# http://alexandre.quessy.net
#
# Purity 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 3 of the License, or
# (at your option) any later version.
#
# Purity 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 Purity.  If not, see <http://www.gnu.org/licenses/>.
#
"""
Simpler example FUDI sender.

TODO: port 5400 + n
"""
import random
import time
import os
from twisted.internet import reactor
from optparse import OptionParser
from rats import fudi
from rats.purity import obj
from rats.purity import client
from rats.purity import server

RUNNING = True

def clear_all(purityclient):
    purityclient.send_message("pd-main", "clear")

def metro_patch(purityclient):
    """
    [r startme] --> [tgl] --> [metro 500] --> [bng]
    """
    main = obj.get_main_patch()
    # subpatch
    patch = main.subpatch("metropatch")
    # objects
    r = patch.receive("startme")
    tgl = patch.obj("tgl")
    metro = patch.obj("metro", 500)
    bang = patch.obj("bng")
    # connections
    patch.connect(r, 0, tgl, 0)
    patch.connect(tgl, 0, metro, 0)
    patch.connect(metro, 0, bang, 0)
    # send messages
    mess_list = main.get_fudi() # list of (fudi) lists
    # print(mess_list)
    for mess in mess_list:
        purityclient.send_message(*mess)
    print "sent FUDI message:", "startme", 1
    purityclient.send_message("startme", 1)

def audio_patch(purityclient):
    """
    [r sine] --> [line~] --> [osc~] --> [*~ 0.25] ==> [dac~]
    """
    main = obj.get_main_patch()
    patch = main.subpatch("sinepatch")
    # objects
    r = patch.receive("sine")
    line = patch.obj("line~")
    osc = patch.obj("osc~", 440)
    mult = patch.obj("*~", 0.125)
    dac = patch.obj("dac~", 1, 2)
    # connections
    patch.connect(r, 0, line, 0)
    patch.connect(line, 0, osc, 0)
    patch.connect(osc, 0, mult, 0)
    patch.connect(mult, 0, dac, 0)
    patch.connect(mult, 0, dac, 1) # stereo
    # todo later:
    def start_audio(purityclient):
        purityclient.send_message("pd", "dsp", 1)
    def send_random_note(purityclient, send_random_note):
        global RUNNING
        note = random.randint(220, 880)
        delay = 500
        purityclient.send_message("sine", note, delay) # ms
        if RUNNING:
            reactor.callLater(delay / 1000., send_random_note, purityclient, send_random_note)
    # send messages
    mess_list = main.get_fudi() # list of (fudi) lists
    # print(mess_list)
    for mess in mess_list:
        purityclient.send_message(*mess)
    reactor.callLater(0.1, start_audio, purityclient)
    reactor.callLater(0.1, send_random_note, purityclient, send_random_note)

def stop_all(purityclient):
    print "stopping"
    mess = ["pd", "quit"]
    purityclient.send_message(*mess)
    reactor.stop()


if __name__ == "__main__":        
    parser = OptionParser(usage="%prog options message...")
    parser.add_option("-s", "--send-port", type="int", \
        help="FUDI Send port.", default=17777)
    parser.add_option("-r", "--receive-port", type="int", \
        help="FUDI Receive port.", default=15555)
    parser.add_option("-t", "--tcp", action="store_true", \
        help="Uses TCP instead of UDP.")
    parser.add_option("-v", "--verbose", action="store_true", \
        help="Sets the output to verbose.")
    parser.add_option("-q", "--quit", action="store_true", \
        help="Quits right after sending message.")
    (options, args) = parser.parse_args()
    use_tcp = not options.tcp
    fudi.VERBOSE = options.verbose

    pid = server.fork_and_start_pd()
    if pid != 0:
        time.sleep(1.0) # Wait until pd is ready. #TODO: use netsend instead.
        purityclient = client.PurityClient(
            receive_port=options.receive_port, 
            send_port=options.send_port, 
            quit=options.quit, 
            use_tcp=True) # create the client
        deferred = purityclient.client_start() # start it
        # examples of what one can do:
        reactor.callLater(0.01, clear_all, purityclient)
        reactor.callLater(0.2, metro_patch, purityclient)
        reactor.callLater(0.3, audio_patch, purityclient)
        # reactor.callLater(10, stop_all, purityclient)
        # print "will stop in 10 seconds"
        try:
            reactor.run()
        except KeyboardInterrupt, e:
            print "quit"

