//  ------------------------------------------------------------------------
//
//  Copyright (C) 2011-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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <time.h>
#include "lrxconf.h"
#include "sstring.h"


Channel::Channel (void)
{
    *_label = 0;
    _gain  = 0;
    _delay = 0;
    for (int j = 0; j < MAXBAND; j++) _dest [j] = 0;
}


Channel::~Channel (void)
{
    for (int j = 0; j < MAXBAND; j++) free (_dest [j]);
}


Lrxconf::Lrxconf (void) :
    _chann (0)
{
    reset ();
}


Lrxconf::~Lrxconf (void)
{
    reset ();
}


void Lrxconf::reset (void)
{
    *_filename = 0;
    _nband = 0;
    _nchan = 0;
    delete[] _chann;
    _chann = 0;
}


void Lrxconf::init (int nchan, int nband)
{
    int j;

    _nchan = nchan;
    _nband = nband;
    _chann = new Channel [nchan];
    for (j = 0; j < nchan; j++)
    {
	sprintf (_chann [j]._label, "%d", j + 1);
    }
    for (j = 0; j < MAXBAND; j++)
    {
	sprintf (_fband [j]._label, "%d", j + 1);
	_fband [j]._gain = 0;
	_fband [j]._delay = 0;
    }
    for (j = 0; j < MAXFILT; j++)
    {
	_xover [j]._freq = 0;
	_xover [j]._shape = -6.0f;
    }
}

/*
int Lrxconf::save (const char *file)
{
    FILE          *F;
    char          *p;

    strcpy (_filename, file);
    p = strrchr (_filename, '.');
    if (!p) strcat (_filename, ".zlrx");
    if (! (F = fopen (_filename, "w"))) 
    {
	fprintf (stderr, "Can't open '%s' for writing.\n", _filename);
        return 1;
    } 

    fclose (F);
    return 0;
}
*/

