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

#include <QtDebug>

#include "util/assert.h"
#include "util/logger.h"

#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"

Lilypond::Lilypond()
: mWriteTempo(false)
{
}

Lilypond::~Lilypond()
{
}

// This code is traducted from the python code of songwrite
//
void Lilypond::writeHeader(const TabProperties& tabProperties)
{
	mStream << "\\version \"2.10.15\"\n";
	
	mStream << "\\header {" << "\n";
	mStream << "\t" << "title = \"" << tabProperties.title() << "\"\n";
	mStream << "\t" << "subtitle = \"" << tabProperties.subTitle() << "\"\n";
	mStream << "\t" << "artist = \"" << tabProperties.artist() << "\"\n";
	mStream << "\t" << "composer = \"" << tabProperties.author() << "\"\n";
	mStream << "\t" << "copyright = \"" << tabProperties.copyright() << "\"\n";
	mStream << "}" << "\n";
	
}

void Lilypond::writeTimes(uint nbStrings, const TabTime& tabTimes)
{
	QString noteDuration;
	QString dot;
	
	if (tabTimes.isRest() == false) {
		mStream << "<\n";
		
		for (uint i = 0; i < nbStrings; i++) {
			if (tabTimes.string(i)->isEmpty() == false) {
				// middle C is 48
				//
				uint note = mTuning[nbStrings - i - 1] + tabTimes.string(i)->fret();
				int octaveHeight = (note / 12) - 4;
				char octaveSign;
				QString octave;
				QString noteName;
				QString ties;
				
				if (octaveHeight < 0) {
					octaveHeight = (-octaveHeight) - 2;
					octaveSign = ',';
				} else
					octaveSign = '\'';
				
				for (int j = 0; j <= octaveHeight; j++)
					octave+=octaveSign;
				
				note = note - ((note / 12) * 12);
				
				switch (note) {
					// C
				case 0:
				case 1:
					noteName = "c";
					break;
					// D
				case 2:
				case 3:
					noteName = "d";
					break;
					// E
				case 4:
					noteName = "e";
					break;
					// F
				case 5:
				case 6:
					noteName = "f";
					break;
					// G
				case 7:
				case 8:
					noteName = "g";
					break;
					// A
				case 9:
				case 10:
					noteName = "a";
					break;
					// B
				case 11:
					noteName = "b";
					break;
				}
				
				if (tabTimes.string(i)->isTieNote() == true)
					ties = "~";
				
				mStream << noteName << octave << ties << " ";
				qDebug() << "note : " << note << " " << octave << "\n";
			}
		}
		
		mStream << "\n" << ">";
	} else {
		mStream << "r";
	}
	
	if (tabTimes.isDotted())
		dot = ".";
	
	switch (tabTimes.duration()) {
	case NoneDuration:
		noteDuration = "";
		break;
	case Whole:
		noteDuration = "1";
		break;
	case Half:
		noteDuration = "2";
		break;
	case Quarter:
		noteDuration = "4";
		break;
	case Eighth:
		noteDuration = "8";
		break;
	case Sixteenth:
		noteDuration = "16";
		break;
	case ThirthSecond:
		noteDuration = "32";
		break;
	case SixtyFourth:
		noteDuration = "64";
		break;
	case HundredTwentyEighth:
		noteDuration = "128";
		break;
	}
	
	mStream << noteDuration << dot << "\n";
}

void Lilypond::writeBars(uint nbStrings, const TabBar& tabBar)
{
	mStream << "\\time " << tabBar.numerator() << "/" << tabBar.denominator() << "\n";
	
	for (uint i = 0; i < tabBar.size(); i++) {
		writeTimes(nbStrings, *tabBar.time(i));
	}
}

void Lilypond::writeTrack(const TabProperties& tabProperties, const TabTrack& tabTrack)
{
	uint i;
	
	mTuning.resize(tabTrack.nbStrings());
	
	for (i = 0; i < tabTrack.nbStrings(); i++)
		mTuning[i] = tabTrack.tune(i);
	
	mStream << "\\new Staff {\n";
	
	if (mWriteTempo == false) {
		mStream << "\t" << "\\tempo 4 = " << tabProperties.tempo() << "\n";
		mWriteTempo = true;
	}
	
	for (i = 0; i < tabTrack.size(); i++)
		writeBars(tabTrack.nbStrings(), *tabTrack.bar(i));
	
	mStream << "}\n";
}

bool Lilypond::saveFile(const QString& fileName, const TabSong& tabSong)
{
	TabSong::const_iterator it;
	
	// Open file
	//
	mFile.setName(fileName);
	
	if (!mFile.open(IO_WriteOnly)) {
		//ktabedit::ktabLog << "Cannot write file" << "\n";
		throw "Cannot open file";
	}
	
	mStream.setDevice(&mFile);
	
	writeHeader(*tabSong.properties());
	
	for (it = tabSong.begin(); it != tabSong.end(); ++it)
		writeTrack(*tabSong.properties(), **it);
	
	mFile.close();
	
	return true;
}
