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

#include <QDir>
#include <QDomDocument>
#include <QFile>
#include <QtDebug>
#include <KZip>

#include "tablature/tabbeateffects.h"
#include "tablature/tabchord.h"
#include "tablature/tabduration.h"

#include "tablature/tabbend.h"
#include "tablature/tabdynamic.h"

#include "tablature/tabgracenotetransition.h"
#include "tablature/tabgracenote.h"

#include "tablature/tabharmonic.h"
#include "tablature/tabslide.h"
#include "tablature/tabtrill.h"
#include "tablature/tabnoteeffect.h"

#include "tablature/tabnote.h"

#include "tablature/songkey.h"
#include "tablature/timesignature.h"

#include "tablature/tabmixtablechanges.h"
#include "tablature/tabtimes.h"
#include "tablature/tabbarproperties.h"

#include "tablature/tabbar.h"

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

#include "tablature/tabsong.h"

#include "tablature/trackmidiproperties.h"
#include "tablature/trackproperties.h"

#include "tablature/tabtrack.h"

const TabTimeEffect KGuitarTab::msNoBeatEffect;
const TabBend KGuitarTab::msNoBendEffect;

KGuitarTab::KGuitarTab()
{
}

KGuitarTab::~KGuitarTab()
{
}

bool KGuitarTab::loadFile(const QString& fileName)
{
	KZip zipFile(fileName);
	QFile file(fileName);
	QDomDocument doc("KGuitar");
	QDomNode node;
	TabSong* tabSong = new TabSong("", 120);
	
	if (zipFile.open(IO_ReadOnly) == false) {
		qDebug() << "[KGuitarTab::loadFile] zipFile.open(IO_ReadOnly) == false\n";
		throw std::exception();
	} else {
		QDir homeDir(QDir::home());
		QFileInfo info(fileName);
		const KArchiveDirectory* dir = zipFile.directory();
		const KArchiveEntry* entry = dir->entry('/' + info.fileName() + ".xml");
		
		// Create ktabedit dir where the the file is 
		// unzip, the file is deleted after the parsing.
		//
		if (!homeDir.cd(".ktabedit"))
			if (homeDir.mkdir(".ktabedit") == false)
				throw "Unable to create .ktabedit directory";
		else {
			// Clean up the dir
			//
			QStringList removeList = homeDir.entryList("*.kg.xml");
			
			for (int i = 0; i < removeList.count(); i++)
				homeDir.remove(removeList[i]);
		}
		
		if (entry) {
			dir->copyTo(homeDir.absPath() + '/');
			QFile file(homeDir.absPath() + '/' + info.fileName() + ".xml");
			
			QDomDocument doc("KTabEdit");
			QDomNode node;
			
			if (file.open(IO_ReadOnly) == false)
				throw "Can not open the file";
			
			if (doc.setContent(&file) == false) {
				file.close();
				file.remove();
				
				throw "Can not set the content of the file in the QDomDocument class";
			}
			
			file.close();
			
			if (!file.remove())
				qDebug() << "Impossible to delete the xml file in " << file.name() << " \n";
			
			doc.documentElement();
			
			node = doc.firstChild();
			while (node.isNull() == false) {
				// Find the kguitar header !!
				//
				if (node.isElement()) {
					QDomElement element = node.toElement();
					
					if ((element.tagName() == "KTabEdit") && (element.attribute("version") == "0.5")) {
						readSongInformation(element.firstChild(), tabSong);
					} else {
						throw "Bad XML file\n";
					}
				}
				
				node = node.nextSibling();
			}

		} else {
			QString err("Do not find /" + info.fileName() + ".xml" + '\n');
			
			throw err;
		}
		
	}
	
	setTabSong(tabSong);
	
	return true;
}

void KGuitarTab::readSongInformation(const QDomNode& domNode, TabSong* tabSong)
{
	QDomNode node = domNode;
	
	while (node.isNull() == false) {
		if (node.isElement()) {
			QDomElement element = node.toElement();
			
			if (element.tagName() == "SongProperties")
				tabSong->setProperties(readSongProperties(element.firstChild()));
			else if (element.tagName() == "Tracks")
				readTrackInformation(element.firstChild(), tabSong);
		}
		
		node = node.nextSibling();
	}
}

