/***************************************************************************
 * tracktimesview.cpp: implementation of TrackTimesView class
 *
 * This file is part of KTabEdit, a KDE tabulature editor
 *
 * copyright (C) 2006- the KTabEdit development team <mrgwen@gmail.com>
 ***************************************************************************/

/***************************************************************************
 * 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.
 *
 * See the file COPYING for more information.
 ***************************************************************************/

#include "tracktimesview.h"

#include <KStandardDirs>
#include <QFontMetrics>
#include <QtDebug>

#include "qcanvascm/qcanvastextcm.h"
#include "qcanvascm/qcanvasellipsecm.h"

#include "tablature/tabnote.h"
#include "tablature/tabtimes.h"

const QFont TrackTimesView::sClassicalFont("feta26", 26);

TrackTimesView::TrackTimesView(const TabTime* time, const QFont& textFont, uint strings, const Cm& space, uint dpi)
: DrawingItem(dpi),
  mTabTime(time),
  mFont(textFont),
  mNbStrings(strings),
  mLineSpaces(space),
  mTimeSpace(0.0, dpi),
  mNoteCollection(),
  mEffectCollection(),
  mDottedTime(0x0),
  mRestTime(0x0)
{
}

TrackTimesView::~TrackTimesView()
{
	for (iterator it = mNoteCollection.begin(); it != mNoteCollection.end(); ++it)
		delete (*it);
	
	for (iterator it = mEffectCollection.begin(); it != mEffectCollection.end(); ++it)
		delete (*it);
	
	if (mDottedTime != 0x0)
		delete mDottedTime;
	
	if (mRestTime != 0x0)
		delete mRestTime;
}

void TrackTimesView::hide()
{
	for (iterator it = mNoteCollection.begin(); it != mNoteCollection.end(); ++it)
		(*it)->hide();
	
	for (iterator it = mEffectCollection.begin(); it != mEffectCollection.end(); ++it)
		(*it)->hide();
	
	if (mDottedTime != 0x0)
		mDottedTime->hide();
	
	if (mRestTime != 0x0)
		mRestTime->hide();
}

void TrackTimesView::refreshTime(const TabTime* tabTime)
{
	PRECONDITION( tabTime != 0x0 );
	
	for (iterator it = mNoteCollection.begin(); it != mNoteCollection.end(); ++it) {
		(*it)->hide();
		delete (*it);
	}
	
	mNoteCollection.clear();
	
	for (iterator it = mEffectCollection.begin(); it != mEffectCollection.end(); ++it) {
		(*it)->hide();
		delete (*it);
	}
	
	mEffectCollection.clear();
	
	if (mDottedTime != 0x0) {
		mDottedTime->hide();
		delete mDottedTime;
		mDottedTime = 0x0;
	}
	
	if (mRestTime != 0x0) {
		mRestTime->hide();
		delete mRestTime;
		mRestTime = 0x0;
	}
	
	mTabTime = tabTime;
	
	show();
}

void TrackTimesView::refreshNoteAt(int note, const TabNote* tabNote)
{
	PRECONDITION( tabNote != 0x0 );
	
	if (mNoteCollection.contains(note) == true) {
		mNoteCollection[note]->hide();
		delete mNoteCollection[note];
		
		mNoteCollection.remove(note);
		
		if (mEffectCollection.contains(note) == true) {
			mEffectCollection[note]->hide();
			delete mEffectCollection[note];
			
			mEffectCollection.remove(note);
		}
	}
	
	drawNote(note, tabNote);
}

