/***************************************************************************
 * tabsong.h: implementation of TabSong class
 *
 * This file is part of KTabEdit, a KDE tabulature editor
 *
 * copyright (C) 2003-2007 the KTabEdit 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 "tabsong.h"
#include "util/assert.h"

#include "tabproperties.h"
#include "tabtrack.h"

TabSong::TabSong()
: mSongProperties(0x0),
  mTabTrack()
{
	mSongProperties = new TabProperties();
}

TabSong::TabSong(const QString& title, int tempo)
: mSongProperties(0x0),
  mTabTrack()
{
	mSongProperties = new TabProperties();
	
	mSongProperties->setTempo(tempo);
	mSongProperties->setTitle(title);
}

TabSong::~TabSong()
{
	clear();
	
	if (hasProperties() == true)
		delete properties();
}

void TabSong::clone(const TabSong* song)
{
	PRECONDITION( song != 0x0 );
	
	clear();
	
	if (hasProperties() == true)
		delete properties();
	
	mSongProperties = new TabProperties();
	if (song->hasProperties() == true)
		mSongProperties->clone(song->properties());
	
	copyTracks(song);
}

void TabSong::clear()
{
	iterator it(begin());
	
	while (it != end()) {
		delete *it;
		++it;
	}
	
	mTabTrack.clear();
}

void TabSong::copyTracks(const TabSong* tabSong)
{
	const_iterator it(tabSong->begin());
	TabTrack* track;
	
	while (it != tabSong->end()) {
		track = new TabTrack();
		track->clone(*it);
		
		push_back(track);
		++it;
	}
}

void TabSong::push_back(TabTrack* tabTrack)
{
	PRECONDITION(tabTrack != 0x0);
	
	mTabTrack.push_back(tabTrack);
}

void TabSong::push_front(TabTrack* tabTrack)
{
	PRECONDITION(tabTrack != 0x0);
	
	mTabTrack.push_front(tabTrack);
}

void TabSong::removeFirst()
{
	mTabTrack.removeFirst();
}

void TabSong::removeLast()
{
	mTabTrack.removeLast();
}

void TabSong::removeAll(TabTrack* tabTrack)
{
	PRECONDITION(tabTrack != 0x0);
	
	mTabTrack.removeAll(tabTrack);
}

TabTrack* TabSong::at(int i) const
{
	PRECONDITION( i < size() );
	
	POSTCONDITION( mTabTrack.value(i) != 0x0 );
	return mTabTrack.value(i);
}

QList<TabTrack*>::reference TabSong::front()
{
	POSTCONDITION(mTabTrack.front() != 0x0);
	
	return mTabTrack.front();
}

QList<TabTrack*>::const_reference TabSong::front() const
{
	POSTCONDITION(mTabTrack.front() != 0x0);
	
	return mTabTrack.front();
}

QList<TabTrack*>::reference TabSong::back()
{
	POSTCONDITION(mTabTrack.back() != 0x0);
	
	return mTabTrack.back();
}

QList<TabTrack*>::const_reference TabSong::back() const
{
	POSTCONDITION(mTabTrack.back() != 0x0);
	
	return mTabTrack.back();
}

QList<TabTrack*>::iterator TabSong::begin()
{
	return mTabTrack.begin();
}

QList<TabTrack*>::const_iterator TabSong::begin() const
{
	return mTabTrack.begin();
}

QList<TabTrack*>::iterator TabSong::end()
{
	return mTabTrack.end();
}

QList<TabTrack*>::const_iterator TabSong::end() const
{
	return mTabTrack.end();
}

int TabSong::size() const
{
	return mTabTrack.size();
}

int TabSong::positionOfTrack(const TabTrack* track) const
{
	PRECONDITION( track != 0x0 );
	
	const_iterator it;
	int result = 0;
	
	for (it = begin(); it != end() && *it != track; ++it)
		result = result + 1;
	
	POSTCONDITION( it != end() );
	
	return result;
}

uint TabSong::maximumOfBars() const
{
	const_iterator it;
	uint result = 0;
	
	for (it = begin(); it != end(); ++it) {
		const TabTrack* tabTrack = *it;
		
		if (result < tabTrack->size())
			result = tabTrack->size();
	}
	
	return result;
}

void TabSong::setProperties(TabProperties* properties)
{
	PRECONDITION( properties != 0x0 );
	
	if (mSongProperties != 0x0)
		delete mSongProperties;
	
	mSongProperties = properties;
}

TabProperties* TabSong::properties() const
{
	POSTCONDITION( mSongProperties != 0x0 );
	
	return mSongProperties;
}

bool TabSong::hasProperties() const
{
	return (mSongProperties != 0x0);
}

bool TabSong::isDrumTrack() const
{
	const_iterator it(begin());
	int n = 1;
	
	while (it != end()) {
		const TabTrack& tabTrack = **it;
		
		if (tabTrack.mode() == DrumTab)
			return true;
		
		n++;
		++it;
	}
	
	return false;
}

int TabSong::drumTrack() const
{
	const_iterator it(begin());
	int n = 1;
	
	while (it != end()) {
		const TabTrack& tabTrack = **it;
		
		if (tabTrack.mode() == DrumTab)
			return n;
		
		n++;
		++it;
	}
	
	return -1;
}

TabTrack* TabSong::at(uint track) const
{
	PRECONDITION(static_cast<long>(track) < size());
	
	const_iterator it(begin());
	uint i = 0;
	
	while (it != end() && i < track) {
		i++;
		++it;
	}
	
	return *it;
}

void TabSong::setTitle(const QString &s)
{
	properties()->setTitle(s);
}

QString TabSong::title() const
{
	return properties()->title();
}

void TabSong::setSubTitle(const QString &s)
{
	properties()->setSubTitle(s);
}

QString TabSong::subTitle() const
{
	return properties()->subTitle();
}

void TabSong::setArtist(const QString &s)
{
	properties()->setArtist(s);
}

QString TabSong::artist() const
{
	return properties()->artist();
}

void TabSong::setAlbum(const QString &s)
{
	properties()->setAlbum(s);
}

QString TabSong::album() const
{
	return properties()->album();
}

void TabSong::setAuthor(const QString &s)
{
	properties()->setAuthor(s);
}

QString TabSong::author() const
{
	return properties()->author();
}

void TabSong::setCopyright(const QString &s)
{
	properties()->setCopyright(s);
}

QString TabSong::copyright() const
{
	return properties()->copyright();
}

void TabSong::setTranscriber(const QString &s)
{
	properties()->setTranscriber(s);
}

QString TabSong::transcriber() const
{
	return properties()->transcriber();
}

void TabSong::setInstructions(const QString &s)
{
	properties()->setInstructions(s);
}

QString TabSong::instructions() const
{
	return properties()->instructions();
}

void TabSong::setComments(const QString &s)
{
	properties()->setComments(s);
}

QString TabSong::comments() const
{
	return properties()->comments();
}

void TabSong::setShuffle(bool i)
{
	properties()->setShuffle(i);
}

bool TabSong::isShuffle() const
{
	return properties()->isShuffle();
}

void TabSong::setTempo(unsigned int i)
{
	properties()->setTempo(i);
}

unsigned int TabSong::tempo() const
{
	return properties()->tempo();
}

void TabSong::setOctave(int i)
{
	properties()->setOctave(i);
}

int TabSong::octave() const
{
	return properties()->octave();
}

void TabSong::setSongKey(SongKey* songKey)
{
	properties()->setSongKey(songKey);
}

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

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

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

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

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


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

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

void TabSong::setTabLyrics(TabLyrics* lyrics)
{
	properties()->setTabLyrics(lyrics);
}

TabLyrics* TabSong::tabLyrics() const
{
	return properties()->tabLyrics();
}

void TabSong::setLyricsTrack(int i)
{
	properties()->setLyricsTrack(i);
}

int TabSong::lyricsTrack() const
{
	return properties()->lyricsTrack();
}

void TabSong::setLyricsMeasure(int i, int j)
{
	properties()->setLyricsMeasure(i, j);
}

int TabSong::lyricsMeasure(int i) const
{
	return properties()->lyricsMeasure(i);
}

void TabSong::setLyrics(int i, const QString& s)
{
	properties()->setLyrics(i, s);
}

QString TabSong::lyrics(int i) const
{
	return properties()->lyrics(i);
}

bool TabSong::compareTracks(const TabSong& tabSong) const
{
	bool result = true;
	bool comp;
	const_iterator it = begin();
	
	while (it != end() && result == true) {
		const_iterator tabsongIt = tabSong.begin();
		comp = false;
		
		while (tabsongIt != end() && comp == false) {
			comp = *tabsongIt != *it;
			
			++tabsongIt;
		}
		
		result = comp;
		++it;
	}
	
	return result;
}

bool TabSong::operator==(const TabSong& tabSong) const
{
	bool listOp = *dynamic_cast< const QList<TabTrack*>* >(this) == *dynamic_cast< const QList<TabTrack*>* >(&tabSong);
	
	return ((listOp == true && mSongProperties == tabSong.mSongProperties) || 
			(listOp == false && mSongProperties == tabSong.mSongProperties && 
			size() != tabSong.size() && compareTracks(tabSong) == true));
}

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