bool KGuitarTab::saveFile(const QString& fileName, const TabSong& tabSong)
{
	TabSong::const_iterator it(tabSong.begin());
	QFile file(fileName + ".xml");
	QString string;
	const TabBar* bar;
	const TabTime* time;
	unsigned int countTrack = 0;
	
	if (file.open(IO_WriteOnly) == false)
		return false;
	
	QTextStream stream(&file);
	
	stream << "<?xml version='1.0' encoding='UTF-8'?>" << "\n";
	stream << "<KTabEdit version='0.5'>" << "\n";
	
	stream << "\t" << "<SongProperties>" << "\n";
	writeSongInformation("\t\t", stream, tabSong);
	stream << "\t" << "</SongProperties>" << "\n";
	
	stream << "\t" << "<Tracks>" << "\n";
	
	while(it != tabSong.end()) {
		const TabTrack& track = **it;
		++it;
		
		stream << "\t\t" << "<TrackProperties>" << "\n";
		writeTrackInformation("\t\t\t", stream, track);
		stream << "\t\t" << "</TrackProperties>" << "\n";
		
		stream << "\t\t" << "<TrackSong>" << "\n";
		
		for (uint j = 0; j < track.size(); j++) {
			stream << "\t\t\t" << "<Bar>" << "\n";
			
			bar = track.bar(j);
			
			writeBarInformation("\t\t\t\t", stream, *bar);
			
			for (uint k = 0; k < bar->size(); k++) {
				time = bar->time(k);
				
				stream << "\t\t\t\t" << "<Time>" << "\n";
				
				writeTimesInformation("\t\t\t\t\t", stream, *time);
				
				if (!time->isRest()) {
					
					for (uint l = 0; l < track.nbStrings(); l++) {
						QString temp;
						
						if (!time->string(l)->isEmpty()) {
							stream << "\t\t\t\t\t" << "<Note chord=\"" << temp.setNum(l) << "\">" << "\n";
							
							writeNoteInformation("\t\t\t\t\t\t", stream, *time->string(l));
							
							stream << "\t\t\t\t\t" << "</Note>" << "\n";
						}
					}
				}
				
				stream << "\t\t\t\t" << "</Time>" << "\n";
			}
			
			stream << "\t\t\t" << "</Bar>" << "\n";
		}
		stream << "\t\t" << "</TrackSong>" << "\n";
		
		countTrack++;
	}
	stream << "\t" << "</Tracks>" << "\n";
	
	stream << "</KTabEdit>" << "\n";
	
	file.close();
	
	file.open(IO_ReadOnly);
	
	QFileInfo info(file);
	
	KZip fileZip(fileName);
	
	char* buffer = new char[info.size()];
	QDataStream fstream(&file);
	fstream.readRawBytes(reinterpret_cast<char *>(buffer),info.size());
	
	file.remove();
	
	fileZip.setCompression(KZip::DeflateCompression);
	fileZip.open(IO_WriteOnly);
	if (!fileZip.writeFile(info.fileName(), info.owner(), info.group(), buffer, info.size()))
		return false;
	
	fileZip.close();
	
	delete buffer;
	
	return true;
}

void KGuitarTab::writeSongInformation(const QString& fill, QTextStream& stream, const TabSong& tabSong)
{
	stream << fill << "<Title>" << tabSong.title().utf8() << "</Title>" << "\n";
	stream << fill << "<SubTitle>" << tabSong.subTitle().utf8() << "</SubTitle>" << "\n";
	stream << fill << "<Artist>" << tabSong.artist().utf8() << "</Artist>" << "\n";
	stream << fill << "<Album>" << tabSong.album().utf8() << "</Album>" << "\n";
	stream << fill << "<Author>" << tabSong.author().utf8() << "</Author>" << "\n";
	stream << fill << "<Copyright>" << tabSong.copyright().utf8() << "</Copyright>" << "\n";
	stream << fill << "<Transcriber>" << tabSong.transcriber().utf8() << "</Transcriber>" << "\n";
	stream << fill << "<Instructions>" << tabSong.instructions().utf8() << "</Instructions>" << "\n";
	stream << fill << "<Comments>" << tabSong.comments().utf8() << "</Comments>" << "\n";
	stream << fill << "<Shuffle>" << tabSong.isShuffle() << "</Shuffle>" << "\n";
	stream << fill << "<Tempo>" << tabSong.tempo() << "</Tempo>" << "\n";
	stream << fill << "<Octave>" << tabSong.octave() << "</Octave>" << "\n";
	stream << fill << "<Key>" << tabSong.key() << "</Key>" << "\n";
	stream << fill << "<Minor>" << tabSong.isMinor() << "</Minor>" << "\n";
	
	stream << fill << "<LyricsProperties>\n";
	writeLyricsInformation(fill + '\t', stream, *tabSong.tabLyrics());
	stream << fill << "</LyricsProperties>\n";
}

TabProperties* KGuitarTab::readSongProperties(QDomNode node)
{
	TabProperties* tabProperties = new TabProperties();
	
	while (node.isNull() == false) {
		if (node.isElement()) {
			QDomElement element = node.toElement();
			
			if (element.tagName() == "Title")
				tabProperties->setTitle(element.text());
			else if (element.tagName() == "SubTitle")
				tabProperties->setSubTitle(element.text());
			else if (element.tagName() == "Artist")
				tabProperties->setArtist(element.text());
			else if (element.tagName() == "Album")
				tabProperties->setAlbum(element.text());
			else if (element.tagName() == "Author")
				tabProperties->setAuthor(element.text());
			else if (element.tagName() == "Copyright")
				tabProperties->setCopyright(element.text());
			else if (element.tagName() == "Transcriber")
				tabProperties->setTranscriber(element.text());
			else if (element.tagName() == "Instructions")
				tabProperties->setInstructions(element.text());
			else if (element.tagName() == "Comments")
				tabProperties->setComments(element.text());
			else if (element.tagName() == "Shuffle")
				tabProperties->setShuffle(element.text().toUInt());
			else if (element.tagName() == "Tempo")
				tabProperties->setTempo(element.text().toUInt());
			else if (element.tagName() == "Octave")
				tabProperties->setOctave(element.text().toUInt());
			else if (element.tagName() == "Key")
				tabProperties->setKey(element.text().toUInt());
			else if (element.tagName() == "Minor")
				tabProperties->setMinor(element.text().toUInt());
			else if (element.tagName() == "LyricsProperties")
				tabProperties->setTabLyrics(readLyricsProperties(element.firstChild()));
		}
		
		node = node.nextSibling();
	}
	
	return tabProperties;
}

void KGuitarTab::writeLyricsInformation(const QString& fill, QTextStream& stream, const TabLyrics& tabLyrics)
{
	stream << fill << "<Track>" << tabLyrics.lyricsTrack() << "</Track>" << "\n";
	
	for (int i = 0; i < 5; i++)
		stream << fill << "<Measure number=\"" << i << "\">" << tabLyrics.lyricsMeasure(i) << "</Measure>" << "\n";
	
	for (int i = 0; i < 5; i++)
		stream << fill << "<Lyrics number=\"" << i << "\">" << tabLyrics.lyrics(i).utf8() << "</Lyrics>" << "\n";
}

