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

#include <QDebug>

#include "tracksystemview.h"
#include "tracktitleview.h"
#include "trackwordsmusicview.h"
#include "tracktuningview.h"

#include "qcanvascm/qcanvasrectanglecm.h"

#include "tablature/tabnote.h"
#include "tablature/tabtimes.h"
#include "tablature/tabbar.h"
#include "tablature/tabtrack.h"
#include "tablature/trackpos.h"

#include "util/assert.h"

#include "settings.h"

TrackPageView::TrackPageView(uint dpi)
: DrawingItem(dpi),
  mSongProperties(0x0),
  mTabTrack(0x0),
  mPageSize(),
  mLeftMargins(0, dpi),
  mTopMargins(0, dpi),
  mPageNumber(0),
  mTitle(false),
  mWordsAndMusic(false),
  mTuning(false),
  mCanvasRectangle(0),
  mCanvasText(0),
  mTitleView(0),
  mWordsAndMusicView(0),
  mTuningView(0),
  mTrackSystemView()
{
}

TrackPageView::~TrackPageView()
{
	for (const_iterator it = mTrackSystemView.begin(); it != mTrackSystemView.end(); ++it)
		delete *it;
	
	deleteTitleView();
	deleteWordsAndMusicView();
	deleteTuningView();
	deletePageView();
}

void TrackPageView::deleteTitleView()
{
	if (mTitle) {
		delete mTitleView;
		mTitleView = 0;
	}
}

void TrackPageView::deleteWordsAndMusicView()
{
	if (mWordsAndMusic) {
		delete mWordsAndMusicView;
		mWordsAndMusicView = 0;
	}
}

void TrackPageView::deleteTuningView()
{
	if (mTuning) {
		delete mTuningView;
		mTuningView = 0;
	}
}

void TrackPageView::deletePageView()
{
	if (mCanvasRectangle) {
		delete mCanvasRectangle;
		delete mCanvasText;
		mCanvasRectangle = 0;
		mCanvasText = 0;
	}
}

void TrackPageView::setSongProperties(const TabProperties* songProperties)
{
	PRECONDITION( songProperties != 0x0 );
	
	mSongProperties = songProperties;
}

const TabProperties* TrackPageView::songProperties() const
{
	return mSongProperties;
}

void TrackPageView::setTabTrack(const TabTrack* tabTrack)
{
	PRECONDITION( tabTrack != 0x0 );
	
	mTabTrack = tabTrack;
}

const TabTrack* TrackPageView::tabTrack() const
{
	return mTabTrack;
}

void TrackPageView::setPageSize(const QSizeCm& pageSize)
{
	mPageSize = pageSize;
}

QSizeCm TrackPageView::pageSize() const
{
	return mPageSize;
}

void TrackPageView::setLeftMargins(Cm margins)
{
	PRECONDITION( margins.value() >= 0 );
	
	mLeftMargins = margins;
}

Cm TrackPageView::leftMargins() const
{
	return mLeftMargins;
}

void TrackPageView::setTopMargins(Cm margins)
{
	PRECONDITION( margins.value() >= 0 );
	
	mTopMargins = margins;
}

Cm TrackPageView::topMargins() const
{
	return mTopMargins;
}

Cm TrackPageView::pageWidth() const
{
	return Cm(mPageSize.width().value() - 2 * mLeftMargins.value(), dpi());
}

void TrackPageView::setPageNumber(uint pageNumber)
{
	mPageNumber = pageNumber;
}

uint TrackPageView::pageNumber() const
{
	return mPageNumber;
}

void TrackPageView::displayTitle(bool b)
{
	deleteTitleView();
	
	mTitle = b;
	
	if (mTitle)
		mTitleView = new TrackTitleView(mSongProperties, dpi());
}

bool TrackPageView::isDisplayTitle() const
{
	return mTitle;
}

