/***************************************************************************
 * convertascii.h: implementation of ConvertAscii 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 "convertascii.h"
#include "settings.h"

#include "global.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"

const uint ConvertAscii::msSpaces = 2;

ConvertAscii::ConvertAscii()
{
	//Settings::getInstance()->config->setGroup("ASCII");
	//mDurMode = Settings::getInstance()->config->readNumEntry("DurationDisplay", 3);
	//mPageWidth = Settings::getInstance()->config->readNumEntry("PageWidth", 72);
}

ConvertAscii::~ConvertAscii()
{
}

bool ConvertAscii::saveFile(const QString& fileName, const TabSong& tabSong)
{
	int n = 1;
	TabSong::const_iterator it;
	
	// Initialize output stream
	//
	mFile.setName(fileName);
	
	if (!mFile.open(IO_WriteOnly))
		return false;
	
	mStream.setDevice(&mFile);
	
	// Print out header
	//
	writeHeader(tabSong);
	
	// Print out track data
	//
	for (it = tabSong.begin(); it != tabSong.end(); ++it) {
		writeTrack(**it, n);
		n++;
	}
	
	mFile.close();
	
	return true;
}

void ConvertAscii::writeHeader(const TabSong& tabSong)
{
	writeCentered(tabSong.title());
	mStream << endl;
	
	writeCentered("Author: " + tabSong.author());
	writeCentered("Transcribed by: " + tabSong.transcriber());
	mStream << "Tempo: " << tabSong.tempo() << endl << endl;
}

void ConvertAscii::writeTrack(const TabTrack& tabTrack, int n)
{
	QString tmp;
	
	startTrack(tabTrack, n);
	startRow(tabTrack);
	
	for (uint i = 0; i < tabTrack.size(); i++) {
		addBar(tabTrack, *tabTrack.bar(i));
		flushBar(tabTrack);
	}
	
	flushBar(tabTrack);
	flushRow(tabTrack);
}

void ConvertAscii::startTrack(const TabTrack& tabTrack, int n)
{
	mStream << "Track " << n << ": " << tabTrack.name() << endl << endl;
	
	mMinstart = 1;
	for (int i = 0; i < tabTrack.nbStrings(); i++)
		if (Settings::getInstance()->noteName(tabTrack.tune(i) % 12).length() > 1)
			mMinstart = 2;
}

void ConvertAscii::startRow(const TabTrack& tabTrack)
{
	for (int i = 0; i < tabTrack.nbStrings(); i++) {
		if (tabTrack.mode() == FretTab) {
			mRow[i] = Settings::getInstance()->noteName(tabTrack.tune(i) % 12);
			while (mRow[i].length() < mMinstart)
				mRow[i] += ' ';
		} else {
			mRow[i] = drum_abbr[tabTrack.tune(i)];
		}
		mRow[i] += "|-";
	}
	mRowBars = 0;
}

void ConvertAscii::writeCentered(const QString& l)
{
	for (uint i = 0; i < (mPageWidth- (int)l.length()) / 2; i++)
		mStream << ' ';
	mStream << l << endl;
}

void ConvertAscii::addBar(const TabTrack& tabTrack, const TabBar& tabBar)
{
	uint i, j, k;
	TabTime* tabTime;
	TabNote* tabNote;
	
	for (i = 0; i < tabBar.size(); i++) {
		tabTime = tabBar.time(i);
		
		// Render Time
		//
		for (j = 0; j < tabTrack.nbStrings(); j++) {
			tabNote = tabTime->string(j);
			
			if (tabNote->isEmpty())
				mBar[j]+="--";
			else if (tabNote->isDeadNote())
				mBar[j]+="-X";
			else if (tabTrack.mode() == DrumTab)
				mBar[j]+="-o";
			else
				mBar[j]+='-' + QString::number(tabNote->fret());
			
			// Space for duration
			for (k = 0; k < msSpaces; k++)
				mBar[j]+='-';
		}
	}
}

void ConvertAscii::flushBar(const TabTrack& tabTrack)
{
	// Close bar with vertical pipe symbol
	//
	for (int i = 0; i < tabTrack.nbStrings(); i++)
		mBar[i] += '|';

	// If we won't overfill page width or if we have no bars yet, add
	// mBar[] to mRow[]
	if (mRowBars == 0 || (mRow[0].length() + mBar[0].length() <= mPageWidth)) {
		for (int i = 0; i < tabTrack.nbStrings(); i++) {
			mRow[i] += mBar[i];
			mBar[i] = "";
		}
		mRowBars++;
	}

	// If we have to flush row, do it
	if (mRow[0].length() + mBar[0].length() >= mPageWidth) {
		flushRow(tabTrack);
		startRow(tabTrack);
	}

	// If we still have bar to flush, do it now
	if (mBar[0].length() > 0) {
		for (int i = 0; i < tabTrack.nbStrings(); i++) {
			mRow[i] += mBar[i];
			mBar[i] = "";
		}
		mRowBars++;
	}
}

void ConvertAscii::flushRow(const TabTrack& tabTrack)
{
	if (mRowBars > 0) {
		for (int i = tabTrack.nbStrings() - 1; i >= 0; i--)
			mStream << mRow[i] << endl;
		
		mStream << endl;
	}
}