TabLyrics* KGuitarTab::readLyricsProperties(QDomNode node)
{
	uint measure = 0, lyrics = 0;
	TabLyrics* tabLyrics = new TabLyrics();
	
	while (node.isNull() == false) {
		if (node.isElement()) {
			QDomElement element = node.toElement();
			
			if (element.tagName() == "Track")
				tabLyrics->setLyricsTrack(element.text().toUInt());
			else if (element.tagName() == "Measure") {
				tabLyrics->setLyricsMeasure(measure, element.text().toUInt());
				measure++;
			} else if (element.tagName() == "Lyrics") {
				tabLyrics->setLyrics(lyrics, element.text());
				lyrics++;
			}
		}
		
		node = node.nextSibling();
	}
	
	return tabLyrics;
}

void KGuitarTab::writeTrackInformation(const QString& fill, QTextStream& stream, const TabTrack& tabTrack)
{
	stream << fill << "<Mode>" << tabTrack.mode() << "</Mode>" << "\n";
	stream << fill << "<Name>" << tabTrack.name().utf8() << "</Name>" << "\n";
	stream << fill << "<Color>" << tabTrack.color().name().utf8() << "</Color>" << "\n";
	stream << fill << "<NbStrings>" << tabTrack.nbStrings() << "</NbStrings>" << "\n";
	stream << fill << "<NbFrets>" << tabTrack.nbFrets() << "</NbFrets>" << "\n";
	
	for (int i = 0; i < tabTrack.nbStrings(); i++)
		stream << fill << "<Tune fret=\"" << i << "\">" << tabTrack.tune(i) << "</Tune>" << "\n";
	
	stream << fill << "<Capo>" << tabTrack.capo() << "</Capo>" << "\n";
	stream << fill << "<TimeSignature numerator=\"" << tabTrack.numerator() 
				   << "\" denominator=\"" << tabTrack.denominator() << "\">" <<  "</TimeSignature>" << "\n";
	stream << fill << "<Patch>" << tabTrack.patch() << "</Patch>" << "\n";
	stream << fill << "<Channel>" << tabTrack.channel() << "</Channel>" << "\n";
	stream << fill << "<ChannelEffects>" << tabTrack.channelEffects() << "</ChannelEffects>" << "\n";
	stream << fill << "<MidiPort>" << tabTrack.midiPort() << "</MidiPort>" << "\n";
	stream << fill << "<Bank>" << tabTrack.bank() << "</Bank>" << "\n";
	stream << fill << "<Volume>" << tabTrack.volume() << "</Volume>" << "\n";
	stream << fill << "<Balance>" << tabTrack.balance() << "</Balance>" << "\n";
	stream << fill << "<Chorus>" << tabTrack.chorus() << "</Chorus>" << "\n";
	stream << fill << "<Reverb>" << tabTrack.reverb() << "</Reverb>" << "\n";
	stream << fill << "<Phaser>" << tabTrack.phaser() << "</Phaser>" << "\n";
	stream << fill << "<Tremolo>" << tabTrack.tremolo() << "</Tremolo>" << "\n";
}

void KGuitarTab::readTrackInformation(QDomNode node, TabSong* tabSong)
{
	TabTrack tabTrack;
	
	while (node.isNull() == false) {
		if (node.isElement()) {
			QDomElement element = node.toElement();
			
			if (element.tagName() == "TrackProperties") {
				tabTrack.setProperties(readTrackProperties(element.firstChild()));
			} else if (element.tagName() == "TrackSong") {
				readTrackSong(element.firstChild(), &tabTrack);
				
				TabTrack* track = new TabTrack();
				track->clone(&tabTrack);
				
				tabSong->push_front(track);
			}
		}
		
		node = node.nextSibling();
	}
}

TrackProperties* KGuitarTab::readTrackProperties(QDomNode node)
{
	uint tune = 0;
	TrackProperties* trackProperties = new TrackProperties;
	
	while (node.isNull() == false) {
		if (node.isElement()) {
			QDomElement element = node.toElement();
			
			if (element.tagName() == "Mode")
				trackProperties->setMode(static_cast<TrackMode>(element.text().toUInt()));
			else if (element.tagName() == "Name")
				trackProperties->setName(element.text());
			else if (element.tagName() == "Color")
				trackProperties->setColor(element.text());
			else if (element.tagName() == "NbStrings")
				trackProperties->setNbStrings(element.text().toUInt());
			else if (element.tagName() == "NbFrets")
				trackProperties->setNbFrets(element.text().toUInt());
			else if (element.tagName() == "Tune") {
				trackProperties->setTune(tune, element.text().toUInt());
				tune++;
			} else if (element.tagName() == "TimeSignature" && element.hasAttribute("numerator") && element.hasAttribute("denominator")) {
				trackProperties->setNumerator(element.attribute("numerator").toUInt());
				trackProperties->setDenominator(element.attribute("denominator").toUInt());
			} else if (element.tagName() == "Patch")
				trackProperties->setPatch(element.text().toUInt());
			else if (element.tagName() == "Channel")
				trackProperties->setChannel(element.text().toUInt());
			else if (element.tagName() == "ChannelEffects")
				trackProperties->setChannelEffects(element.text().toUInt());
			else if (element.tagName() == "MidiPort")
				trackProperties->setMidiPort(element.text().toUInt());
			else if (element.tagName() == "Bank")
				trackProperties->setBank(element.text().toUInt());
			else if (element.tagName() == "Volume")
				trackProperties->setVolume(element.text().toUInt());
			else if (element.tagName() == "balance")
				trackProperties->setBalance(element.text().toUInt());
			else if (element.tagName() == "Chorus")
				trackProperties->setChorus(element.text().toUInt());
			else if (element.tagName() == "Reverb")
				trackProperties->setReverb(element.text().toUInt());
			else if (element.tagName() == "Phaser")
				trackProperties->setPhaser(element.text().toUInt());
			else if (element.tagName() == "Tremolo")
				trackProperties->setTremolo(element.text().toUInt());
		}
		
		node = node.nextSibling();
	}
	
	return trackProperties;
}

