// ----------------------------------------------------------------------------
//
//  Copyright (C) 2003-2013 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 "filtwin.h"
#include "global.h"


Filtwin::Filtwin (X_window *parent, X_callback *callb, int xp, int yp, int xs, int ys) :
    X_window (parent, xp, yp, xs, ys, Colors.plot_bg),
    _callb (callb),
    _xs (xs),
    _ys (ys),
    _show (false),
    _dots (0)
{
    int i;

    x_add_events (ExposureMask | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | StructureNotifyMask);  

    _xd = _xs - LSW - RSW;
    _yd = _ys - TPM - BSH - BWH;

    _plotw = new X_subwin (this, LSW, TPM, _xd, _yd, Colors.plot_bg);
    _plotw->x_add_events (ExposureMask);
    _plotw->x_map ();

    _lswin = new X_subwin (this, 0, 0, LSW, _yd + TPM + 8, Colors.plot_bg);
    _lswin->x_add_events (ExposureMask);
    _lswin->x_map ();

    _rswin = new X_subwin (this, _xs - RSW, 0, RSW, _yd + TPM + 8, Colors.plot_bg);
    _rswin->x_set_win_gravity (NorthEastGravity);
    _rswin->x_add_events (ExposureMask);
    _rswin->x_map ();

    _bswin = new X_subwin (this, LSW - 8, TPM + _yd, _xd + 16, BSH, Colors.plot_bg);
    _bswin->x_set_win_gravity (SouthWestGravity);
    _bswin->x_add_events (ExposureMask);
    _bswin->x_map ();

    _bbwin = new X_window (this, 0, _ys - BWH, _xs, BWH, XftColors.main_bg->pixel);
    _bbwin->x_set_win_gravity (SouthWestGravity);
    _bbwin->x_map ();

    set_xscale ();  
    set_yscale ();
    _dots1._col = Colors.plot_mk [0] ^ Colors.plot_bg;
    _dots2._col = Colors.plot_mk [1] ^ Colors.plot_bg;
    for (i = 0; i < 33; i++)
    {
        _dots1._v [i] = 0.5f;
        _dots2._v [i] = 0.0f;
    }    
    _dots2._v [ 0] = 1.0f;
    _dots2._v [32] = 1.0f;
}


Filtwin::~Filtwin (void)
{
}


void Filtwin::handle_event (XEvent *E)
{
    switch (E->type)
    {
    case MapNotify:
        _show = true;
        break;
    case UnmapNotify:
        _show = false;
        break;
    case GraphicsExpose:
    case Expose:
        expose ((XExposeEvent *) E);
        break;  
    case ButtonPress:
        bpress ((XButtonEvent *) E);
        break;  
    case ButtonRelease:
        brelse ((XButtonEvent *) E);
        break;  
    case MotionNotify:
        motion ((XPointerMovedEvent *) E);
        break;  
    }
}


void Filtwin::handle_callb (int k, X_window *W, XEvent *E )
{
/*
    int b, c, e;

    c = X_callback::cb_class (k);
    e = X_callback::cb_event (k);
    switch (c)
    {
    case X_callback::BUTTON:
    {
	X_button *B = (X_button *) W;
        b = ((XButtonEvent *) E)->button;
        k = B->cbid ();
        if (e == X_button::PRESS)
	{
	    switch (k)
	    {
	    default:
		;
	    }
	}
	break;
    }

    default:
	;
    }
*/
}


void Filtwin::expose (XExposeEvent *E)
{
    if (E->window == win ())
    {
    }
    else if (E->window == _plotw->win ())
    {
        if (E->count == 0) redraw ();
    }
    else if (E->window == _lswin->win ())
    {
	if (E->count == 0) plot_lscale ();
    }
    else if (E->window == _rswin->win ())
    {
	if (E->count == 0) plot_rscale ();
    }
    else if (E->window == _bswin->win ())
    {
	if (E->count == 0) plot_xscale ();
    }
}


void Filtwin::resize (int xs, int ys)
{
    if ((_xs != xs) || (_ys != ys))
    {
        _xs = xs;
        _ys = ys;
        _xd = _xs - LSW - RSW;
        _yd = _ys - TPM - BSH - BWH;
        x_resize (_xs, _ys); 
        set_xscale ();
        set_yscale ();
        _plotw->x_resize (_xd, _yd);
        _lswin->x_resize (LSW, _yd + TPM + 8);
        _rswin->x_resize (RSW, _yd + TPM + 8);
        _bswin->x_resize (_xd + 16, BSH);
        _bbwin->x_resize (_xs, BWH);
    }
}


void Filtwin::bpress (XButtonEvent *E)
{
    int x, y;

    if (_dots) return; 
    x = E->x - LSW;
    y = E->y - TPM;
    if      ((y >= _dots1._y1 - 3) && (y < _dots1._y0 + 3)) _dots = &_dots1;  
    else if ((y >= _dots2._y1 - 3) && (y < _dots2._y0 + 3)) _dots = &_dots2;  
    if (_dots)
    {
	finddot (x);
	if (_idot >= 0) movedot (y);
    }
}


void Filtwin::motion (XPointerMovedEvent *E)
{
    int x, y;

    if (_dots)
    {
	x = E->x - LSW;
	y = E->y - TPM;
	if (E->state & Button3Mask) finddot (x);
	if (_idot >= 0) movedot (y);
    }
}


void Filtwin::brelse (XButtonEvent *E)
{
    _dots = 0;
}


