/***************************************************************************
 * tabbar.cpp: implementation of TabBar class
 *
 * This file is part of KGuitar, a KDE tabulature editor
 *
 * 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 "tabbar.h"
#include "util/assert.h"

#include "tabnote.h"
#include "tabtimes.h"

TabBar::TabBar(uchar bar)
: mBar(bar),
  keysig(0),
  mTabTime(),
  mMixer(0x0),
  mProperties(0x0)
{
	mMixer = new TabMixTableChanges();
	mProperties = new TabBarProperties();
}

TabBar::TabBar(uchar bar, uchar i, uchar j)
: mBar(bar),
  keysig(0),
  mTabTime(),
  mMixer(0x0),
  mProperties(0x0)
{
	mMixer = new TabMixTableChanges;
	mProperties = new TabBarProperties;
	
	setNumerator(i);
	setDenominator(j);
}

TabBar::~TabBar()
{
	if (hasMixer() == true)
		delete mixer();
	
	if (hasProperties() == true)
		delete properties();
	
	for (int i = 0; i < mTabTime.size(); i++)
		delete mTabTime[i];
}

void TabBar::clone(const TabBar* bar)
{
	PRECONDITION( bar != 0x0 );
	
	if (hasMixer() == true)
		delete mixer();
	
	if (hasProperties() == true)
		delete properties();
	
	for (int i = 0; i < mTabTime.size(); i++)
		delete mTabTime[i];
	
	mTabTime.clear();
	
	mBar = bar->mBar;
	keysig = bar->keysig;
	
	mProperties = new TabBarProperties();
	if (bar->hasProperties() == true)
		mProperties->clone(bar->properties());
	
	mMixer = new TabMixTableChanges();
	if (bar->hasMixer() == true)
		mMixer->clone(bar->mixer());
	
	TabTime* time;
	for (int i = 0; i < bar->mTabTime.size(); i++) {
		time = new TabTime(0);
		time->clone(bar->mTabTime[i]);
		
		mTabTime.push_back(time);
	}
}

uchar TabBar::bar() const
{
	return mBar;
}

void TabBar::setKeySignature(uint i)
{
	keysig = i;
}

uint TabBar::keySignature() const
{
	return keysig;
}

unsigned int TabBar::size() const
{
	return mTabTime.size();
}

void TabBar::insertTime(TabTime* time)
{
	PRECONDITION( time != 0 );
	
	mTabTime.push_back(time);
}

void TabBar::setTime(int timeNumber, TabTime* time)
{
	PRECONDITION( time != 0 );
	PRECONDITION( timeNumber < mTabTime.size() );
	
	delete mTabTime[timeNumber];
	mTabTime[timeNumber] = time;
}

TabTime* TabBar::time(int timeNumber) const
{
	PRECONDITION( timeNumber < mTabTime.size() );
	
	return mTabTime[timeNumber];
}

void TabBar::deleteTime(int timeNumber)
{
	PRECONDITION( timeNumber < mTabTime.size() );
	
	delete mTabTime[timeNumber];
	mTabTime.removeAt(timeNumber);
}

void TabBar::setTimeDuration(int timeNumber, Duration duration)
{
	PRECONDITION( timeNumber < mTabTime.size() );
	
	time(timeNumber)->setDuration(duration);
}

Duration TabBar::timeDuration(int timeNumber) const
{
	PRECONDITION( timeNumber < mTabTime.size() );
	
	return time(timeNumber)->duration();
}

double TabBar::timeRealDuration(int timeNumber) const
{
	PRECONDITION( timeNumber < mTabTime.size() );
	
	return time(timeNumber)->realDuration();
}

bool TabBar::isEmptyTime(int timeNumber) const
{
	PRECONDITION( timeNumber < mTabTime.size() );
	
	return time(timeNumber)->isEmpty();
}

void TabBar::setRest(int timeNumber, bool b)
{
	PRECONDITION( timeNumber < mTabTime.size() );
	
	time(timeNumber)->setRest(b);
}

bool TabBar::isDotted(int timeNumber) const
{
	PRECONDITION( timeNumber < mTabTime.size() );
	
	return time(timeNumber)->isDotted();
}

void TabBar::setDotted(int timeNumber, bool b)
{
	PRECONDITION( timeNumber < mTabTime.size() );
	
	time(timeNumber)->setDotted(b);
}

void TabBar::setFret(int timeNumber, uint stringNumber, uint fret)
{
	PRECONDITION( timeNumber < mTabTime.size() );
	
	time(timeNumber)->setFret(stringNumber, fret);
}

char TabBar::fret(int timeNumber, uint stringNumber) const
{
	PRECONDITION( timeNumber < mTabTime.size() );
	
	return time(timeNumber)->fret(stringNumber);
}

void TabBar::deleteFret(int timeNumber, uint stringNumber)
{
	PRECONDITION( timeNumber < mTabTime.size() );
	
	time(timeNumber)->deleteFret(stringNumber);
}

void TabBar::setNote(int timeNumber, uint stringNumber, TabNote* tabNote)
{
	PRECONDITION( timeNumber < mTabTime.size() );
	
	time(timeNumber)->setString(stringNumber, tabNote);
}

TabNote* TabBar::note(int timeNumber, uint stringNumber) const
{
	PRECONDITION( timeNumber < mTabTime.size() );
	
	return time(timeNumber)->string(stringNumber);
}

void TabBar::deleteNote(int timeNumber, uint stringNumber)
{
	PRECONDITION( timeNumber < mTabTime.size() );
	
	time(timeNumber)->deleteString(stringNumber);
}

bool TabBar::isRestTime(int timeNumber) const
{
	PRECONDITION( timeNumber < mTabTime.size() );
		
	return time(timeNumber)->isRest();
}

bool TabBar::isEmptyNote(int timeNumber, uint stringNumber) const
{
	PRECONDITION( timeNumber < mTabTime.size() );
	
	return time(timeNumber)->isNoteEmpty(stringNumber);
}

bool TabBar::isTieNote(int timeNumber, uint stringNumber) const
{
	PRECONDITION( timeNumber < mTabTime.size() );
	
	return time(timeNumber)->isTieNote(stringNumber);
}

bool TabBar::isFull() const
{
	bool full = true;
	float durationCount = 0;
	float time = 0.;
	unsigned int tuplet;
	
	for (int i = 0; i < mTabTime.size(); i++) {
		tuplet = mTabTime[i]->nTuplet() + 1;
		
		time = mTabTime[i]->duration();
		
		if (mTabTime[i]->isDotted())
			time+=(time / 2.0);

		if (tuplet > 1)
			time*=2;
		
		durationCount+=(time / tuplet);
	}
	
	if (durationCount < numerator() * (Whole / denominator()))
			full = false;
	
	return full;
}

bool TabBar::isOverTaken() const
{
	bool full = false;
	float durationCount = 0;
	float time = 0.;
	unsigned int tuplet;
	
	for (int i = 0; i < mTabTime.size(); i++) {
		tuplet = mTabTime[i]->nTuplet() + 1;
		
		time = mTabTime[i]->duration();
		
		if (mTabTime[i]->isDotted())
			time+=(time / 2.0);

		if (tuplet > 1)
			time*=2;
		
		durationCount+=(time / tuplet);
	}
	
	if (durationCount > numerator() * (Whole / denominator()))
			full = true;
	
	return full;
}

void TabBar::setMixer(TabMixTableChanges* mixer)
{
	PRECONDITION( mixer != 0x0 );
	
	if (mMixer)
		delete mMixer;
	
	mMixer = mixer;
}

TabMixTableChanges* TabBar::mixer() const
{
	PRECONDITION( mMixer != 0x0 );
	
	return mMixer;
}

bool TabBar::hasMixer() const
{
	return (mMixer != 0x0);
}

void TabBar::setInstrument(int i)
{
	mixer()->setInstrument(i);
}

int TabBar::instrument() const
{
	return mixer()->instrument();
}

void TabBar::setVolume(int i)
{
	mixer()->setVolume(i);
}

int TabBar::volume() const
{
	return mixer()->volume();
}

void TabBar::setBalance(int i)
{
	mixer()->setBalance(i);
}

int TabBar::balance() const
{
	return mixer()->balance();
}

void TabBar::setChorus(int i)
{
	mixer()->setChorus(i);
}

int TabBar::chorus() const
{
	return mixer()->chorus();
}

void TabBar::setReverb(int i)
{
	mixer()->setReverb(i);
}

int TabBar::reverb() const
{
	return mixer()->reverb();
}

void TabBar::setPhaser(int i)
{
	mixer()->setPhaser(i);
}

int TabBar::phaser() const
{
	return mixer()->phaser();
}

void TabBar::setTremolo(int i)
{
	mixer()->setTremolo(i);
}

int TabBar::tremolo() const
{
	return mixer()->tremolo();
}

void TabBar::setTempo(int i)
{
	mixer()->setTempo(i);
}

int TabBar::tempo() const
{
	return mixer()->tempo();
}

void TabBar::setProperties(TabBarProperties* properties)
{
	PRECONDITION( properties != 0x0 );
	
	if (mProperties != 0x0)
		delete mProperties;
	
	mProperties = properties;
}

TabBarProperties* TabBar::properties() const
{
	PRECONDITION( mProperties != 0x0 );
	
	return mProperties;
}

bool TabBar::hasProperties() const
{
	return (mProperties != 0x0);
}

void TabBar::setColor(const QColor& i)
{
	properties()->setColor(i);
}

QColor TabBar::color() const
{
	return properties()->color();
}

void TabBar::setMarker(const QString& s)
{
	properties()->setMarker(s);
}

QString TabBar::marker() const
{
	return properties()->marker();
}

void TabBar::setRepeatBar(bool b)
{
	properties()->setRepeatBar(b);
}

bool TabBar::isRepeatBar() const
{
	return properties()->isRepeatBar();
}

void TabBar::setCloseBar(bool b, QChar v)
{
	properties()->setCloseBar(b, v);
}

bool TabBar::isCloseBar() const
{
	return properties()->isCloseBar();
}

void TabBar::setAltBar(bool b)
{
	properties()->setAltBar(b);
}

bool TabBar::isAltBar() const
{
	return properties()->isAltBar();
}

void TabBar::setRepeatStart(bool b)
{
	properties()->setRepeatBar(b);
}

bool TabBar::isRepeatStart() const
{
	return properties()->isRepeatStart();
}

void TabBar::setRepetitions(int i)
{
	properties()->setRepetitions(i);
}

int TabBar::repetitions() const
{
	return properties()->repetitions();
}

void TabBar::setAlternateEndings(int i)
{
	properties()->setAlternateEndings(i);
}

int TabBar::isAlternateEndings() const
{
	return properties()->isAlternateEndings();
}

void TabBar::setDoubleBar(bool b)
{
	properties()->setDoubleBar(b);
}

bool TabBar::isDoubleBar() const
{
	return properties()->isDoubleBar();
}

void TabBar::setSongKey(SongKey* key)
{
	properties()->setSongKey(key);
}

SongKey* TabBar::songKey() const
{
	return properties()->songKey();
}

void TabBar::setKey(QChar c)
{
	properties()->setKey(c);
}

QChar TabBar::key() const
{
	return properties()->key();
}

char TabBar::asciiCodeOfKey() const
{
	return properties()->asciiCodeOfKey();
}

QString TabBar::nameOfKey() const
{
	return properties()->nameOfKey();
}

void TabBar::setMinor(bool i)
{
	properties()->setMinor(i);
}

bool TabBar::isMinor() const
{
	return properties()->isMinor();
}

void TabBar::setTimeSignature(TimeSignature* timeSignature)
{
	properties()->setTimeSignature(timeSignature);
}

TimeSignature* TabBar::timeSignature() const
{
	return properties()->timeSignature();
}

void TabBar::setNumerator(uchar c)
{
	properties()->setNumerator(c);
}

uchar TabBar::numerator() const
{
	return properties()->numerator();
}

void TabBar::setDenominator(uchar c)
{
	properties()->setDenominator(c);
}

uchar TabBar::denominator() const
{
	return properties()->denominator();
}

uint TabBar::timeLigatures() const
{
	return properties()->timeLigatures();
}

void TabBar::setDeadNote(uint timeNumber, uint stringNumber, bool b)
{
	time(timeNumber)->setDeadNote(stringNumber, b);
}

bool TabBar::isDeadNote(uint timeNumber, uint stringNumber) const
{
	return time(timeNumber)->isDeadNote(stringNumber);
}

bool TabBar::isAccentuated(uint timeNumber, uint stringNumber) const
{
	return time(timeNumber)->isAccentuated(stringNumber);
}

void TabBar::setGhostNote(uint timeNumber, uint stringNumber, bool b)
{
	time(timeNumber)->setGhostNote(stringNumber, b);
}

bool TabBar::isGhostNote(uint timeNumber, uint stringNumber) const
{
	return time(timeNumber)->isGhostNote(stringNumber);
}

void TabBar::setTieNote(uint timeNumber, uint stringNumber, bool b)
{
	time(timeNumber)->setTieNote(stringNumber, b);
}

bool TabBar::isTieNote(uint timeNumber, uint stringNumber) const
{
	return time(timeNumber)->isTieNote(stringNumber);
}

void TabBar::setHammerOnPullOff(uint timeNumber, uint stringNumber, bool b)
{
	time(timeNumber)->setHammerOnPullOff(stringNumber, b);
}

bool TabBar::isHammerOnPullOff(uint timeNumber, uint stringNumber) const
{
	return time(timeNumber)->isHammerOnPullOff(stringNumber);
}

void TabBar::setLetRing(uint timeNumber, uint stringNumber, bool b)
{
	time(timeNumber)->setLetRing(stringNumber, b);
}

bool TabBar::isLetRing(uint timeNumber, uint stringNumber) const
{
	return time(timeNumber)->isLetRing(stringNumber);
}

bool TabBar::isDynamic(uint timeNumber, uint stringNumber) const
{
	return time(timeNumber)->isDynamic(stringNumber);
}

bool TabBar::isFingeringLeft(uint timeNumber, uint stringNumber) const
{
	return time(timeNumber)->isFingeringLeft(stringNumber);
}

bool TabBar::isFingeringRight(uint timeNumber, uint stringNumber) const
{
	return time(timeNumber)->isFingeringRight(stringNumber);
}

bool TabBar::isPalmMute(uint timeNumber, uint stringNumber) const
{
	return time(timeNumber)->isPalmMute(stringNumber);
}

bool TabBar::isStaccato(uint timeNumber, uint stringNumber) const
{
	return time(timeNumber)->isStaccato(stringNumber);
}

bool TabBar::isTremoloPicking(uint timeNumber, uint stringNumber) const
{
	return time(timeNumber)->isTremoloPicking(stringNumber);
}

bool TabBar::isHarmonic(uint timeNumber, uint stringNumber) const
{
	return time(timeNumber)->isHarmonic(stringNumber);
}

bool TabBar::isGraceNote(uint timeNumber, uint stringNumber) const
{
	return time(timeNumber)->isGraceNote(stringNumber);
}

TabBend* TabBar::bend(uint timeNumber, uint stringNumber) const
{
	return time(timeNumber)->bend(stringNumber);
}

void TabBar::setBend(uint timeNumber, uint stringNumber, TabBend* bend) const
{
	time(timeNumber)->setBend(stringNumber, bend);
}

bool TabBar::isBend(uint timeNumber, uint stringNumber) const
{
	return time(timeNumber)->isBend(stringNumber);
}

bool TabBar::isTrill(uint timeNumber, uint stringNumber) const
{
	return time(timeNumber)->isTrill(stringNumber);
}

bool TabBar::isRasgueado(uint timeNumber) const
{
	return time(timeNumber)->isRasgueado();
}

bool TabBar::isPickStroke(uint timeNumber) const
{
	return time(timeNumber)->hasPickStroke();
}

bool TabBar::isTremolo(uint timeNumber) const
{
	return time(timeNumber)->hasTremolo();
}

bool TabBar::isTapping(uint timeNumber) const
{
	return time(timeNumber)->isTapping();
}

bool TabBar::isPopping(uint timeNumber) const
{
	return time(timeNumber)->isPopping();
}

bool TabBar::isSlapping(uint timeNumber) const
{
	return time(timeNumber)->isSlapping();
}

bool TabBar::isStroke(uint timeNumber) const
{
	return time(timeNumber)->isStroke();
}

bool TabBar::isVibrato(uint timeNumber) const
{
	return time(timeNumber)->isVibrato();
}

bool TabBar::isFadeIn(uint timeNumber) const
{
	return time(timeNumber)->isFadeIn();
}

bool TabBar::operator==(const TabBar& tabBar) const
{
	bool result = true;
	
	if (mMixer != 0x0  || mixer()->operator!=(*dynamic_cast<const TabMixTableChanges*>(&tabBar)))
		result = false;
	
	if (result == true && (mProperties != 0x0  || properties()->operator!=(*dynamic_cast<const TabBarProperties*>(&tabBar))))
		result = false;
	
	if (result == true && keysig != tabBar.keysig)
		result = false;
		
	if (result == true && mTabTime.size() != tabBar.mTabTime.size())
		result = false;
	
	const_iterator it1 = tabBar.mTabTime.begin();
	const_iterator it2 = this->mTabTime.begin();
	
	for (; result == true && it1 != tabBar.mTabTime.end(); ++it1, ++it2)
		if (*it1 != *it2 || **it1 != **it2)
			result = false;
	
	return result;
}

bool TabBar::operator!=(const TabBar& tabBar) const
{
	return this->operator!=(tabBar);
}