void KGuitarTab::readTrackSong(QDomNode node, TabTrack* tabTrack)
{
	int i = 0;
	
	while (node.isNull() == false) {
		if (node.isElement()) {
			QDomElement element = node.toElement();
			
			if (element.tagName() == "Bar") {
				tabTrack->addBar(readBar(element.firstChild(), i));
				i++;
			}
		}
		
		node = node.nextSibling();
	}
}

void KGuitarTab::writeBarInformation(const QString& fill, QTextStream& stream, const TabBar& tabBar)
{
	stream << fill << "<TimeSignature numerator=\"" << tabBar.numerator() << "\" denominator=\"" << tabBar.denominator() << "\">" <<  "</TimeSignature>" << "\n";
	stream << fill << "<KeySignature>" << tabBar.keySignature() << "</KeySignature>" << "\n";
	stream << fill << "<Color>" << tabBar.color().name().utf8() << "</Color>" << "\n";
	stream << fill << "<Marker>" << tabBar.marker().utf8() << "</Marker>" << "\n";
	
	if (tabBar.isRepeatBar())
		stream << fill << "<RepeatBar>" << tabBar.isRepeatBar() << "</RepeatBar>" << "\n";
	
	if (tabBar.isCloseBar())
		stream << fill << "<CloseBar>" << tabBar.isCloseBar() << "</CloseBar>" << "\n";
	
	if (tabBar.isAltBar())
		stream << fill << "<AltBar>" << tabBar.isAltBar() << "</AltBar>" << "\n";
	
	if (tabBar.isRepeatStart())
		stream << fill << "<RepeatStart>" << tabBar.isRepeatStart() << "</RepeatStart>" << "\n";
	
	if (tabBar.repetitions())
		stream << fill << "<Repetitions>" << tabBar.repetitions() << "</Repetitions>" << "\n";
	
	if (tabBar.isAlternateEndings())
		stream << fill << "<AlternateEndings>" << tabBar.isAlternateEndings() << "</AlternateEndings>" << "\n";
	
	if (tabBar.isDoubleBar())
		stream << fill << "<DoubleBar>" << tabBar.isDoubleBar() << "</DoubleBar>" << "\n";
	
	stream << fill << "<Key>" << tabBar.key() << "</Key>" << "\n";
	stream << fill << "<Minor>" << tabBar.isMinor() << "</Minor>" << "\n";
}

TabBar* KGuitarTab::readBar(QDomNode node, uchar bar)
{
	TabBar* tabBar = new TabBar(bar);
	int i = 0;
	
	while (node.isNull() == false) {
		if (node.isElement()) {
			QDomElement element = node.toElement();
			
			if (element.tagName() == "TimeSignature" && element.hasAttribute("numerator") && element.hasAttribute("denominator")) {
				tabBar->setNumerator(element.attribute("numerator").toUInt());
				tabBar->setDenominator(element.attribute("denominator").toUInt());
			} else if (element.tagName() == "KeySignature")
				tabBar->setKeySignature(element.text().toUInt());
			else if (element.tagName() == "Color")
				tabBar->setColor(element.text());
			else if (element.tagName() == "Marker")
				tabBar->setMarker(element.text());
			else if (element.tagName() == "RepeatStart")
				tabBar->setRepeatStart(element.text().toUInt());
			else if (element.tagName() == "Repetitions")
				tabBar->setRepetitions(element.text().toUInt());
			else if (element.tagName() == "AlternateEndings")
				tabBar->setAlternateEndings(element.text().toUInt());
			else if (element.tagName() == "DoubleBar")
				tabBar->setDoubleBar(element.text().toUInt());
			else if (element.tagName() == "Key")
				tabBar->setKey(element.text().toUInt());
			else if (element.tagName() == "KeySignature")
				tabBar->setMinor(element.text().toUInt());
			else if (element.tagName() == "Time") {
				tabBar->insertTime(readTime(element.firstChild(), i));
				i++;
			}
		}
		
		node = node.nextSibling();
	}
	
	return tabBar;
}

void KGuitarTab::writeTimesInformation(const QString& fill, QTextStream& stream, const TabTime& tabTimes)
{
	stream << fill << "<Duration>" << tabTimes.duration() << "</Duration>" << "\n";
	
	if (tabTimes.isRest())
		stream << fill << "<Rest>" << tabTimes.isRest() << "</Rest>" << "\n";
	
	if (tabTimes.isDotted())
		stream << fill << "<Dotted>" << tabTimes.isDotted() << "</Dotted>" << "\n";
	
	if (tabTimes.nTuplet())
		stream << fill << "<NTuplet>" << tabTimes.nTuplet() << "</NTuplet>" << "\n";
	
	if (tabTimes.text().length())
		stream << fill << "<Text>" << tabTimes.text().utf8() << "</Text>" << "\n";
	
	if (*tabTimes.effect() != msNoBeatEffect) {
		stream << fill << "<Effect>\n";
		writeTimesEffectInformation(fill + '\t', stream, *tabTimes.effect());
		stream << fill << "</Effect>\n";
		
		if (tabTimes.bendType() != TabBend::NoneBend) {
			stream << fill << "<Bend>\n";
			writeBendInformation(fill + '\t', stream, *tabTimes.bend());
			stream << fill << "</Bend>\n";
		}
	}
	
	if (tabTimes.hasChord() == false)
		return ;
	
	stream << fill << "<Chord>\n";
	writeChordInformation(fill + '\t', stream, *tabTimes.tabChord());
	stream << fill << "</Chord>\n";
}

