// ----------------------------------------------------------------------------
//
//  Copyright (C) 2006-2011 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// ----------------------------------------------------------------------------


#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include "styles.h"
#include "global.h"
#include "confwin.h"



static const char *_r_scale_text [3] = { "N3D", "SN3D", "Furse-Malham" };
static const char *_r_delcm_text [1] = { "Delay comp." };
static const char *_r_levcm_text [1] = { "Gain comp."  };
static const char *_r_nfecm_text [3] = { "None", "On inputs", "On outputs" };
static const char *_chan_label [16] = { "W", "Y", "Z", "X", "V", "T", "R", "S", "U",
                                        "Q", "O", "M", "K", "L", "N", "P" };



Confwin::Confwin (X_rootwin *parent, X_callback *xcbh, X_resman *xres, int xp, int yp) :
    X_window (parent, xp, yp, XSIZE, YSIZE, XftColors [C_MAIN_BG]->pixel),
    _xcbh (xcbh),
    _conf (0),
    _r_scale (this, 0),
    _r_ipscl (this, this),
    _r_delay (this, this),
    _r_level (this, this),
    _r_nfeff (this, this),
    _focus (0)
{
    X_hints   H;
    int       i, x, y;
    
    _atom = XInternAtom (dpy (), "WM_DELETE_WINDOW", True);
    XSetWMProtocols (dpy (), win (), &_atom, 1);
    _atom = XInternAtom (dpy (), "WM_PROTOCOLS", True);

    H.position (xp, yp);
    H.size (XSIZE, YSIZE);
    H.minsize (XSIZE, YSIZE);
    H.maxsize (XSIZE, YSIZE);
    x_apply (&H);
    x_set_title ("AmbDec - Configuration");

    _filewin = new Filewin (parent, this, xres);

    Bst0.size.x = 70;
    Bst0.size.y = 18;
    _b_load = new X_tbutton (this, this, &Bst0,   0, 0, "Load",   0, B_LOAD);   
    _b_load->x_map ();
    _b_save = new X_tbutton (this, this, &Bst0,  70, 0, "Save",   0, B_SAVE);   
    _b_save->x_map ();
    _b_canc = new X_tbutton (this, this, &Bst0, 140, 0, "Cancel", 0, B_CANC);   
    _b_canc->x_map ();
    _b_appl = new X_tbutton (this, this, &Bst0, 210, 0, "Apply",  0, B_APPL);   
    _b_appl->x_map ();
    _t_stat = new X_textip (this, 0, &Tst1, 300,  0, 300, 18, 63);
    _t_stat->x_map ();
    (new X_textln (this, &Tst2,  20, 30, 85, 18, "Description", -1))->x_map ();
    _t_comm = new X_textip (this, this, &Tst0, 110, 30, 400, 17, 63);
    _t_comm->x_map ();

    (new X_textln (this, &Tst2,  20, 60, 115, 18, "Matrix scaling", -1))->x_map ();
    (new X_textln (this, &Tst2, 140, 60, 115, 18, "Input scaling",  -1))->x_map ();
    (new X_textln (this, &Tst2, 260, 60, 115, 18, "Speaker distance", -1))->x_map ();
    (new X_textln (this, &Tst2, 380, 60, 115, 18, "Near-field comp.", -1))->x_map ();
    _r_scale.init (&Bst1, &Tst1, _r_scale_text, 3,  20,  82, 115, 18, 0);
    _r_ipscl.init (&Bst1, &Tst1, _r_scale_text, 3, 140,  82, 115, 18, CB_OPT_IPSCL);
    _r_delay.init (&Bst1, &Tst1, _r_delcm_text, 1, 260,  82, 115, 18, CB_OPT_DELCM);
    _r_level.init (&Bst1, &Tst1, _r_levcm_text, 1, 260, 100, 115, 18, CB_OPT_LEVCM);
    _r_nfeff.init (&Bst1, &Tst1, _r_nfecm_text, 3, 380,  82, 115, 18, CB_OPT_NFECM);
    _l_xfreq = new X_textln (this, &Tst2, 500, 60, 120, 18, "Crossover freq.", -1);
    _l_xfreq->x_map ();
    _t_xfreq = new X_textip (this, this, &Tst0, 505, 82, 70, 17, 11);
    _t_xfreq->x_map ();
    _l_ratio = new X_textln (this, &Tst2, 500, 105, 120, 18, "H/L balance (dB)", -1);
    _l_ratio->x_map ();
    _t_ratio = new X_textip (this, this, &Tst0, 505, 127, 70, 17, 11);
    _t_ratio->x_map ();

    Bst3.size.x = 18;
    Bst3.size.y = 18;
    x = 700;
    y = 40;
    _chbutt [0] = new X_tbutton (this, 0, &Bst3, x, y, _chan_label [0], 0, 0);
    x -= 20;
    y += 20;
    for (i = 1; i < 4; i++)
    {
        _chbutt [i] = new X_tbutton (this, 0, &Bst3, x, y, _chan_label [i], 0, 0);
	x += 20;
    }
    x -= 80;
    y += 20;
    for (i = 4; i < 9; i++)
    {
        _chbutt [i] = new X_tbutton (this, 0, &Bst3, x, y, _chan_label [i], 0, 0);
	x += 20;
    }
    x -= 120;
    y += 20;
    for (i = 9; i < 16; i++)
    {
        _chbutt [i] = new X_tbutton (this, 0, &Bst3, x, y, _chan_label [i], 0, 0);
	x += 20;
    }
    for (i = 0; i < 16; i++) _chbutt [i]->x_map ();
}

 
Confwin::~Confwin (void)
{
}

 
void Confwin::handle_event (XEvent *E)
{
    switch (E->type)
    {
    case ClientMessage: 
	clmesg ((XClientMessageEvent *) E);
	break;
    }
}


