/***************************************************************************
 * trackdurationview.cpp: implementation of TrackDurationView class
 *
 * This file is part of KTabEdit, a KDE tabulature editor
 *
 * copyright (C) 2003-2007 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 "trackdurationview.h"

#include <QtDebug>

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

const double TrackDurationView::queueSpace = 0.1;

TrackDurationView::TrackDurationView(const TabTime* time, uint strings, const Cm& space, const Cm& width, uint dpi)
: DrawingItem(dpi),
  mTabTime(time),
  nbStrings(strings),
  lineSpaces(space),
  durationWidth(width),
  mHalfDurationWidthCm(durationWidth / 2),
  mQueueLengthCm(lineSpaces * (nbStrings + 1)),
  mQueueSpaceCm(queueSpace, dpi),
  lineList(),
  mNextDuration(NoneDuration),
  mPreviousDuration(NoneDuration),
  mXPositionPreviousDuration(0.0, dpi)
{
}

TrackDurationView::~TrackDurationView()
{
	for (iterator it = lineList.begin(); it != lineList.end(); ++it)
		delete (*it);
}

void TrackDurationView::hide()
{
	for (iterator it = lineList.begin(); it != lineList.end(); ++it)
		(*it)->hide();
}

void TrackDurationView::setPreviousDuration(Duration previousDuration)
{
	mPreviousDuration = previousDuration;
}

Duration TrackDurationView::previousDuration() const
{
	return mPreviousDuration;
}

void TrackDurationView::setPositionOfPreviousDuration(const Cm& x)
{
	mXPositionPreviousDuration = x;
}

void TrackDurationView::setNextDuration(Duration nextDuration)
{
	mNextDuration = nextDuration;
}

Duration TrackDurationView::nextDuration() const
{
	return mNextDuration;
}

void TrackDurationView::show()
{
	drawVerticalLine();
	
	if (mPreviousDuration >= Quarter || mPreviousDuration == NoneDuration) {
		drawWithoutLink();
		//qDebug() << "1° cas\n";
	} else
		if (mNextDuration >= Quarter || mNextDuration == NoneDuration) {
			drawWithLinkAndNoNextLink();
			//qDebug() << "2° cas\n";
		} else {
			drawWithLinkAndNextLink();
			//qDebug() << "3° cas\n";
		}
}

void TrackDurationView::drawVerticalLine()
{
	int j;
	
	QCanvasLineCm* line = new QCanvasLineCm();
	lineList.push_front(line);
	
	switch (mTabTime->duration()) {
	case HundredTwentyEighth:
	case SixtyFourth:
	case ThirthSecond:  // 1/32 Triple croche
	case Sixteenth:  // 1/16 Double croche
	case Eighth:  // 1/8 Croche
	case Quarter: // 1/4 - a long vertical line, so we need to find the highest note
		for (j = nbStrings - 1;((j >= 0) && (mTabTime->isNoteEmpty(j) == true) && (mTabTime->isDeadNote(j) == false)); j--);
		
		// If it's an empty measure at all - draw the vertical line from bottom
		//
		if (j < 0)  j = 1;
		
		line->setPoints(position().x(), position().y() + lineSpaces * j,
						position().x(), position().y() + mQueueLengthCm);
		addItemToScene(line);
		
		break;		// required to prevent print preview artefact
	case Half: // 1/2 Blanche
		line->setPoints(position().x(), position().y() + mQueueLengthCm - Cm(0.05, dpi()),
						position().x(), position().y() + mQueueLengthCm);
		addItemToScene(line);
		
	case Whole: // whole Ronde
	case NoneDuration:
		break;
	}
}

void TrackDurationView::drawWithoutLink()
{
	uint nbLines = linesOfTimesDuration(mTabTime->duration());
	Cm y(0, dpi());
	
	QCanvasLineCm* line;
	
	for (uint i = 0; i < nbLines; i++) {
		line = new QCanvasLineCm();
		lineList.push_front(line);
		
		y = position().y() + mQueueLengthCm - (mQueueSpaceCm * i);
		
		line->setPoints(position().x(), y, position().x() + mHalfDurationWidthCm, y);
		addItemToScene(line);
	}
}

void TrackDurationView::drawWithLinkAndNoNextLink()
{
	if (mPreviousDuration <= mTabTime->duration()) {
		drawTimesDuration(linesOfTimesDuration(mTabTime->duration()), -mHalfDurationWidthCm);
	} else {
		drawTimesDurationWithGreaterPreviousDuration(-mHalfDurationWidthCm);
	}
}

void TrackDurationView::drawWithLinkAndNextLink()
{
	if (mPreviousDuration <= mTabTime->duration()) {
		drawTimesDuration(linesOfTimesDuration(mTabTime->duration()), -mHalfDurationWidthCm);
	} else {
		drawTimesDurationWithGreaterPreviousDuration(-mHalfDurationWidthCm);
	}
	
	if (mNextDuration <= mTabTime->duration()) {
		drawTimesDuration(linesOfTimesDuration(mTabTime->duration()), mHalfDurationWidthCm);
	}
}

void TrackDurationView::drawTimesDuration(uint nbLines)
{
	drawTimesDuration(nbLines, mHalfDurationWidthCm);
}

void TrackDurationView::drawTimesDuration(uint nbLines, const Cm& width)
{
	QCanvasLineCm* line;
	Cm y(0, dpi());
	
	for (uint i = 0; i < nbLines; i++) {
		line = new QCanvasLineCm();
		lineList.push_front(line);
		
		y = position().y() + mQueueLengthCm - (mQueueSpaceCm * i);
		
		line->setPoints(position().x(), y, position().x() + width, y);
		/*if (mXPositionPreviousDuration > Cm(0.0, dpi()))
			line->setPoints(mXPositionPreviousDuration, y, position().x() + width, y);
		else
			line->setPoints(position().x(), y, position().x() + width, y);*/
		
		addItemToScene(line);
	}
}