void TrackPageView::displayWordsAndMusic(bool b)
{
	deleteWordsAndMusicView();
	
	mWordsAndMusic = b;
	
	if (mWordsAndMusic)
		mWordsAndMusicView = new TrackWordsAndMusicView(mSongProperties, dpi());
}

bool TrackPageView::isDisplayWordsAndMusic() const
{
	return mWordsAndMusic;
}

void TrackPageView::displayTuning(bool b)
{
	deleteTuningView();
	
	mTuning = b;
	
	if (mTuning)
		mTuningView = new TrackTuningView(mTabTrack->properties(), dpi());
}

bool TrackPageView::isDisplayTuning() const
{
	return mTuning;
}

void TrackPageView::addSystem(TrackSystemView* systemView)
{
	mTrackSystemView.push_back(systemView);
}

void TrackPageView::hide()
{
	if (isVisible() == false)
		return ;
	
	DrawingItem::hide();
	
	mCanvasText->hide();
	mCanvasRectangle->hide();
	
	hideHeaders();
	
	for (iterator it = mTrackSystemView.begin(); it != mTrackSystemView.end(); ++it)
		(*it)->hide();
}

Cm TrackPageView::rigthPositionOfPageRect() const
{
	return pageRectangle().right();
}

Cm TrackPageView::bottomPositionOfPageRect() const
{
	return pageRectangle().bottom();
}

QRectCm TrackPageView::pageRectangle() const
{
	return  QRectCm(mLeftMargins, (mPageSize.height() * (mPageNumber - 1)) + mTopMargins,
					mPageSize.width() - (mLeftMargins * 2), mPageSize.height() - mTopMargins);
}

int TrackPageView::lengthOfFeeder() const
{
	return feederOfPage().length();
}

QString TrackPageView::feederOfPage() const
{
	QString temp;
	return "Page " + temp.setNum(mPageNumber);
}

void TrackPageView::drawPage()
{
	QFont textFont(Settings::getInstance()->textAndTabFont());
	QFontMetrics textFontInfo(textFont);
	Pixel textWidth(textFontInfo.boundingRect("8").width(), dpi());
	Pixel textHeight(textFontInfo.boundingRect("8").height(), dpi());
	
	textWidth.fromOtherDpi(75);
	textHeight.fromOtherDpi(75);
	
	mCanvasRectangle = new QCanvasRectangleCm(pageRectangle());
	mCanvasText = new QCanvasTextCm(feederOfPage(), textFont);
	
	mCanvasText->setPosFromCoord(rigthPositionOfPageRect() - textWidth.toCm() * (lengthOfFeeder() + 1),
								 bottomPositionOfPageRect() + textHeight.toCm() * 0.5);
	
	addItemToScene(mCanvasText);
	addItemToScene(mCanvasRectangle);
}

void TrackPageView::drawHeaders()
{
	QPointCm currentPosition(position());
	
	drawAndAddHeight(mTitle, mTitleView, &currentPosition);
	drawAndAddHeight(mWordsAndMusic, mWordsAndMusicView, &currentPosition);
	drawAndAddHeight(mTuning, mTuningView, &currentPosition);
}

void TrackPageView::hideHeaders()
{
	if (mTitle)
		mTitleView->hide();
	
	if (mWordsAndMusic)
		mWordsAndMusicView->hide();
	
	if (mTuning)
		mTuningView->hide();
}

void TrackPageView::show()
{
	if (isVisible() == true)
		return ;
	
	DrawingItem::show();
	
	//setPosition(QPointCm(Cm(0, dpi()) + mLeftMargins, (mPageSize.height() * (mPageNumber - 1)) + mTopMargins));
	
	deletePageView();
	drawPage();
	drawHeaders();
	
	for (iterator it = mTrackSystemView.begin(); it != mTrackSystemView.end(); ++it)
		(*it)->show();
}

void TrackPageView::refresh()
{
	hide();
	show();
}

