// ----------------------------------------------------------------------------
//
//  Copyright (C) 2008-2017 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 <math.h>
#include "styles.h"
#include "global.h"
#include "mainwin.h"


Mainwin::Mainwin (X_rootwin *parent, X_resman *xres, int xp, int yp, Jclient *jclient) :
    A_thread ("Main"),
    X_window (parent, xp, yp, XSIZE, YSIZE, XftColors [C_MAIN_BG]->pixel),
    _stop (false),
    _xres (xres),
    _jclient (jclient)
{
    X_hints     H;
    char        s [256];

    _atom = XInternAtom (dpy (), "WM_DELETE_WINDOW", True);
    XSetWMProtocols (dpy (), win (), &_atom, 1);
    _atom = XInternAtom (dpy (), "WM_PROTOCOLS", True);

    sprintf (s, "%s", jclient->jname ());
    x_set_title (s);
    H.position (xp, yp);
    H.minsize (XSIZE, YSIZE);
    H.maxsize (XSIZE, YSIZE);
    H.rname (xres->rname ());
    H.rclas (xres->rclas ());
    x_apply (&H); 

    RotaryCtl::init (disp ());
    _inpgain = new Rlinctl (this, this, R_INPGAIN, &r_ipgain_geom, 20, 0, 200, 5, -10.0, 30.0, 0.0);
    _threshd = new Rlinctl (this, this, R_THRESHD, &r_thresh_geom, 20, 0, 100, 1, -10.0,  0.0, 0.0);
    _reltime = new Rlogctl (this, this, R_RELTIME, &r_reltim_geom, 20, 0,  90, 3, 1e-3f,  1.0, 0.01);
    _inpgain->x_map ();
    _threshd->x_map ();
    _reltime->x_map ();

    _dispwin = new X_window (this, 275, 1, 315, 72, XftColors [C_DISP_BG]->pixel);
    _dispmap = XCreatePixmap (dpy (), _dispwin->win (), 315, 72, disp ()->depth ());
    _dispgct = XCreateGC (dpy (), _dispmap, 0, NULL);
    init_disp ();
    print_param (R_INPGAIN);
    print_param (R_THRESHD);
    print_param (R_RELTIME);
    _dispwin->x_map ();

    x_add_events (ExposureMask); 
    x_map (); 
    set_time (0);
    inc_time (500000);
}

 
Mainwin::~Mainwin (void)
{
    x_unmap ();
    XFreePixmap (dpy (), _dispmap);
    XFreeGC (dpy (), _dispgct);
    RotaryCtl::fini ();
}

 
int Mainwin::process (void)
{
    int e;

    if (_stop) handle_stop ();

    e = get_event_timed ();
    switch (e)
    {
    case EV_TIME:
        handle_time ();
	break;
    }
    return e;
}


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


void Mainwin::expose (XExposeEvent *E)
{
    if (E->count) return;
    redraw ();
}


void Mainwin::clmesg (XClientMessageEvent *E)
{
    if (E->message_type == _atom) _stop = true;
}


void Mainwin::handle_time (void)
{
    float gmax, gmin, peak;

    _jclient->dplimit ()->get_stats (&peak, &gmax, &gmin);
    disp_levels (gmax, gmin, peak);
    inc_time (50000);
    XFlush (dpy ());
}


void Mainwin::handle_stop (void)
{
    put_event (EV_EXIT, 1);
}


void Mainwin::init_disp (void)
{
    X_draw  D (dpy (), _dispmap, _dispgct, 0);

    D.setcolor (XftColors [C_DISP_BG]);
    D.fillrect (0, 0, 315, 72);
    XPutImage (dpy (), _dispmap, _dispgct, hmeter0_img, 0, 1, 2, 61, 311, 7); 
    XSetWindowBackgroundPixmap (dpy (), _dispwin->win (), _dispmap);
    _km = 0;
}


void Mainwin::disp_levels (float gmax, float gmin, float peak)
{
    int  d, x0, x1, xp;

    x0 = 105 - (int)(200.0f * log10f (gmin) - 0.5f);
    x1 = 105 - (int)(200.0f * log10f (gmax) - 0.5f);
    XCopyArea (dpy (), _dispmap, _dispmap, _dispgct, 107, 1, 208, 60, 107, 0);
    XPutImage (dpy (), _dispmap, _dispgct, hmeter1_img, x1, 0, x1 + 2, 59, x0 - x1 + 1, 1); 
    xp = 105 + (int)(200.0f * log10 (peak + 1e-6f) + 0.5f);
    if (xp <   0) xp = 0;
    if (xp > 310) xp = 310;
    d = xp - _km;
    if (d > 0)
    {
        XPutImage (dpy (), _dispmap, _dispgct, hmeter1_img, _km + 1, 1, _km + 3, 61, d, 7); 
	_km += d;
    }	    
    else if (d < 0)
    {
	if (d < -3) d = -3;
        _km += d;
        XPutImage (dpy (), _dispmap, _dispgct, hmeter0_img, _km + 1, 1, _km + 3, 61, -d, 7); 
    }	    
    _dispwin->x_clear ();
}


void Mainwin::handle_callb (int type, X_window *W, XEvent *E)
{
    RotaryCtl  *R;
    int         k;

    switch (type)
    {
    case RotaryCtl::PRESS:
	R = (RotaryCtl *) W;
	k = R->cbind ();
	break;

    case RotaryCtl::DELTA:
	R = (RotaryCtl *) W;
	k = R->cbind ();
	print_param (k);
	switch (k)
	{
        case R_INPGAIN:
   	    _jclient->set_inpgain (_inpgain->value ());
	    break;
        case R_THRESHD:
   	    _jclient->set_threshd (_threshd->value ());
	    break;
        case R_RELTIME:
   	    _jclient->set_reltime (_reltime->value ());
	    break;
	}
	break;
    }
}


void Mainwin::print_param (int k)
{
    int      y;
    float    v;
    char     s [10];
    XftColor *C;
    X_draw   D (dpy (), _dispmap, _dispgct, xft ());

    switch (k)
    {
    case R_INPGAIN:
        y = 0;
        v = _inpgain->value ();
        sprintf (s, "%2.1lf dB", v);
        C = XftColors [C_INPGAIN];
        break;
    case R_THRESHD:
	y = 18;
	v = _threshd->value ();
        sprintf (s, "%5.1lf dB", v);
	C = XftColors [C_THRESHD];
	break;
    case R_RELTIME:
	y = 36;
	v = _reltime->value ();
        if      (v >= 0.30f)  sprintf (s, "%4.2lf s", v);
        else if (v >= 0.03f)  sprintf (s, "%3.0lf ms", 1e3f * v);
        else                  sprintf (s, "%3.1lf ms", 1e3f * v);
	C = XftColors [C_RELTIME];
	break;
    default:
	return;
    }
    D.setcolor (XftColors [C_DISP_BG]);
    D.fillrect (0, y, 72, y + 20);
    D.setcolor (C);
    D.setfont (XftFonts [F_PARAMS]);
    D.move (70, y + 16);
    D.drawstring (s, 1);
    _dispwin->x_clear ();
}


void Mainwin::redraw (void)
{
    int x;

    x = 20;
    XPutImage (dpy (), win (), dgc (), parsect_img, 0, 0, x, 0, 233, 75);
    x = XSIZE - 35;
    XPutImage (dpy (), win (), dgc (), redzita_img, 0, 0, x, 0, 35, 35);
}