void TrackTimesView::drawFret()
{
	//QGraphicsPixmapItem* img;
	//QString string;
	QFontMetrics fm(mFont);
	Pixel fontHeight(fm.boundingRect("8").height(), dpi());
	Pixel fontWidth(fm.boundingRect("8").width(), dpi());
	
	fontHeight.fromOtherDpi(75);
	fontWidth.fromOtherDpi(75);
	
	for (unsigned int i = 0; i < mNbStrings; i++)
		drawNote(i, mTabTime->string(i));
	
	 /*{
		img = 0x0;
		
 		if ((mTabTime->isNoteEmpty(i) == false) || ((mTabTime->isDeadNote(i) == true) && (mTabTime->isTieNote(i) == false))) {
			if (mTabTime->isDeadNote(i) == true)
				string = "X";
			else if (mTabTime->isNoteGhostNote(i))
				string = '(' + string.setNum(mTabTime->fret(i)) + ')';
			else
				string = string.setNum(mTabTime->fret(i));
			
			QCanvasTextCm* canvasText = new QCanvasTextCm(string);
			mNoteCollection.insert(i, canvasText);
			canvasText->setPosFromCoord(positionX(), positionY() + fontHeight.toCm() * i - fontHeight.toCm() / 2);
			//canvasText->setPosFromCoord(positionX(), positionY() + mLineSpaces * i - mLineSpaces / 2);
			addItemToScene(canvasText);
			
			switch (mTabTime->bend(i)->bendType()) {
			case TabBend::Bend:
				img = new QGraphicsPixmapItem(QPixmap(KStandardDirs::locate("data", "ktabedit/pics/bend.png")));
				break;
			case TabBend::BendRelease:
				img = new QGraphicsPixmapItem(QPixmap(KStandardDirs::locate("data", "ktabedit/pics/bendrelease.png")));
				break;
			case TabBend::BendReleaseBend:
				img = new QGraphicsPixmapItem(QPixmap(KStandardDirs::locate("data", "ktabedit/pics/bendrelease.png")));
				break;
			case TabBend::PreBend:
				img = new QGraphicsPixmapItem(QPixmap(KStandardDirs::locate("data", "ktabedit/pics/prebendrelease.png")));
				break;
			case TabBend::PreBendRelease:
				img = new QGraphicsPixmapItem(QPixmap(KStandardDirs::locate("data", "ktabedit/pics/prebendrelease.png")));
				break;
			default:
				break;
			}
			
			if (img != 0x0) {
				img->setOffset(positionX().toPixel().value() + 5, (positionY() + mLineSpaces * i - mLineSpaces / 2).toPixel().value());
				addItemToScene(img);
				mEffectCollection.insert(i, img);
			}
		}
	}*/
	
	if (mTabTime->isDotted() == true) {
		mDottedTime = new QCanvasEllipseCm(positionX() + fontWidth.toCm() ,positionY() + mLineSpaces * mNbStrings - mLineSpaces / 2, 
														 Cm(0.05, dpi()), Cm(0.05, dpi()));
		addItemToScene(mDottedTime);
	}
}

void TrackTimesView::drawNote(uint note, const TabNote* tabNote)
{
	QFontMetrics fm(mFont);
	Pixel fontHeight(fm.boundingRect("8").height(), dpi());
	Pixel fontWidth(fm.boundingRect("8").width(), dpi());
	
	fontHeight.fromOtherDpi(75);
	fontWidth.fromOtherDpi(75);
	QGraphicsPixmapItem* img = 0x0;
	QString string;
	
	if ((tabNote->isEmpty() == false) || ((tabNote->isDeadNote() == true) && (tabNote->isTieNote() == false))) {
		if (tabNote->isDeadNote() == true)
			string = "X";
		else if (tabNote->isGhostNote())
			string = '(' + string.setNum(tabNote->fret()) + ')';
		else
			string = string.setNum(tabNote->fret());
		
		QCanvasTextCm* canvasText = new QCanvasTextCm(string);
		mNoteCollection.insert(note, canvasText);
		canvasText->setPosFromCoord(positionX(), positionY() + fontHeight.toCm() * note - fontHeight.toCm() / 2);
		addItemToScene(canvasText);
		
		switch (tabNote->bendType()) {
		case TabBend::Bend:
			img = new QGraphicsPixmapItem(QPixmap(KStandardDirs::locate("data", "ktabedit/pics/bend.png")));
			break;
		case TabBend::BendRelease:
			img = new QGraphicsPixmapItem(QPixmap(KStandardDirs::locate("data", "ktabedit/pics/bendrelease.png")));
			break;
		case TabBend::BendReleaseBend:
			img = new QGraphicsPixmapItem(QPixmap(KStandardDirs::locate("data", "ktabedit/pics/bendrelease.png")));
			break;
		case TabBend::PreBend:
			img = new QGraphicsPixmapItem(QPixmap(KStandardDirs::locate("data", "ktabedit/pics/prebendrelease.png")));
			break;
		case TabBend::PreBendRelease:
			img = new QGraphicsPixmapItem(QPixmap(KStandardDirs::locate("data", "ktabedit/pics/prebendrelease.png")));
			break;
		default:
			break;
		}
		
		if (img != 0x0) {
			img->setOffset(positionX().toPixel().value() + 5, (positionY() + mLineSpaces * note - mLineSpaces / 2).toPixel().value());
			addItemToScene(img);
			mEffectCollection.insert(note, img);
		}
	}
}

