/***************************************************************************
 * trackpagelist.cpp: implementation of TrackPageList 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 "trackpagelist.h"

#include <QtDebug>
#include <QGraphicsScene>

#include "trackpageview.h"
#include "tablature/tabproperties.h"

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

#include "util/assert.h"

TrackPageList::TrackPageList()
: mSongProperties(0x0),
  mTabTrack(0x0),
  mPageSize(),
  mLeftMargins(Cm(0.0, 72)),
  mBottomMargins(Cm(0.0, 72)),
  mDpi(0),
  mGraphicsScene(0)
{
}

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

void TrackPageList::setGraphicsScene(QGraphicsScene* graphicsScene)
{
	PRECONDITION(graphicsScene != 0);
	
	mGraphicsScene = graphicsScene;
}

QGraphicsScene* TrackPageList::graphicsScene() const
{
	return mGraphicsScene;
}

void TrackPageList::setSongProperties(const TabProperties* songProperties)
{
	PRECONDITION( songProperties != 0x0 );
	
	mSongProperties = songProperties;
	
	if (size() >= 1) {
		TrackPageList::iterator it = page(1);
		
		(*it)->setSongProperties(mSongProperties);
		(*it)->refreshSongProperties();
	}
}

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

void TrackPageList::setTabTrack(const TabTrack* tabTrack)
{
	mTabTrack = tabTrack;
}

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

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

QSizeCm TrackPageList::pageSize()
{
	return mPageSize;
}

void TrackPageList::setMargins(const Cm& left, const Cm& bottom)
{
	PRECONDITION( left.value() >= 0.0 );
	PRECONDITION( bottom.value() >= 0.0 );
	
	mLeftMargins = left;
	mBottomMargins = bottom;
}

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

Cm TrackPageList::bottomMargins() const
{
	return mBottomMargins;
}

void TrackPageList::setDpi(uint dpi)
{
	mDpi = dpi;
}

uint TrackPageList::dpi()
{
	return mDpi;
}

void TrackPageList::push_front(TrackPageView* trackPageView)
{
	PRECONDITION(trackPageView != 0);
	QList<TrackPageView*>::push_front(trackPageView);
}

void TrackPageList::push_back(TrackPageView* trackPageView)
{
	PRECONDITION(trackPageView != 0);
	QList<TrackPageView*>::push_back(trackPageView);
}

void TrackPageList::push_back(uint pageNb)
{
	QRectCm pageSize(mLeftMargins,
					 mPageSize.height() * pageNb + mBottomMargins,
					 mPageSize.width() - (mLeftMargins * 2),
					 mPageSize.height() - (mBottomMargins * 2));
	
	/*TrackPageView *trackPage = new TrackPageView(mSongProperties, *mTabTrack, mScene, pageSize, pageNb + 1, mDpi);
	
	trackPage->draw();
	
	std::list<TrackPageView*>::push_back(trackPage);*/
}

TrackPageList::iterator TrackPageList::page(uint pageNumber)
{
	PRECONDITION( pageNumber > 0 );
	PRECONDITION( pageNumber <= size() );
	
	iterator it;
	uint i;
	
	for (it = begin(), i = 1; i < pageNumber; ++it, i++)
		;
	
	return it;
}

TrackPageList::const_iterator TrackPageList::page(uint pageNumber) const
{
	PRECONDITION( pageNumber > 0 );
	PRECONDITION( pageNumber <= size() );
	
	const_iterator it;
	uint i;
	
	for (it = begin(), i = 1; i < pageNumber; ++it, i++)
		;
	
	return it;
}

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

TrackBarView* TrackPageList::barAt(const TrackPos& trackPos)
{
	TrackBarView* bar = 0x0;
	iterator it = begin();
	
	while (it != end() && bar == 0x0) {
		if ((*it)->hasBarNumber(trackPos.bar()) == true)
			bar = (*it)->barAt(trackPos.bar());
		
		++it;
	}
	
	POSTCONDITION( bar != 0x0 );
	
	return bar;
}

void TrackPageList::draw(const TrackPageList::iterator& it)
{
	(*it)->show();
}

void TrackPageList::drawRange(const TrackPageList::iterator& from, const TrackPageList::iterator& to)
{
	for (iterator it = from; it != to; ++it)
		draw(it);
}

void TrackPageList::draw()
{
	drawRange(begin(), end());
}

void TrackPageList::draw(uint pageNumber)
{
	draw(page(pageNumber));
}

void TrackPageList::drawRange(uint from, uint to)
{
	to++;
	
	if (to < from)
		return ;
	
	for (iterator it = page(from); from < to; ++it, from++)
		draw(it);
}

bool TrackPageList::isPageDraw(uint pageNumber) const
{
	return (*page(pageNumber))->isVisible();
}

void TrackPageList::refreshPageAt(const TrackPos& trackPos)
{
	for (iterator it = begin(); it != end(); ++it)
		if ((*it)->hasBarNumber(trackPos.bar()) == true) {
			(*it)->refresh();
		}
}

void TrackPageList::refreshBarAt(const TrackPos& position)
{
	iterator it = begin();
	
	while ((it != end()) && ((*it)->hasBarNumber(position.bar()) == false))
		++it;
	
	if (it != end())
		(*it)->refreshBarAt(position.bar(), mTabTrack->bar(position.bar()));
}

void TrackPageList::refreshTimeAt(int bar, int time)
{
	iterator it = begin();
	
	while ((it != end()) && ((*it)->hasBarNumber(bar) == false))
		++it;
	
	if (it != end())
		(*it)->refreshTimeAt(bar, time, mTabTrack->time(bar, time));
}

void TrackPageList::refreshNoteAt(const TrackPos& position)
{
	iterator it = begin();
	
	while ((it != end()) && ((*it)->hasBarNumber(position.bar()) == false))
		++it;
	
	if (it != end())
		(*it)->refreshNoteAt(position, mTabTrack->note(position));
}

bool TrackPageList::isEmpty() const
{
	if (size() == 0)
		return true;
	
	return false;
}

bool TrackPageList::isObscured() const
{
	bool result = false;
	
	const_iterator it1 = begin();
	while (it1 != end() && result == false) {
		const_iterator it2 = begin();
		
		while (it2 != end() && result == false) {
			if (it1 != it2) {
				result = ((*it1)->positionX() < (*it2)->positionX() && (*it1)->positionX() + (*it1)->width() > (*it2)->positionX()
						&& (*it1)->positionY() < (*it2)->positionY() && (*it1)->positionY() + (*it1)->height() > (*it2)->positionY())
						|| ((*it1)->position() == (*it2)->position());
			}
			
			++it2;
		}
		
		++it1;
	}
	
	return result;
}