void TrackPageView::refreshSongProperties()
{
	hideHeaders();
	
	displayTitle(mTitle);
	displayWordsAndMusic(mWordsAndMusic);
	displayTuning(mTuning);
	
	drawHeaders();
}

void TrackPageView::drawAndAddHeight(bool condition, DrawingItem* canvasItem, QPointCm* point)
{
	if (condition == true) {
		canvasItem->setGraphicsScene(graphicsScene());
		drawCanvas(*point, canvasItem);
		point->setY(point->y() + canvasItem->height());
	}
}

void TrackPageView::refreshBarAt(uint barNumber, const TabBar* tabBar)
{
	const_iterator it = mTrackSystemView.begin();
	
	while ((it != mTrackSystemView.end()) && ((*it)->hasBarNumber(barNumber) == false))
		++it;
		
	if (it != mTrackSystemView.end())
		(*it)->refreshBarAt(barNumber, tabBar);
}

void TrackPageView::refreshTimeAt(uint bar, uint time, const TabTime* tabTime)
{
	const_iterator it = mTrackSystemView.begin();
	
	while ((it != mTrackSystemView.end()) && ((*it)->hasBarNumber(bar) == false))
		++it;
		
	if (it != mTrackSystemView.end())
		(*it)->refreshTimeAt(bar, time, tabTime);
}

void TrackPageView::refreshNoteAt(const TrackPos& position, const TabNote* tabNote)
{
	const_iterator it = mTrackSystemView.begin();
	
	while ((it != mTrackSystemView.end()) && ((*it)->hasBarNumber(position.bar()) == false))
		++it;
	
	if (it != mTrackSystemView.end())
		(*it)->refreshNoteAt(position, tabNote);
}

bool TrackPageView::hasBarNumber(uint barNumber) const
{
	bool result = false;
	
	for (const_iterator it = mTrackSystemView.begin(); result == false && it != mTrackSystemView.end(); ++it)
		result = (*it)->hasBarNumber(barNumber);
	
	return result;
}

TrackBarView* TrackPageView::barAt(uint barNumber) const
{
	for (const_iterator it = mTrackSystemView.begin(); it != mTrackSystemView.end(); ++it)
		if ((*it)->hasBarNumber(barNumber) == true)
			return (*it)->barAt(barNumber);
	
	qDebug() << "[TrackPageView::barAt] it != end()\n";
	throw std::exception();
}

TrackPos TrackPageView::cursorPositionAt(const QPointCm& point)
{
	TrackPos result;
	iterator it = mTrackSystemView.begin();
	
	while (it != mTrackSystemView.end() && (*it)->isPointInSystem(point) == false)
		++it;
	
	if (it != mTrackSystemView.end() && (*it)->isPointInSystem(point) == true) {
		//qDebug() << "[TrackPageView::cursorPositionAt]\n";
		result.clone((*it)->cursorPositionAt(point));
	}
	
	return result;
}

bool TrackPageView::isPointInPage(const QPointCm& point) const
{
	QRectCm rect = boundingRect();
	
	return point.x() >= rect.left() && point.x() <= rect.right() && point.y() >=  rect.top() && point.y() <= rect.bottom();
}

QRectCm TrackPageView::boundingRect() const
{
	return QRectCm(Cm(0, dpi()), mPageSize.height() * (mPageNumber - 1), mPageSize.width() - mLeftMargins, mPageSize.height() * mPageNumber);
}

Cm TrackPageView::height() const
{
	return mPageSize.height();
}

Cm TrackPageView::width() const
{
	return mPageSize.width();
}

Cm TrackPageView::headersHeight() const
{
	Cm headers(0, dpi());
	
	if (mTitle)
		headers = headers + mTitleView->height();
	
	if (mWordsAndMusic)
		headers = headers + mWordsAndMusicView->height();
	
	if (mTuning)
		headers = headers + mTuningView->height();
	
	return mTopMargins + headers;
}