void TrackTimesView::show()
{
	if (mTabTime->isRest()) {
		QCanvasTextCm* canvasText = 0;
		QString string;
		
		switch (mTabTime->duration()) {
		case NoneDuration:
			break;
		case HundredTwentyEighth:
			string = QChar(46);
			break;
		case SixtyFourth:
			string = QChar(45);
			break;
		case ThirthSecond:  // 1/32
			string = QChar(44);
			break;
		case Sixteenth:  // 1/16
			string = QChar(43);
			break;
		case Eighth:  // 1/8
			string = QChar(42);
			break;
		case Quarter: // 1/4
			string = QChar(40);
			break;
		case Half: // 1/2
			string = QChar(34);
			break;
		case Whole: // whole
			string = QChar(33);
			break;
		}
		
		mRestTime = canvasText = new QCanvasTextCm(string, sClassicalFont);
		canvasText->moveBy(positionX(), positionY());
		addItemToScene(canvasText);
	} else
		drawFret();
}

QRectCm TrackTimesView::boundingRect () const
{
	return QRectCm(position().x() - width() / 2, position().y(), width(), height());
}

Cm TrackTimesView::height() const
{
	QFontMetrics fm(mFont);
	Pixel fontHeight(fm.boundingRect("8").height(), dpi());
	fontHeight.fromOtherDpi(75);
	
	return fontHeight.toCm() * mNbStrings - fontHeight.toCm();
}

Cm TrackTimesView::width() const
{
	QFontMetrics fm(mFont);
	Pixel fontWidth(fm.boundingRect("8").width(), dpi());
	fontWidth.fromOtherDpi(75);
	
	return mLineSpaces;
}

bool TrackTimesView::isPointInTime(const QPointCm& point) const
{
	QRectCm rect = boundingRect();
	
	//qDebug() << "[TrackTimesView::isPointInTime] " << point.x().valueOfPixel() << " " << point.y().valueOfPixel() << "\n";
	//qDebug() << "[TrackTimesView::isPointInTime] " << rect.left().valueOfPixel() << " " << rect.right().valueOfPixel() << " " <<
	//			rect.top().valueOfPixel() << " " << rect.bottom().valueOfPixel() << "\n";
	//qDebug() << "[TrackTimesView::isPointInTime] " << mLineSpaces.valueOfPixel() << "\n";
	
	return point.x() >= rect.left() && point.x() <= rect.right() && point.y() >=  rect.top() && point.y() <= rect.bottom();
}

uint TrackTimesView::cursorPositionAt(const QPointCm& point)
{
	QFontMetrics fm(mFont);
	Pixel fontHeight(fm.boundingRect("8").height(), dpi());
	uint result = 0;
	bool chord = false;
	uint i = 0;
	
	fontHeight.fromOtherDpi(75);
	
	while (i < mNbStrings && chord == false) {
		chord = (positionY() + fontHeight.toCm() * i - fontHeight.toCm() / 2  <= point.y()) &&
				(positionX(), positionY() + fontHeight.toCm() * i + fontHeight.toCm() / 2 >= point.y());
		
		i++;
	}
	
	if (chord == true)
		result = i - 1;
	
	return result;
}
