/***************************************************************************
 * tracksystemview.cpp: implementation of TrackSystemView class
 *
 * This file is part of KTabEdit, a KDE tabulature editor
 *
 * copyright (C) 2003-2006 the KGuitar development team <mrgwen@gmail.com>
 * copyright (C) 2002-2003 the KGuitar 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 "tracksystemview.h"

#include <QtDebug>

#include "tablature/tabbar.h"
#include "tablature/tabnote.h"
#include "tablature/trackproperties.h"
#include "tablature/trackpos.h"
#include "trackbarview.h"

#include "util/assert.h"

TrackSystemView::TrackSystemView(uint dpi)
: DrawingItem(dpi),
  mSystem(),
  mSystemHeight(0, dpi),
  mSystemWidth(0, dpi),
  mHeight(0, dpi),
  mWidth(0, dpi),
  mLastSystem(false)
{
}

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

void TrackSystemView::setSystem(QList<TrackBarView*>& system)
{
	mSystem = system;
	
	minimalSystemWidth();
}

QList<TrackBarView*> TrackSystemView::system()
{
	return mSystem;
}

void TrackSystemView::appendBar(TrackBarView* trackBarView)
{
	PRECONDITION( trackBarView != 0 );
	
	mSystem.push_back(trackBarView);
	
	mSystemWidth = mSystemWidth + trackBarView->minimalWidth();
}

void TrackSystemView::lastSystem(bool b)
{
	mLastSystem = b;
}

bool TrackSystemView::isLastSystem() const
{
	return mLastSystem;
}

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

void TrackSystemView::show()
{
	// PRECONDITION(areBarsOnSamePositionY());
	
	QPointCm temp(position());
	Cm step(0, dpi());
	
	if (mLastSystem == true)
		step = Cm(0, dpi());
	else
		step = (mWidth - mSystemWidth) / mSystem.size();
	
	for (iterator it = mSystem.begin(); it != mSystem.end(); ++it) {
		(*it)->setPosition(temp);
		(*it)->setWidth((*it)->minimalWidth() + step);
		(*it)->show();
		
		temp.setX(temp.x() + (*it)->width());
	}
}

void TrackSystemView::refreshBarAt(uint barNumber, const TabBar* tabBar)
{
	const_iterator it = mSystem.begin();
	
	while ((it != mSystem.end()) && ((*it)->isBarNumber(barNumber) == false))
		++it;
	
	if (it != mSystem.end()) {
		(*it)->setTabBar(tabBar);
		(*it)->refresh();
	}
}

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

void TrackSystemView::refreshNoteAt(const TrackPos& position, const TabNote* tabNote)
{
	const_iterator it = mSystem.begin();
	
	while ((it != mSystem.end()) && ((*it)->isBarNumber(position.bar()) == false))
		++it;
	
	if (it != mSystem.end())
		(*it)->refreshNoteAt(position.times(), position.chord(), tabNote);
}

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

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

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

bool TrackSystemView::isPointInSystem(const QPointCm& point) const
{
	QRectCm rect = boundingRect();
	
	//qDebug() << point.x().value() << " " << point.y().value() << "\n";
	//qDebug() << rect.left().value() << " " << rect.right().value() << " " << rect.top().value() << " " << rect.bottom().value() << "\n";
	
	return point.x() >= rect.left() && point.x() <= rect.right() && point.y() >=  rect.top() && point.y() <= rect.bottom();
}

QRectCm TrackSystemView::boundingRect() const
{
	return QRectCm(positionX(), positionY(), width(), height());
}

void TrackSystemView::setHeight(const Cm& cm)
{
	mHeight = cm;
}

Cm TrackSystemView::height() const
{
	return mHeight;
}

void TrackSystemView::setWidth(const Cm& width)
{
	mWidth = width;
}

Cm TrackSystemView::width() const
{
	return mWidth;
}

Cm TrackSystemView::minimalSystemWidth()
{
	mSystemWidth = Cm(0.0, dpi());
	
	for (iterator it = mSystem.begin(); it != mSystem.end(); ++it)
		mSystemWidth = mSystemWidth + (*it)->minimalWidth();
	
	return mSystemWidth;
}

bool TrackSystemView::areBarsOnSamePositionY() const
{
	bool result = true;
	const_iterator it = mSystem.begin();
	
	while (it != mSystem.end() && result) {
		qDebug() << "Position =  "  << (*it)->positionY().value() << "  " << positionY().value() << "\n";
		result = ((*it)->positionY() == positionY());
		++it;
	}
	
	return result;
}

bool TrackSystemView::areBarsNotOnSamePositionX() const
{
	bool result = true;
	const_iterator it = mSystem.begin();
	const_iterator previousIt = mSystem.begin();
	
	if (it != mSystem.end()) {
		++it;
		
		while (it != mSystem.end() && result) {
			qDebug() << "Position =  "  << (*it)->positionX().value() << "  " << (*previousIt)->positionX().value() << "\n";
			result = ((*it)->positionX() <= (*previousIt)->positionX() + (*previousIt)->width());
			++it;
		}
	}
	
	return result;
}