void Confwin::clmesg (XClientMessageEvent *E)
{
    if (E->message_type == _atom) close ();
}


void Confwin::open (AD_conf *C)
{
    if (_conf) delete C;
    else
    {
        conf2disp (_conf = C);
	_b_save->set_stat (0);
	_b_appl->set_stat (0);
	_t_stat->set_text (_conf->_fname);
    }
    x_mapraised ();
}


void Confwin::close (void)
{
    x_unmap ();
    delete _conf;
    _conf = 0;
}


void Confwin::handle_callb (int type, X_window *W, XEvent *E)
{
    X_button   *B;
    X_textip   *T;

    switch (type)
    {
    case X_callback::BUTTON | X_button::PRESS:
    {
        B = (X_button *) W;
        switch (B->cbid ())
	{
	case B_LOAD:
  	    _filewin->load_dialog (".", "ambdec", "");
	    break;
	case B_SAVE:
	    if (disp2conf (_conf)) _t_stat->set_text ("Configuration error");
	    else _filewin->save_dialog (".", "ambdec", _conf->_fname);
	    break;
	case B_CANC:
	    if (_conf)
	    {
		delete _conf;
		_conf = 0;
		_xcbh->handle_callb (CB_CONF_CANC, 0, 0);
		_b_appl->set_stat (0);
	    }
	    break;
        case B_APPL:
	    if (_conf->_state)
	    {
		if (disp2conf (_conf)) _t_stat->set_text ("Configuration error");
		else
	        {
                    _t_stat->set_text (_conf ? _conf->_fname : "");
		    _xcbh->handle_callb (CB_CONF_APPL, 0, 0);
		    conf2disp (_conf);
		    _conf->_state = 0;
		    _b_appl->set_stat (0);
		    if (_focus) _focus->callb_modified ();
		}
	    }
	    break;
	}
	break;
    }
    case CB_OPT_IPSCL:    
    case CB_OPT_NFECM:    
    case CB_OPT_DELCM:    
    case CB_OPT_LEVCM:
    {
	_conf->_state |= AD_conf::ST_OPTS;
	_b_save->set_stat (1);
	_b_appl->set_stat (1);
	break;
    }
    case X_callback::TEXTIP | X_textip::BUT:
    {
        T = (X_textip *) W;
        T->enable ();
	T->callb_modified ();
	_focus = T;
	break;
    }
    case X_callback::TEXTIP | X_textip::MODIF:
    {
	_b_save->set_stat (1);
	_b_appl->set_stat (1);
	_conf->_state |= AD_conf::ST_OPTS | AD_conf::ST_MATR;
	break;
    }
    case CB_FILE_LOAD:
    {	
	chdir (_filewin->wdir ());
	if (_conf->load (_filewin->file ()))
	{
	    _b_save->set_stat (0);
            _t_stat->set_text ("LOAD FAILED");
	}
	else
	{
	    conf2disp (_conf);
	    _b_save->set_stat (0);
	    _b_appl->set_stat (1);
	    _t_stat->set_text (_conf->_fname);
	    _conf->_state = AD_conf::ST_ALL;
	}
	break;
    }
    case CB_FILE_SAVE:
    {
	chdir (_filewin->wdir ());
        if (_conf->save (_filewin->file ()))
	{
            _t_stat->set_text ("Save failed");
	}
	else
	{
	    _b_save->set_stat (0);
	    _t_stat->set_text (_conf->_fname);
	}
	break;
    }
    default:
	;
    }
}


int Confwin::conf2disp (AD_conf *C)
{
    int  i, m;
    char s [16];

    _r_scale.set_stat (C->_dec.scale);
    _r_ipscl.set_stat (C->_opt.scale);
    _r_delay.set_stat (C->_opt.delay); 
    _r_level.set_stat (C->_opt.level);
    _r_nfeff.set_stat (C->_opt.nfeff);
    sprintf (s, "%4.0lf", C->_opt.xfreq);
    _t_xfreq->set_color (Tst0.color.normal.bgnd, Tst0.color.normal.text);
    _t_xfreq->set_text (s);
    sprintf (s, "%4.1lf", C->_opt.ratio);
    _t_ratio->set_color (Tst0.color.normal.bgnd, Tst0.color.normal.text);
    _t_ratio->set_text (s);
    _t_comm->set_text (C->_descr);

    for (i = 0, m = C->_dec.cmask; i < 16; i++, m >>= 1)
    {
	_chbutt [i]->set_stat (m & 1);
    }
    return 0;
}


int Confwin::disp2conf (AD_conf *C)
{
    float    v;
    bool     err;

    C->_opt.scale = _r_ipscl.stat ();
    C->_opt.delay = _r_delay.stat (); 
    C->_opt.level = _r_level.stat ();
    C->_opt.nfeff = _r_nfeff.stat ();
    strcpy (C->_descr, _t_comm->text ());

    err = false;
    if (C->_dec.nband == 2)
    {
	if ((sscanf (_t_xfreq->text (), "%f", &v) != 1) || (v < 50) || (v > 5000))
	{
	    _t_xfreq->set_color (XftColors [C_TEXT_FG]->pixel, XftColors [C_TEXT_ER]);
	    err = true;
	}
	else C->_opt.xfreq = (int) v;
	if ((sscanf (_t_ratio->text (), "%f", &v) != 1) || (v < -30) || (v > 30))
	{
	    _t_ratio->set_color (XftColors [C_TEXT_FG]->pixel, XftColors [C_TEXT_ER]);
	    err = true;
	}
	else C->_opt.ratio = v;
    }

    return err ? 1 : 0;
}


