#include "equalizer.h"
#include "engine.h"
#include <common.h>
#include <dynamicrequest.h>
#include <artsflow.h>
#include <noatunapp.h>
#include <player.h>
#include <soundserver.h> 
#include "Equalizer.h"
#include <ktempfile.h>
#include <qdom.h>
#include <netaccess.h>
#include <kstddirs.h>
#include <qtextstream.h>
#include <math.h>

#define EQ napp->equalizer()
#define EQBACK napp->player()->engine()->equalizer()

Band::Band(int start, int end) : mLevel(0), mStart(start), mEnd(end)
{
	EQ->add(this);
	EQ->update();
	emit EQ->changed();
	emit EQ->changed(this);
}

Band::~Band()
{
	EQ->remove(this);
}

int Band::level()
{
	return mLevel;
}

void Band::setLevel(int l)
{
	mLevel=l;
	EQ->update();
	emit EQ->changed();
	emit EQ->changed(this);
}

int Band::start() const
{
	return mStart;
}

int Band::end() const
{
	return mEnd;
}

int Band::center() const
{
	return (mStart+mEnd)/2;
}

static QString formatFreq(int f, bool withHz)
{
	QString format;
	if (f<991)
		format=QString::number(f);
	else
		format=QString::number((int)((f+500)/1000.0))+"k";
	
	if (withHz)
		format+="Hz";

	return format;
}

QString Band::formatStart(bool withHz) const
{
	return formatFreq(mStart, withHz);
}

QString Band::formatEnd(bool withHz) const
{
	return formatFreq(mEnd, withHz);
}

QString Band::format(bool withHz) const
{
	return formatFreq(center(), withHz);
}

/* rate 4
27       54     0-108      108
81       163    109-217    108
243      514    218-810    269
729      1621   811-2431  1620
2187     4661   2432-7290 4858
6561     13645  7291+     12708
   
*/
Equalizer::Equalizer() : mUpdates(true)
{
}

void Equalizer::init()
{
	for (Band *i=mBands.first(); i!=0; i=mBands.next())
		delete i;

	if (!load(napp->dirs()->saveLocation("data", "noatun/") + "equalizer"))
	{
		enableUpdates(false);
		new Band(0, 108);
		new Band(109, 217);
		new Band(218, 810);
		new Band(811, 2431);
		new Band(2432, 7290);
		new Band(7291, 19999);
	
		enableUpdates();
		setPreamp(0);
		update(true);
	}
}

Equalizer::~Equalizer()
{
	save(napp->dirs()->saveLocation("data", "noatun/") + "equalizer");
	for (Band *i=mBands.first(); i!=0; i=mBands.next())
		delete i;
}

const QList<Band> &Equalizer::bands() const
{
	return mBands;
}

Band *Equalizer::band(int num) const
{
	// can't use QList::at since it sets current

	QListIterator<Band> item(mBands);
	item+=(unsigned int)num;
	return *item;		
}

int Equalizer::bandCount() const
{
	return (int)mBands.count();
}

int Equalizer::preamp() const
{
	return mPreamp;
}

bool Equalizer::isEnabled() const
{
	return (bool)EQBACK->enabled();

}

void Equalizer::setPreamp(int p)
{
	mPreamp=p;
	EQBACK->preamp(pow(2,(float)p/100.0));
	emit changed();
	emit preampChanged();
	emit preampChanged(p);
}

void Equalizer::enable()
{
	setEnabled(true);
}

void Equalizer::disable()
{
	setEnabled(false);
}

void Equalizer::setEnabled(bool e)
{
	EQBACK->enabled((long)e);
	emit enabled(e);
	if (e)
		emit enabled();
	else
		emit disabled();
	emit changed();
}

bool Equalizer::save(const KURL &filename) const
{
	QDomDocument doc("noatunequalizer");
	doc.setContent(QString("<!DOCTYPE NoatunEqualizer><noatunequalizer/>"));
	QDomElement docElem = doc.documentElement();
	
	{
		docElem.setAttribute("level", preamp());
		docElem.setAttribute("enabled", isEnabled());
	}

	for (QListIterator<Band> i(mBands); i.current(); ++i)
	{
		QDomElement elem = doc.createElement("band");
		elem.setAttribute("start", (*i)->start());
		elem.setAttribute("end", (*i)->end());
		elem.setAttribute("level", (*i)->level());
	
		docElem.appendChild(elem);
	}
	
	KTempFile file;

	*(file.textStream()) << doc.toString();
	file.close();
	
	return KIO::NetAccess::upload(file.name(), filename);
}

bool Equalizer::load(const KURL &filename)
{
	QString dest;
	if(KIO::NetAccess::download(filename, dest))
	{
		QFile file(dest);
		if (!file.open(IO_ReadOnly))
			return false;
		
		QDomDocument doc("noatunequalizer");
		if (!doc.setContent(&file))
			return false;
	
		QDomElement docElem = doc.documentElement();
		if (docElem.tagName()!="noatunequalizer")
			return false;

		setEnabled(docElem.attribute("enabled", "0")!="0");
		
		enableUpdates(false);
	
		blockSignals(true);
		setPreamp(docElem.attribute("preamp", "0").toInt());
		for (QDomNode n = docElem.firstChild(); !n.isNull(); n = n.nextSibling())
		{
			QDomElement e = n.toElement();
			if(e.isNull()) continue;
			if (e.tagName()!="band") continue;

			int start=e.attribute("start","0").toInt();
			int end=e.attribute("end", "108").toInt();
			int level=e.attribute("level", "0").toInt();
			Band *b=new Band(start,end);
			b->setLevel(level);
		}
		enableUpdates();
		blockSignals(false);
		update(true);
		emit changed();
		return true;
	}
	return false;
}

void Equalizer::add(Band *b)
{
	mBands.append(b);
}

void Equalizer::remove(Band *b)
{
	mBands.removeRef(b);
}

void Equalizer::update(bool full)
{
	if (!mUpdates)
		return;
	
	vector<float> levels;
	vector<float> mids;
	vector<float> widths;
	
	for (Band *i=mBands.first(); i!=0; i=mBands.next())
	{
		levels.push_back(pow(2, (float)i->mLevel/50.0));
		if (full)
		{
			int mid=i->mStart+i->mEnd;
			mids.push_back(((float)mid)*0.5);
			widths.push_back((float)(i->mEnd-i->mStart));
		}
	}
	if (full)
		EQBACK->set(levels, mids, widths);
	else
		EQBACK->levels(levels);
}

void Equalizer::enableUpdates(bool on)
{
	mUpdates=on;
}

#include "equalizer.moc"

