//  ------------------------------------------------------------------------
//
//  Copyright (C) 2012 Fons Adriaensen <fons@linuxaudio.org>
//
//  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 3 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, see <http://www.gnu.org/licenses/>.
//
//  ------------------------------------------------------------------------


#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
#include <ctype.h>
#include <sys/mman.h>
#include <clthreads.h>
#include "jclient.h"


static const char   *clopt = "hN:s:";
static const char   *N_val = "zita-lrx";
static const char   *s_val = 0;


static void help (void)
{
    fprintf (stderr, "\nzita-lrx-%s\n\n", VERSION);
    fprintf (stderr, "(C) 2012 Fons Adriaensen  <fons@linuxaudio.org>\n\n");
    fprintf (stderr, "Usage: zita-lrx <options> <config file>\n");
    fprintf (stderr, "Options:\n");
    fprintf (stderr, "  -h                 Display this text\n");
    fprintf (stderr, "  -N <name>          Name to use as JACK client [zita-lrx]\n");   
    fprintf (stderr, "  -s <server>        Jack server name\n");
    exit (1);
}


static void procoptions (int ac, char *av [], const char *where)
{
    int k;
    
    optind = 1;
    opterr = 0;
    while ((k = getopt (ac, av, (char *) clopt)) != -1)
    {
        if (optarg && (*optarg == '-'))
        {
            fprintf (stderr, "\n%s\n", where);
	    fprintf (stderr, "  Missing argument for '-%c' option.\n", k); 
            fprintf (stderr, "  Use '-h' to see all options.\n");
            exit (1);
        }
	switch (k)
	{
        case 'h' : help (); exit (0);
        case 'N' : N_val = optarg; break; 
        case 's' : s_val = optarg; break; 
        case '?':
            fprintf (stderr, "\n%s\n", where);
            if (optopt != ':' && strchr (clopt, optopt))
	    {
                fprintf (stderr, "  Missing argument for '-%c' option.\n", optopt); 
	    }
            else if (isprint (optopt))
	    {
                fprintf (stderr, "  Unknown option '-%c'.\n", optopt);
	    }
            else
	    {
                fprintf (stderr, "  Unknown option character '0x%02x'.\n", optopt & 255);
	    }
            fprintf (stderr, "  Use '-h' to see all options.\n");
            exit (1);
        default:
            abort ();
 	}
    }
}


static Jclient   *jclient = 0;
static ITC_ctrl   itcctrl;
static bool       stop = false;


static void sigint_handler (int)
{
    signal (SIGINT, SIG_IGN);
    stop = true;
}


static void syncjack (int ev)
{
    itcctrl.send_event (ev, 1);
    itcctrl.get_event (1 << ev);
}


int main (int ac, char *av [])
{
    int      ev;
    Lrxconf  conf;

    procoptions (ac, av, "On command line:");
    if (ac <= optind) help ();

    if (conf.load (av [optind]))
    {
        fprintf (stderr, "Can't load configuration '%s'\n", av [optind]);
	return 1;
    }

    jclient = new Jclient (N_val, s_val);
    if (conf.check (jclient->fsamp ()))
    {
	delete jclient;
	return 1;
    }

    ITC_ctrl::connect (&itcctrl, EV_GO_BYPASS,  jclient,  EV_GO_BYPASS);
    ITC_ctrl::connect (&itcctrl, EV_GO_SILENCE, jclient,  EV_GO_SILENCE);
    ITC_ctrl::connect (&itcctrl, EV_GO_PROCESS, jclient,  EV_GO_PROCESS);
    ITC_ctrl::connect (jclient,  EV_GO_BYPASS,  &itcctrl, EV_GO_BYPASS);
    ITC_ctrl::connect (jclient,  EV_GO_SILENCE, &itcctrl, EV_GO_SILENCE);
    ITC_ctrl::connect (jclient,  EV_GO_PROCESS, &itcctrl, EV_GO_PROCESS);
    ITC_ctrl::connect (jclient,  EV_SHUTDOWN,   &itcctrl, EV_SHUTDOWN);

    if (mlockall (MCL_CURRENT | MCL_FUTURE)) fprintf (stderr, "Warning: memory lock failed.\n");
    signal (SIGINT, sigint_handler); 

    jclient->init_lrxproc (&conf);
    jclient->create_inpports (&conf);
    jclient->create_outports (&conf);
    syncjack (EV_GO_SILENCE);
    jclient->connect_outports (&conf);
    syncjack (EV_GO_PROCESS);

    itcctrl.set_time (0);
    itcctrl.inc_time (250000);
    while (! stop)
    {
	ev = itcctrl.get_event_timed ();
	switch (ev)
        {
	case Esync::EV_TIME:
	    itcctrl.inc_time (250000);
	    break;
	case EV_SHUTDOWN:
	    printf ("Kicked out by jack server !\n");
	    delete jclient;
	    return 1;
	}
    }

    syncjack (EV_GO_SILENCE);
    jclient->disconn_outports ();
    delete jclient;
   
    return 0;
}