int Lrxconf::load (const char *file)
{
    FILE          *F;
    char          *p, *q;
    char          buff [1024];
    int           line, stat, n;
    int           i1, i2;
    float         f1;
    char          s1 [64];

    strcpy (_filename, file);
    p = strrchr (_filename, '.');
    if (!p) strcat (_filename, ".zlrx");
    if (! (F = fopen (_filename, "r"))) 
    {
	fprintf (stderr, "Can't open '%s' for reading.\n", _filename);
        return 1;
    } 

    reset ();
    stat = 0;
    line = 0;
    while (! stat && fgets (buff, 1024, F))
    {
        line++;
        p = buff; 
        while (isspace (*p)) p++;
        if (*p == '#' || *p < ' ') continue;
        q = p;
        while ((*q >= ' ') && !isspace (*q)) q++;
        *q++ = 0;   
        while ((*q >= ' ') && isspace (*q)) q++;

        stat = NOERR;  
        if (!strcmp (p, "/zita-lrx"))
	{
	    if (_nband || _nchan) stat = SCOPE;
	    if (sscanf (q, "%d%d%n", &i1, &i2, &n) != 2) stat = ARGS;
	    else
	    {
		q += n;
		if ((i1 < 1) && (i1 > 16))
		{
		    fprintf (stderr, "Line %d: number of channels (%d) is out of range.\n", line, i1);
		    stat = ERROR;
		}
		else if ((i2 < 2) && (i2 > 4))
		{
		    fprintf (stderr, "Line %d: number of bands (%d) is out of range.\n", line, i1);
		    stat = ERROR;
		}
		else init (i1, i2);
	    }
	}
        else if (!strcmp (p, "/chann/label"))
	{
	    if (!_nchan) stat = SCOPE;
	    else if (sscanf (q, "%d%s%n", &i1, s1, &n) != 2) stat = ARGS;
	    else
	    {
		q += n;
		if ((i1 < 1) || (i1 > _nchan))
		{
		    fprintf (stderr, "Line %d: channel index (%d) is out of range.\n", line, i1);
		    stat = ERROR;
		}
		else if (strlen (s1) > 15)
		{
		    fprintf (stderr, "line %d: channel label (%s) is too long.\n", line, s1);
		    stat = ERROR;
		}
		else strcpy (_chann [i1 - 1]._label, s1);
	    }
	}
        else if (!strcmp (p, "/chann/gain"))
	{
	    if (!_nchan) stat = SCOPE;
	    else if (sscanf (q, "%d%f%n", &i1, &f1, &n) != 2) stat = ARGS;
	    else
	    {
	        q += n;
                if ((i1 < 1) || (i1 > _nchan))
	        {
	            fprintf (stderr, "Line %d: channel index (%d) is out of range.\n", line, i1);
	            stat = ERROR;
	        }
	        else if ((f1 < -30.0f) || (f1 > 10.0f))
	        {
	            fprintf (stderr, "Line %d: gain (%3.1lf) is out of range.\n", line, f1);
	            stat = ERROR;
	        }
	        else _chann [i1 - 1]._gain = f1;
	    }
	}
        else if (!strcmp (p, "/chann/delay"))
	{
	    if (!_nchan) stat = SCOPE;
	    else if (sscanf (q, "%d%f%n", &i1, &f1, &n) != 2) stat = ARGS;
	    else
	    {
	        q += n;
                if ((i1 < 1) || (i1 > _nchan))
	        {
	            fprintf (stderr, "Line %d: channel index (%d) is out of range.\n", line, i1);
	            stat = ERROR;
	        }
	        else if ((f1 < 0) || (f1 > 30.0f))
	        {
	            fprintf (stderr, "Line %d: delay (%4.2lf) is out of range.\n", line, f1);
	            stat = ERROR;
	        }
	        else _chann [i1 - 1]._delay = f1;
	    }
	}
        else if (!strcmp (p, "/chann/connect"))
	{
	    if (!_nchan) stat = SCOPE;
	    else if (sscanf (q, "%d%d%n", &i1, &i2, &n) != 2) stat = ARGS;
	    else
	    {
		q += n;
		if ((i1 < 1) || (i1 > _nchan))
		{
		    fprintf (stderr, "Line %d: channel index (%d) is out of range.\n", line, i1);
		    stat = ERROR;
		}
		else if ((i2 < 1) || (i2 > _nband))
		{
		    fprintf (stderr, "Line %d: fband index (%d) is out of range.\n", line, i1);
		    stat = ERROR;
		}
		else
		{
		    n = sstring (q, s1, 64);
		    if (n > 0) _chann [i1 - 1]._dest [i2 - 1] = strdup (s1);
		    q += n;
		}
	    }
	}
        else if (!strcmp (p, "/fband/suffix"))
	{
	    if (!_nband) stat = SCOPE;
	    else if (sscanf (q, "%d%s%n", &i1, s1, &n) != 2) stat = ARGS;
	    else
	    {
		q += n;
		if ((i1 < 1) || (i1 > _nband))
		{
		    fprintf (stderr, "Line %d: fband index (%d) is out of range.\n", line, i1);
		    stat = ERROR;
		}
		else if (strlen (s1) > 15)
		{
		    fprintf (stderr, "line %d: output suffix (%s) is too long.\n", line, s1);
		    stat = ERROR;
		}
		else strcpy (_fband [i1 - 1]._label, s1);
	    }
	}
        else if (!strcmp (p, "/fband/gain"))
	{
	    if (!_nband) stat = SCOPE;
	    else if (sscanf (q, "%d%f%n", &i1, &f1, &n) != 2) stat = ARGS;
	    else
	    {
	        q += n;
                if ((i1 < 1) || (i1 > _nband))
	        {
	            fprintf (stderr, "Line %d: fband index (%d) is out of range.\n", line, i1);
	            stat = ERROR;
	        }
	        else if ((f1 < -30.0f) || (f1 > 10.0f))
	        {
	            fprintf (stderr, "Line %d: gain (%3.1lf) is out of range.\n", line, f1);
	            stat = ERROR;
	        }
	        else _fband [i1 - 1]._gain = f1;
	    }
	}
        else if (!strcmp (p, "/fband/delay"))
	{
	    if (!_nband) stat = SCOPE;
	    else if (sscanf (q, "%d%f%n", &i1, &f1, &n) != 2) stat = ARGS;
	    else
	    {
	        q += n;
                if ((i1 < 1) || (i1 > _nband))
	        {
	            fprintf (stderr, "Line %d: fband index (%d) is out of range.\n", line, i1);
	            stat = ERROR;
	        }
	        else if ((f1 < 0) || (f1 > 30.0f))
	        {
	            fprintf (stderr, "Line %d: delay (%4.2lf) is out of range.\n", line, f1);
	            stat = ERROR;
	        }
	        else _fband [i1 - 1]._delay = f1;
	    }
	}
        else if (!strcmp (p, "/xover/freq"))
	{
	    if (!_nband) stat = SCOPE;
	    else if (sscanf (q, "%d%f%n", &i1, &f1, &n) != 2) stat = ARGS;
	    else
	    {
	        q += n;
                if ((i1 < 1) || (i1 > _nband - 1))
	        {
	            fprintf (stderr, "Line %d: xover index (%d) is out of range.\n", line, i1);
	            stat = ERROR;
	        }
	        else if ((f1 < 10.0f) || (f1 > 24e3f))
	        {
	            fprintf (stderr, "Line %d: frequency (%4.2lf) is out of range.\n", line, f1);
	            stat = ERROR;
	        }
	        else _xover [i1 - 1]._freq = f1;
	    }
	}
        else if (!strcmp (p, "/xover/shape"))
	{
	    if (!_nband) stat = SCOPE;
	    else if (sscanf (q, "%d%f%n", &i1, &f1, &n) != 2) stat = ARGS;
	    else
	    {
	        q += n;
                if ((i1 < 1) || (i1 > _nband - 1))
	        {
	            fprintf (stderr, "Line %d: xover index (%d) is out of range.\n", line, i1);
	            stat = ERROR;
	        }
	        else if ((f1 < -6.0f) || (f1 > -3.0f))
	        {
	            fprintf (stderr, "Line %d: shape (%3.1lf) is out of range.\n", line, f1);
	            stat = ERROR;
	        }
	        else _xover [i1 - 1]._shape = f1;
	    }
	}
	else stat = COMM;

        if (!stat)
	{
            while (isspace (*q)) q++;
            if (*q >= ' ') stat = EXTRA;
	}		     

        switch (stat)
	{
        case COMM:
	    fprintf (stderr, "Line %d: unknown command '%s.'\n", line, p);   
            break;
        case ARGS:
	    fprintf (stderr, "Line %d: missing arguments in '%s' command.\n", line, p);   
            break;
        case EXTRA:
	    fprintf (stderr, "Line %d: extra arguments in '%s' command.\n", line, p);   
            break;
        case SCOPE:
	    fprintf (stderr, "Line %d: command '%s' in wrong scope.\n", line, p);   
            break;
	}
    }

    fclose (F);
    return stat;
}


int Lrxconf::check (float fsamp)
{
    int    i;
    float  f;

    for (i = 0; i < _nband - 1; i++)
    {
	f = _xover [i]._freq;
	if (f < 1.0f)
	{
	    fprintf (stderr, "Xover frequency at index %d is not defined.\n", i + 1);
	    return 1;
	}
	if (f > 0.48f * fsamp)
	{
	    fprintf (stderr, "Xover frequency %3.1lf is too high for sample rate.\n.", f);
	    return 1;
	}
    }
    return 0;
}