TabTime* KGuitarTab::readTime(QDomNode node, uchar time)
{
	TabTime* tabTime = new TabTime(time);
	
	while (node.isNull() == false) {
		if (node.isElement()) {
			QDomElement element = node.toElement();
			
			if (element.tagName() == "Duration")
				tabTime->setDuration(static_cast<Duration>(element.text().toUInt()));
			else if (element.tagName() == "Rest")
				tabTime->setRest(element.text().toUInt());
			else if (element.tagName() == "Dotted")
				tabTime->setDotted(element.text().toUInt());
			else if (element.tagName() == "NTuplet")
				tabTime->setNTuplet(element.text().toUInt());
			else if (element.tagName() == "Text")
				tabTime->setText(element.text());
			else if (element.tagName() == "Effect")
				tabTime->setEffect(readTimesEffect(element.firstChild()));
			else if (element.tagName() == "Bend")
				tabTime->setBend(readBendEffect(element.firstChild()));
			else if (element.tagName() == "Chord")
				tabTime->setChord(readChordEffect(element.firstChild()));
			else if (element.tagName() == "Note" && element.hasAttribute("chord"))
				tabTime->setString(element.attribute("chord").toUInt(), readNote(element.firstChild(), element.attribute("chord").toUInt()));
		}
		
		node = node.nextSibling();
	}
	
	return tabTime;
}

void KGuitarTab::writeTimesEffectInformation(const QString& fill, QTextStream& stream, const TabTimeEffect& timesEffect)
{
	if (timesEffect.isRasgueado())
		stream << fill << "<Rasgueado>" << timesEffect.isRasgueado() << "</Rasgueado>" << "\n";
	
	if (timesEffect.pickstroke() != NonePickStroke)
		stream << fill << "<Pickstroke>" << timesEffect.pickstroke() << "</Pickstroke>" << "\n";
	
	if (timesEffect.tremolo())
		stream << fill << "<Tremolo>" << timesEffect.tremolo() << "</Tremolo>" << "\n";
	
	if (timesEffect.isTapping())
		stream << fill << "<Tapping>" << timesEffect.isTapping() << "</Tapping>" << "\n";
	
	if (timesEffect.isPopping())
		stream << fill << "<Popping>" << timesEffect.isPopping() << "</Popping>" << "\n";
	
	if (timesEffect.isSlapping())
		stream << fill << "<Slapping>" << timesEffect.isSlapping() << "</Slapping>" << "\n";
	
	if (timesEffect.isStroke())
		stream << fill << "<Stroke>" << timesEffect.isStroke() << "</Stroke>" << "\n";
	
	if (timesEffect.upStroke())
		stream << fill << "<UpStroke>" << timesEffect.upStroke() << "</UpStroke>" << "\n";
	
	if (timesEffect.downStroke())
		stream << fill << "<DownStroke>" << timesEffect.downStroke() << "</DownStroke>" << "\n";
	
	if (timesEffect.isVibrato())
		stream << fill << "<Vibrato>" << timesEffect.isVibrato() << "</Vibrato>" << "\n";
	
	if (timesEffect.isWideVibrato())
		stream << fill << "<WideVibrato>" << timesEffect.isWideVibrato() << "</WideVibrato>" << "\n";
	
	if (timesEffect.isNaturalHarmonic())
		stream << fill << "<NaturalHarmonic>" << timesEffect.isNaturalHarmonic() << "</NaturalHarmonic>" << "\n";
	
	if (timesEffect.isArtificialHarmonic())
		stream << fill << "<ArtificialHarmonic>" << timesEffect.isArtificialHarmonic() << "</ArtificialHarmonic>" << "\n";
	
	if (timesEffect.isFadeIn())
		stream << fill << "<FadeIn>" << timesEffect.isFadeIn() << "</FadeIn>" << "\n";
}

TabTimeEffect* KGuitarTab::readTimesEffect(QDomNode node)
{
	TabTimeEffect* tabEffect = new TabTimeEffect();
	
	while (node.isNull() == false) {
		if (node.isElement()) {
			QDomElement element = node.toElement();
			
			if (element.tagName() == "Rasgueado")
				tabEffect->setRasgueado(element.text().toUInt());
			else if (element.tagName() == "PickStroke")
				tabEffect->setPickStroke(static_cast<PickStroke>(element.text().toUInt()));
			else if (element.tagName() == "Tremolo")
				tabEffect->setTremolo(element.text().toUInt());
			else if (element.tagName() == "Tapping")
				tabEffect->setTapping(element.text().toUInt());
			else if (element.tagName() == "Popping")
				tabEffect->setPopping(element.text().toUInt());
			else if (element.tagName() == "Slapping")
				tabEffect->setSlapping(element.text().toUInt());
			else if (element.tagName() == "Stroke")
				tabEffect->setStroke(element.text().toUInt());
			else if (element.tagName() == "UpStroke")
				tabEffect->setUpStroke(element.text().toUInt());
			else if (element.tagName() == "DownStroke")
				tabEffect->setDownStroke(element.text().toUInt());
			else if (element.tagName() == "Vibrato")
				tabEffect->setVibrato(element.text().toUInt());
			else if (element.tagName() == "WideVibrato")
				tabEffect->setWideVibrato(element.text().toUInt());
			else if (element.tagName() == "NaturalHarmonic")
				tabEffect->setNaturalHarmonic(element.text().toUInt());
			else if (element.tagName() == "ArtificialHarmonic")
				tabEffect->setArtificialHarmonic(element.text().toUInt());
			else if (element.tagName() == "FadeIn")
				tabEffect->setFadeIn(element.text().toUInt());
		}
		
		node = node.nextSibling();
	}
	
	return tabEffect;
}