void Filtwin::set_xscale (void)
{
    int i;

    _xunit = (_xd - 1) / 3.3f;
    for (i = 12; i <= 44; i++)
    {
        _xticks [i - 12] = (int)(_xunit * (0.1f * i - 1.15f) + 0.5f);
    }
}


void Filtwin::set_yscale (void)
{
    int i, s;

    s = _yd - 1;
    for (i = 0; i <= 8; i++) _yticks [i] = s * i / 8;
    _dots1._y0 = _yticks [6];
    _dots1._y1 = _yticks [2];
    _dots2._y0 = _yticks [8];
    _dots2._y1 = _yticks [7];
}


void Filtwin::plot_xscale (void)
{
    int     i, d;
    X_draw  D (dpy (), _bswin->win (), dgc (), xft ());

    if (!_show) return;
    D.setfont (XftFonts.scales);
    D.clearwin ();
    D.setfunc (GXcopy);
    D.setline (0);
    D.setcolor (XftColors.plot_sc);
    d = XftFonts.scales->ascent + 1;
    for (i = 0; i < 33; i++)
    {
        D.move (_xticks [i] + 8, 0);
        if (_xtexts [i])
        {
            D.rdraw (0, 5);  
	    D.rmove (0, d);
            D.drawstring (_xtexts [i], 0);
	}
        else D.rdraw (0, 3);
    }
}


void Filtwin::plot_lscale (void)
{
    int     d, i;
    X_draw  D (dpy (), _lswin->win (), dgc (), xft ());

    if (!_show) return;
    D.setfont (XftFonts.scales);
    D.clearwin ();
    D.setfunc (GXcopy);
    D.setline (0);
    D.setcolor (XftColors.plot_sc);
    d = XftFonts.scales->ascent / 2 - 1;
    for (i = 0; i <= 8; i++)
    {
        D.move (LSW - 1, _yticks [i] + TPM);
        D.rdraw (-5, 0);
    }
}


void Filtwin::plot_rscale (void)
{
    int     d, i;
    X_draw  D (dpy (), _rswin->win (), dgc (), xft ());

    if (!_show) return;
    D.setfont (XftFonts.scales);
    D.clearwin ();
    D.setfunc (GXcopy);
    D.setline (0);
    D.setcolor (XftColors.plot_sc);
    d = XftFonts.scales->ascent / 2 - 1;
    for (i = 0; i <= 8; i++)
    {
        D.move (0, _yticks [i] + TPM);
        D.rdraw (5, 0);
    }
}


void Filtwin::update (void)
{
    if (_show) 
    {
	redraw ();
    }
}


void Filtwin::redraw ()
{
    X_draw  D (dpy (), _plotw->win (), dgc (), xft ());

    D.setcolor (Colors.plot_bg);
    D.setfunc (GXcopy);
    D.clearwin ();
    plot_grid (&D);
/*
    if (_data)
    {
	plot_data (&D);
	D.setfunc (GXxor);
    }
*/
    plot_dots (&D, &_dots1);
    plot_dots (&D, &_dots2);
}


void Filtwin::plot_grid (X_draw *D)
{
    int i;

    D->setline (0);
    D->setcolor (Colors.plot_gr);
    D->move (0, 0);
    D->rdraw (0, _yd);
    D->move (_xd - 1, 0);
    D->rdraw (0, _yd);
    for (i = 0; i <= 8; i++)
    {
	D->move (0, _yticks [i]);
	D->rdraw (_xd, 0);
    }
    for (i = 0; i < 33; i++)
    {
        if ((i % 3) == 0)
        {
	    D->move (_xticks [i], 0);
	    D->rdraw (0, _yd);
	}
    }
}


void Filtwin::plot_data (X_draw *D)
{
}


void Filtwin::plot_dots (X_draw *D, Dots *P)
{
    int   i, x, y;

    D->setfunc (GXxor);
    D->setcolor (P->_col);
    for (i = 0; i < 33; i++)
    {
        x = _xticks [i] - 3;
        y = P->v2y (P->_v [i]) - 3;
	D->fillrect (x, y, x + 6, y + 6);
    }
}


void Filtwin::finddot (int x)
{
    _idot = (int)(10 * x / _xunit);
    if (_idot <  0) _idot = 0;
    if (_idot > 32) _idot = 32;
    if (abs (_xticks [_idot] - x) > 5) _idot = -1;
}


void Filtwin::movedot (int y1)
{
    int     x0, y0;
    X_draw  D (dpy (), _plotw->win (), dgc (), 0);
    
    D.setfunc (GXxor);
    D.setcolor (_dots->_col);
    x0 = _xticks [_idot] - 3;
    y0 = _dots->v2y (_dots->_v [_idot]) - 3;
    _dots->_v [_idot] = _dots->y2v (y1);
    y1 = _dots->v2y (_dots->_v [_idot]) - 3;
    if (y1 != y0)
    {
        D.fillrect (x0, y0, x0 + 6, y0 + 6);
        D.fillrect (x0, y1, x0 + 6, y1 + 6);
    }
}


const char *Filtwin::_xtexts [33] =
{
    0,  "20", 0, 0, 0,  "50", 0, 0, "100", 0,
    0, "200", 0, 0, 0, "500", 0, 0,  "1k", 0,
    0,  "2k", 0, 0, 0,  "5k", 0, 0, "10k", 0,
    0, "20k", 0
};
