/*
 * eqparameterwidget.cpp - defination of EqParameterWidget class.
 *
 * Copyright (c) 2014 David French <dave/dot/french3/at/googlemail/dot/com>
 *
 * This file is part of LMMS - http://lmms.io
 *
 * 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 (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#include "EqParameterWidget.h"
#include "QPainter"
#include "qwidget.h"
#include "lmms_math.h"
#include "MainWindow.h"
#include "QMouseEvent"
#include "EqControls.h"

EqParameterWidget::EqParameterWidget( QWidget *parent, EqControls * controls ) :
	QWidget( parent ),
	m_bands ( 0 ),
	m_selectedBand ( 0 )
{
	m_bands = new EqBand[8];
	resize( 250, 116 );
	//    connect( Engine::mainWindow(), SIGNAL( periodicUpdate() ), this, SLOT( update() ) );
	QTimer *timer = new QTimer(this);
	connect(timer, SIGNAL(timeout()), this, SLOT(update()));
	timer->start(100);
	float totalLength = log10( 21000 );
	m_pixelsPerUnitWidth = width( ) /  totalLength ;
	float totalHeight = 80;
	m_pixelsPerUnitHeight = (height() - 4) / ( totalHeight );
	m_scale = 1.5;
	m_pixelsPerOctave = freqToXPixel( 10000 ) - freqToXPixel( 5000 );
	m_controls = controls;
	tf = new TextFloat();
	tf->hide();

}




EqParameterWidget::~EqParameterWidget()
{
	if(m_bands)
	{
		delete[] m_bands;
		m_bands = 0;
	}
}




void EqParameterWidget::paintEvent( QPaintEvent *event )
{
	QPainter painter( this );
	//Draw Frequecy maker lines
	painter.setPen( QPen( QColor( 100, 100, 100, 200 ), 1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin ) );
	for( int x = 20 ; x < 100; x += 10)
	{
		painter.drawLine( freqToXPixel( x )  , 0, freqToXPixel( x ) , height() );
	}
	for( int x = 100 ; x < 1000; x += 100)
	{
		painter.drawLine( freqToXPixel( x )  , 0, freqToXPixel( x ) , height() );
	}
	for( int x = 1000 ; x < 11000; x += 1000)
	{
		painter.drawLine( freqToXPixel( x )  , 0, freqToXPixel( x ) , height() );
	}
	//draw 0dB line
	painter.drawLine(0, gainToYPixel( 0 ) , width(), gainToYPixel( 0 ) );

	for( int i = 0 ; i < bandCount() ; i++ )
	{
		m_bands[i].color.setAlpha( m_bands[i].active->value() ? activeAplha() : inactiveAlpha() );
		painter.setPen( QPen( m_bands[i].color, 1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin ) );
		float  x = freqToXPixel( m_bands[i].freq->value() );
		float y = height() * 0.5;
		float gain = 1;
		if( m_bands[i].gain )
		{
			gain = m_bands[i].gain->value();
		}
		y = gainToYPixel( gain );
		float bw = m_bands[i].freq->value() * m_bands[i].res->value();
		m_bands[i].x = x; m_bands[i].y = y;
		const int radius = 7;
		painter.drawEllipse( x - radius , y - radius, radius * 2 ,radius * 2 );
		QString msg = QString ( "%1" ).arg ( QString::number (i + 1) );
		painter.drawText(x - ( radius * 0.5 ), y + ( radius * 0.85 ), msg );
		painter.setPen( QPen( m_bands[i].color, 1, Qt::SolidLine, Qt::SquareCap, Qt::BevelJoin ) );
		if( i == 0 || i == bandCount() - 1 )
		{
			painter.drawLine(x , y, x, y - (m_bands[i].res->value() * 4  ) );
		}
		else
		{
			painter.drawLine(freqToXPixel(m_bands[i].freq->value()-(bw * 0.5)),y,freqToXPixel(m_bands[i].freq->value()+(bw * 0.5)),y);
		}
	}
}




void EqParameterWidget::mousePressEvent( QMouseEvent *event )
{
	m_oldX = event->x(); m_oldY = event->y();
	m_selectedBand = selectNearestHandle( event->x(), event->y() );
	m_mouseAction = none;
	if ( event->button() == Qt::LeftButton ) m_mouseAction = drag;
	if ( event->button() == Qt::RightButton ) m_mouseAction = res;
}




void EqParameterWidget::mouseReleaseEvent( QMouseEvent *event )
{
	m_selectedBand = 0;
	m_mouseAction = none;
	const int inXmin = 228;
	const int inXmax = 250;
	const int inYmin = 20;
	const int inYmax = 30;

	const int outXmin = 228;
	const int outXmax = 250;
	const int outYmin = 30;
	const int outYmax = 40;

	if(event->x() > inXmin && event->x() < inXmax && event->y() > inYmin && event->y() < inYmax )
	{
		m_controls->m_analyseIn = !m_controls->m_analyseIn;
	}

	if(event->x() > outXmin && event->x() < outXmax && event->y() > outYmin && event->y() < outYmax )
	{
		m_controls->m_analyseOut = !m_controls->m_analyseOut;
	}

	tf->hide();
}




void EqParameterWidget::mouseMoveEvent( QMouseEvent *event )
{
	int deltaX = event->x() - m_oldX;
	int deltaR = event->y() - m_oldY;
	m_oldX = event->x(); m_oldY = event->y();
	if(m_selectedBand && m_selectedBand->active->value() )
	{
		switch ( m_mouseAction ) {
		case none :
			break;
		case drag:
			if( m_selectedBand->freq ) m_selectedBand->freq->setValue( xPixelToFreq( m_oldX ) );
			if( m_selectedBand->gain )m_selectedBand->gain->setValue( yPixelToGain( m_oldY ) );
			break;
		case res:
			if( m_selectedBand->res )m_selectedBand->res->incValue( ( deltaX) * resPixelMultiplyer() );
			if( m_selectedBand->res )m_selectedBand->res->incValue( (-deltaR) * resPixelMultiplyer() );
			break;
		default:
			break;
		}
	}
	if( m_oldX > 0 && m_oldX < width() && m_oldY > 0 && m_oldY < height() )
	{
		tf->setText( QString::number(xPixelToFreq( m_oldX )) + tr( "Hz ") );
		tf->show();
		const int x = event->x() > width() * 0.5 ?
					m_oldX - tf->width() :
					m_oldX;
		tf->moveGlobal(this, QPoint( x, m_oldY - tf->height() ) );
	}
}




void EqParameterWidget::mouseDoubleClickEvent( QMouseEvent *event )
{
	EqBand* selected = selectNearestHandle( event->x() , event->y() );
	if( selected )
	{
		selected->active->setValue( selected->active->value() ? 0 : 1 );
	}
}




EqBand*  EqParameterWidget::selectNearestHandle( const int x, const  int y )
{
	EqBand* selectedModel = 0;
	float* distanceToHandles = new float[bandCount()];
	//calc distance to each handle
	for( int i = 0 ; i < bandCount() ; i++ )
	{
		int xOffset = m_bands[i].x - x;
		int yOffset = m_bands[i].y - y;
		distanceToHandles[i] = fabs( sqrt( ( xOffset * xOffset ) + ( yOffset * yOffset ) ) );
	}
	//select band
	int shortestBand = 0;
	for ( int i = 1 ; i < bandCount() ; i++ )
	{
		if ( distanceToHandles [i] < distanceToHandles[shortestBand] ){
			shortestBand = i;
		}
	}
	if(distanceToHandles[shortestBand] <  maxDistanceFromHandle() )
	{
		selectedModel = &m_bands[shortestBand];
	}
	delete[] distanceToHandles;
	return selectedModel;
}




EqBand::EqBand() :
	gain ( 0 ),
	res ( 0 ),
	freq ( 0 ),
	color ( QColor( 255, 255, 255 ) ),
	x( 0 ),
	y( 0 ),
	name ( QString( "" ) ),
	peakL( 0 ),
	peakR( 0 )
{
}