void KGuitarTab::writeBendInformation(const QString& fill, QTextStream& stream, const TabBend& tabBend)
{
	stream << fill << "<Type>" << tabBend.bendType() << "</Type>" << "\n";
	stream << fill << "<Value>" << tabBend.bendValue() << "</Value>" << "\n";
	
	for (int i = 0; i < tabBend.sizeOfBendPoints(); i++) {
		stream << fill << "<Point>\n";
		stream << fill << "\t" << "<Position>" << tabBend.bendPoint(i)->position() << "</Position>" << "\n";
		stream << fill << "\t" << "<Height>" << tabBend.bendPoint(i)->height() << "</Height>" << "\n";
		stream << fill << "\t" << "<Vibrato>" << tabBend.bendPoint(i)->tabVibrato() << "</Vibrato>" << "\n";
		stream << fill << "</Point>\n";
	}
}

TabBend* KGuitarTab::readBendEffect(QDomNode node)
{
	TabBend* tabBend = new TabBend();
	
	while (node.isNull() == false) {
		if (node.isElement()) {
			QDomElement element = node.toElement();
			
			if (element.tagName() == "Type")
				tabBend->setBendType(static_cast<TabBend::BendType>(element.text().toUInt()));
			else if (element.tagName() == "Value")
				tabBend->setBendValue(element.text().toUInt());
			else if (element.tagName() == "Point")
				tabBend->addBendPoint(readPointBend(element.firstChild()));
		}
		
		node = node.nextSibling();
	}
	
	return tabBend;
}

TabBendPoint* KGuitarTab::readPointBend(QDomNode node)
{
	TabBendPoint* point = new TabBendPoint();
	
	while (node.isNull() == false) {
		if (node.isElement()) {
			QDomElement element = node.toElement();
			
			if (element.tagName() == "Position")
				point->setPosition(element.text().toUInt());
			else if (element.tagName() == "Height")
				point->setHeight(element.text().toUInt());
			else if (element.tagName() == "Vibrato")
				point->setVibrato(static_cast<TabVibrato>(element.text().toUInt()));
		}
		
		node = node.nextSibling();
	}
	
	return point;
}

void KGuitarTab::writeChordInformation(const QString& fill, QTextStream& stream, const TabChord& tabChord)
{
	stream << fill << "<Name>" << tabChord.name().utf8() << "</Name>" << "\n";
	stream << fill << "<Sharp>" << tabChord.isSharp() << "</Sharp>" << "\n";
	stream << fill << "<Root>" << tabChord.root() << "</Root>" << "\n";
	stream << fill << "<Type>" << tabChord.type() << "</Type>" << "\n";
	stream << fill << "<NineElevenThirteen>" << tabChord.nineElevenThirteen() << "</NineElevenThirteen>" << "\n";
	stream << fill << "<Bass>" << tabChord.bass() << "</Bass>" << "\n";
	stream << fill << "<AugmentedDiminished>" << tabChord.augmentedDiminished() << "</AugmentedDiminished>" << "\n";
	stream << fill << "<AddedNote>" << tabChord.addedNote() << "</AddedNote>" << "\n";
	stream << fill << "<TonalityFive>" << tabChord.tonalityFive() << "</TonalityFive>" << "\n";
	stream << fill << "<TonalityNine>" << tabChord.tonalityNine() << "</TonalityNine>" << "\n";
	stream << fill << "<TonalityEleven>" << tabChord.tonalityEleven() << "</TonalityEleven>" << "\n";
	stream << fill << "<BaseFret>" << tabChord.baseFret() << "</BaseFret>" << "\n";
	
	for (int i = 0; i < 6; i++) {
		stream << fill << "<Fret chord=\"" << i << "\">" << tabChord.fret(i) << "</Fret>" << "\n";
	}
	
	stream << fill << "<NumBarres>" << tabChord.numBarres() << "</NumBarres>" << "\n";
	
	for (int i = 0; i < 5; i++) {
		stream << fill << "<BarreFret chord=\"" << i << "\">" << tabChord.barreFret(i) << "</BarreFret>" << "\n";
	}
	
	for (int i = 0; i < 5; i++) {
		stream << fill << "<BarreStart chord=\"" << i << "\">" << tabChord.barreStart(i) << "</BarreStart>" << "\n";
	}
	
	for (int i = 0; i < 5; i++) {
		stream << fill << "<BarreEnd chord=\"" << i << "\">" << tabChord.barreEnd(i) << "</BarreEnd>" << "\n";
	}
	
	for (int i = 0; i < 7; i++) {
		stream << fill << "<Fingering chord=\"" << i << "\">" << tabChord.fingering(i) << "</Fingering>" << "\n";
	}
	
	stream << fill << "<Show>" << tabChord.isShowDiagram() << "</Show>" << "\n";
}