void TrackDurationView::drawTimesDurationWithGreaterPreviousDuration(const Cm& width)
{
	uint nbPreviousLines = linesOfTimesDuration(mPreviousDuration);
	uint nbLines = linesOfTimesDuration(mTabTime->duration());
	QCanvasLineCm* line;
	Cm y(0, dpi());
	
	for (uint i = 0; i < nbPreviousLines; i++) {
		line = new QCanvasLineCm();
		lineList.push_front(line);
		
		y = position().y() + mQueueLengthCm - (mQueueSpaceCm * i);
		
		if (mXPositionPreviousDuration > Cm(0.0, dpi()))
			line->setPoints(mXPositionPreviousDuration, y, position().x() + width, y);
		else
			line->setPoints(position().x(), y, position().x() + width, y);
		
		addItemToScene(line);
	}
	
	for (uint i = 0; i < nbLines; i++) {
		line = new QCanvasLineCm();
		lineList.push_front(line);
		
		y = position().y() + mQueueLengthCm - (mQueueSpaceCm * i);
		
		line->setPoints(position().x(), y, position().x() + (width / 2), y);
		
		addItemToScene(line);
	}
}

uint TrackDurationView::linesOfTimesDuration(Duration duration) const
{
	uint nbLines = 0;
	
	switch (duration) {
	case HundredTwentyEighth:
		nbLines = 5;
		break;
	case SixtyFourth:
		nbLines = 4;
		break;
	case ThirthSecond:
		nbLines = 3;
		break;
	case Sixteenth:
		nbLines = 2;
		break;
	case Eighth:
		nbLines = 1;
		break;
	case Quarter:
	case Half:
	case Whole:
	case NoneDuration:
		break; 
	}
	
	return nbLines;
}

QRectCm TrackDurationView::boundingRect() const
{
	return QRectCm(position().x(), position().y(), width(), height());
}

Cm TrackDurationView::height() const
{
	int j;
	
	switch (mTabTime->duration()) {
	case HundredTwentyEighth:
	case SixtyFourth:
	case ThirthSecond:
	case Sixteenth:
	case Eighth:
	case Quarter:
		for (j = nbStrings - 1;((j >= 0) && (mTabTime->isNoteEmpty(j)) && (mTabTime->isDeadNote(j) == false)); j--);
		
		if (j < 0)  j = 1;
		
		return lineSpaces * j;
		break;
	case Half: 
		return mQueueLengthCm - Cm(0.05, dpi());
	case Whole:
	case NoneDuration:
		break;
	}
	
	return Cm(0, dpi());
}

Cm TrackDurationView::width() const
{
	return durationWidth;
}