TabChord* KGuitarTab::readChordEffect(QDomNode node)
{
	QString temp;
	TabChord* tabChord = new TabChord();
	
	while (node.isNull() == false) {
		if (node.isElement()) {
			QDomElement element = node.toElement();
			
			if (element.tagName() == "Name")
				tabChord->setName(element.text());
			else if (element.tagName() == "Sharp")
				tabChord->setSharp(element.text().toUInt());
			else if (element.tagName() == "Root")
				tabChord->setRoot(element.text().toUInt());
			else if (element.tagName() == "Root")
				tabChord->setRoot(element.text().toUInt());
			else if (element.tagName() == "Type")
				tabChord->setType(element.text().toUInt());
			else if (element.tagName() == "NineElevenThirteen")
				tabChord->setNineElevenThirteen(static_cast<TabChord::ExtentionChord>(element.text().toUInt()));
			else if (element.tagName() == "Bass")
				tabChord->setBass(element.text().toUInt());
			else if (element.tagName() == "AugmentedDiminished")
				tabChord->setAugmentedDiminished(static_cast<TabChord::AugmentedDiminished>(element.text().toUInt()));
			else if (element.tagName() == "AddedNote")
				tabChord->setAddedNote(element.text().toUInt());
			else if (element.tagName() == "TonalityFive")
				tabChord->setTonalityFive(element.text().toUInt());
			else if (element.tagName() == "TonalityNine")
				tabChord->setTonalityNine(element.text().toUInt());
			else if (element.tagName() == "TonalityEleven")
				tabChord->setTonalityEleven(element.text().toUInt());
			else if (element.tagName() == "BaseFret")
				tabChord->setBaseFret(element.text().toUInt());
			else if (element.tagName() == "Fret" && element.hasAttribute("chord"))
				tabChord->setFret(element.attribute("chord").toUInt(), element.text().toUInt());
			else if (element.tagName() == "NumBarres")
				tabChord->setNumBarres(element.text().toUInt());
			else if (element.tagName() == "BarreFret" && element.hasAttribute("chord"))
				tabChord->setBarreFret(element.attribute("chord").toUInt(), element.text().toUInt());
			else if (element.tagName() == "BarreStart" && element.hasAttribute("chord"))
				tabChord->setBarreStart(element.attribute("chord").toUInt(), element.text().toUInt());
			else if (element.tagName() == "BarreEnd" && element.hasAttribute("chord"))
				tabChord->setBarreEnd(element.attribute("chord").toUInt(), element.text().toUInt());
			else if (element.tagName() == "Fingering" && element.hasAttribute("chord"))
				tabChord->setBarreEnd(element.attribute("chord").toUInt(), element.text().toUInt());
			else if (element.tagName() == "Show")
				tabChord->setShowDiagram(element.text().toUInt());
		}
		
		node = node.nextSibling();
	}
	
	return tabChord;
}

void KGuitarTab::writeNoteInformation(const QString& fill, QTextStream& stream, const TabNote& tabNote)
{
	TabNoteEffect noNoteEffect;
	
	stream << fill << "<Fret>" << tabNote.fret() << "</Fret>" << "\n";
	stream << fill << "<Duration>" << tabNote.duration() << "</Duration>" << "\n";
	
	if (tabNote.nTuplet())
		stream << fill << "<NTuplet>" << tabNote.nTuplet() << "</NTuplet>" << "\n";
	
	if (tabNote.isDotted())
		stream << fill << "<Dotted>" << tabNote.isDotted() << "</Dotted>" << "\n";
	
	if (tabNote.isDeadNote())
		stream << fill << "<Dead>" << tabNote.isDeadNote() << "</Dead>" << "\n";
	
	if (*tabNote.effect() != noNoteEffect) {
		if (tabNote.isAccentuated())
			stream << fill << "<Accentuated>" << tabNote.isAccentuated() << "</Accentuated>" << "\n";
		
		if (tabNote.isGhostNote())
		stream << fill << "<Ghost>" << tabNote.isGhostNote() << "</Ghost>" << "\n";
		
		if (tabNote.isTieNote())
			stream << fill << "<Tie>" << tabNote.isTieNote() << "</Tie>" << "\n";
		
		if (tabNote.isHammerOnPullOff())
			stream << fill << "<Hammer>" << tabNote.isHammerOnPullOff() << "</Hammer>" << "\n";
		
		if (tabNote.isLetRing())
			stream << fill << "<LetRing>" << tabNote.isLetRing() << "</LetRing>" << "\n";
		
		if (tabNote.dynamic() != NoneDynamic)
			stream << fill << "<Dynamic>" << tabNote.dynamic() << "</Dynamic>" << "\n";
		
		if (tabNote.fingeringLeft() != NoneFingering)
			stream << fill << "<FingeringLeft>" << tabNote.fingeringLeft() << "</FingeringLeft>" << "\n";
		
		if (tabNote.fingeringRight() != NoneFingering)
			stream << fill << "<FingeringRight>" << tabNote.fingeringRight() << "</FingeringRight>" << "\n";
		
		if (tabNote.isLeftHandVibrato())
			stream << fill << "<LeftHandVibrato>" << tabNote.isLeftHandVibrato() << "</LeftHandVibrato>" << "\n";
		
		if (tabNote.isPalmMute())
			stream << fill << "<PalmMute>" << tabNote.isPalmMute() << "</PalmMute>" << "\n";
		
		if (tabNote.isStaccato())
			stream << fill << "<Staccato>" << tabNote.isStaccato() << "</Staccato>" << "\n";
		
		if (tabNote.slide() != NoneSlide) {
			stream << fill << "<SlideType>" << tabNote.slide() << "</SlideType>" << "\n";
		}
		
		if (tabNote.tremoloPicking())
			stream << fill << "<TremoloPicking>" << tabNote.tremoloPicking() << "</TremoloPicking>" << "\n";
		
		if (tabNote.harmonic() != NoneHarmonic)
			stream << fill << "<Harmonic>" << tabNote.harmonic() << "</Harmonic>" << "\n";
		
		if (tabNote.bendType() != TabBend::NoneBend) {
			stream << fill << "<Bend>\n";
			writeBendInformation(fill + '\t', stream, *tabNote.bend());
			stream << fill << "</Bend>\n";
		}
		
		if (tabNote.period() != 0) {
			stream << fill << "<Trill>\n";
			writeTrillInformation(fill + '\t', stream, *tabNote.trill());
			stream << fill << "</Trill>\n";
		}
		
		if (tabNote.graceNoteDuration() != 0) {
			stream << fill << "<GraceNote>\n";
			writeGraceNoteInformation(fill + '\t', stream, *tabNote.graceNote());
			stream << fill << "</GraceNote>\n";
		}
	}
}

TabNote* KGuitarTab::readNote(QDomNode node, uchar chord)
{
	TabNote* note = new TabNote(chord);
	
	while (node.isNull() == false) {
		if (node.isElement()) {
			QDomElement element = node.toElement();
			
			if (element.tagName() == "Fret")
				note->setFret(element.text().toUInt());
			else if (element.tagName() == "Duration")
				note->setDuration(static_cast<Duration>(element.text().toUInt()));
			else if (element.tagName() == "NTuplet")
				note->setNTuplet(element.text().toUInt());
			else if (element.tagName() == "Accentuated")
				note->setAccentuated(element.text().toUInt());
			else if (element.tagName() == "Dotted")
				note->setDotted(element.text().toUInt());
			else if (element.tagName() == "Ghost")
				note->setGhostNote(element.text().toUInt());
			else if (element.tagName() == "Tie")
				note->setTieNote(element.text().toUInt());
			else if (element.tagName() == "Hammer")
				note->setHammerOnPullOff(element.text().toUInt());
			else if (element.tagName() == "LetRing")
				note->setLetRing(element.text().toUInt());
			else if (element.tagName() == "Dynamic")
				note->setDynamic(static_cast<Dynamic>(element.text().toUInt()));
			else if (element.tagName() == "FingeringLeft")
				note->setFingeringLeft(static_cast<TabFingering>(element.text().toUInt()));
			else if (element.tagName() == "FingeringRight")
				note->setFingeringRight(static_cast<TabFingering>(element.text().toUInt()));
			else if (element.tagName() == "LeftHandVibrato")
				note->setLeftHandVibrato(element.text().toUInt());
			else if (element.tagName() == "PalmMute")
				note->setPalmMute(element.text().toUInt());
			else if (element.tagName() == "Staccato")
				note->setStaccato(element.text().toUInt());
			else if (element.tagName() == "SlideType")
				note->setSlide(static_cast<Slide>(element.text().toUInt()));
			else if (element.tagName() == "TremoloPicking")
				note->setTremoloPicking(element.text().toUInt());
			else if (element.tagName() == "Harmonic")
				note->setHarmonic(static_cast<Harmonic>(element.text().toUInt()));
			else if (element.tagName() == "Bend")
				note->setBend(readBendEffect(element.firstChild()));
			else if (element.tagName() == "Trill")
				note->setTrill(readTrillEffect(element.firstChild()));
			else if (element.tagName() == "GraceNote")
				note->setGraceNote(readGraceNoteEffect(element.firstChild()));
		}
		
		node = node.nextSibling();
	}
	
	return note;
}

void KGuitarTab::writeTrillInformation(const QString& fill, QTextStream& stream, const TabTrill& tabTrill)
{
	stream << fill << "<Fret>"<< tabTrill.fretTrill() << "</Fret>\n";
	stream << fill << "<Period>"<< tabTrill.fretTrill() << "</Period>\n";
}

TabTrill* KGuitarTab::readTrillEffect(QDomNode node)
{
	TabTrill* tabTrill = new TabTrill();
	
	while (node.isNull() == false) {
		if (node.isElement()) {
			QDomElement element = node.toElement();
			
			if (element.tagName() == "Fret")
				tabTrill->setFretTrill(element.text().toUInt());
			else if (element.tagName() == "Period")
				tabTrill->setPeriod(element.text().toUInt());
		}
		
		node = node.nextSibling();
	}
	
	return tabTrill;
}

void KGuitarTab::writeGraceNoteInformation(const QString& fill, QTextStream& stream, const TabGraceNote& tabGraceNote)
{
	stream << fill << "<Duration>"<< tabGraceNote.graceNoteDuration() << "</Duration>\n";
	stream << fill << "<Dynamic>"<< tabGraceNote.graceNoteDynamic() << "</Dynamic>\n";
	stream << fill << "<Fret>"<< tabGraceNote.graceNoteFret() << "</Fret>\n";
	stream << fill << "<Transition>"<< tabGraceNote.graceNoteTransition() << "</Transition>\n";
}

TabGraceNote* KGuitarTab::readGraceNoteEffect(QDomNode node)
{
	TabGraceNote* graceNote = new TabGraceNote();
	
	while (node.isNull() == false) {
		if (node.isElement()) {
			QDomElement element = node.toElement();
			
			if (element.tagName() == "Duration")
				graceNote->setGraceNoteDuration(element.text().toUInt());
			else if (element.tagName() == "Dynamic")
				graceNote->setGraceNoteDynamic(static_cast<Dynamic>(element.text().toUInt()));
			else if (element.tagName() == "Fret")
				graceNote->setGraceNoteFret(element.text().toUInt());
			else if (element.tagName() == "Transition")
				graceNote->setGraceNoteTransition(static_cast<GraceNoteTransition>(element.text().toUInt()));
		}
		
		node = node.nextSibling();
	}
	
	return graceNote;
}
