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

#include <QString>

#include "tablature/tabbar.h"
#include "tablature/tabnote.h"
#include "tablature/tabnoteeffect.h"
#include "tablature/tabtimes.h"
#include "tablature/tabtrack.h"

#include "util/assert.h"

Serialize::Serialize(const TabTrack* track)
: mTrack(track),
  mCopyTrack(true),
  mBegin(),
  mEnd()
{
	PRECONDITION(mTrack != 0x0 );
}

Serialize::Serialize(const TabTrack* track, const TrackPos& begin, const TrackPos& end)
: mTrack(track),
  mCopyTrack(false),
  mBegin(begin),
  mEnd(end)
{
	PRECONDITION(mTrack != 0x0 );
}

Serialize::~Serialize()
{
}

QByteArray Serialize::exec()
{
	QByteArray array;
	
	if (mCopyTrack == true)
		array.append(properties());
	
	for (int i = 0; i < mTrack->size(); i++)
		array.append(bar(mTrack->bar(i)));
	
	return array;
}

QByteArray Serialize::properties()
{
	QByteArray array;
	
	array.append(QString::number(mTrack->mode()).toLatin1());
	array.append(mTrack->name().toLatin1());
	array.append(QString::number(mTrack->color().value()).toLatin1());
	array.append(QString::number(mTrack->nbStrings()).toLatin1());
	array.append(QString::number(mTrack->nbFrets()).toLatin1());
	
	for (int i = 0; i < mTrack->nbStrings(); i++)
		array.append(QString::number(mTrack->tune(i)).toLatin1());
	
	array.append(QString::number(mTrack->capo()).toLatin1());
	
	array.append(QString::number(mTrack->patch()).toLatin1());
	array.append(QString::number(mTrack->channel()).toLatin1());
	array.append(QString::number(mTrack->channelEffects()).toLatin1());
	array.append(QString::number(mTrack->midiPort()).toLatin1());
	array.append(QString::number(mTrack->bank()).toLatin1());
	array.append(QString::number(mTrack->volume()).toLatin1());
	array.append(QString::number(mTrack->balance()).toLatin1());
	array.append(QString::number(mTrack->chorus()).toLatin1());
	array.append(QString::number(mTrack->reverb()).toLatin1());
	array.append(QString::number(mTrack->phaser()).toLatin1());
	array.append(QString::number(mTrack->tremolo()).toLatin1());
	array.append(QString::number(mTrack->numerator()).toLatin1());
	array.append(QString::number(mTrack->denominator()).toLatin1());
	
	return array;
}

QByteArray Serialize::bar(const TabBar* bar)
{
	PRECONDITION(bar != 0x0 );
	
	QByteArray array;
	
	array.append(barMixerProperties(bar->mixer()));
	array.append(barProperties(bar->properties()));
	
	for (uint i = 0; i < bar->size(); i++)
		array.append(time(bar->time(i)));
	
	return array;
}

QByteArray Serialize::barMixerProperties(const TabMixTableChanges* properties)
{
	PRECONDITION(properties != 0x0 );
	
	QByteArray array;
	
	array.append(QString::number(properties->instrument()).toLatin1());
	array.append(QString::number(properties->volume()).toLatin1());
	array.append(QString::number(properties->balance()).toLatin1());
	array.append(QString::number(properties->chorus()).toLatin1());
	array.append(QString::number(properties->reverb()).toLatin1());
	array.append(QString::number(properties->phaser()).toLatin1());
	array.append(QString::number(properties->tremolo()).toLatin1());
	array.append(QString::number(properties->tempo()).toLatin1());
	
	return array;
}

QByteArray Serialize::barProperties(const TabBarProperties* properties)
{
	PRECONDITION(properties != 0x0 );
	
	QByteArray array;
	
	array.append(QString::number(properties->color().value()).toLatin1());
	array.append(properties->marker().toLatin1());
	array.append(QString::number(properties->isRepeatBar()).toLatin1());
	array.append(QString::number(properties->isCloseBar()).toLatin1());
	array.append(QString::number(properties->isAltBar()).toLatin1());
	array.append(QString::number(properties->isRepeatStart()).toLatin1());
	array.append(QString::number(properties->repetitions()).toLatin1());
	array.append(QString::number(properties->isAlternateEndings()).toLatin1());
	array.append(QString::number(properties->isDoubleBar()).toLatin1());
	array.append(properties->asciiCodeOfKey());
	array.append(QString::number(properties->isMinor()).toLatin1());
	array.append(QString::number(properties->numerator()).toLatin1());
	array.append(QString::number(properties->denominator()).toLatin1());
	
	return array;
}

QByteArray Serialize::time(const TabTime* time)
{
	PRECONDITION(time != 0x0 );
	
	QByteArray array;
	
	array.append(timeEffects(time->effect()));
	array.append(timeChord(time->tabChord()));
	
	for (uint i = 0; i < time->size(); i++)
		array.append(note(time->string(i)));
	
	return array;
}

QByteArray Serialize::timeEffects(const TabTimeEffect* effect)
{
	PRECONDITION(effect != 0x0 );
	
	QByteArray array;
	
	array.append(QString::number(effect->isRasgueado()).toLatin1());
	array.append(QString::number(effect->pickstroke()).toLatin1());
	array.append(QString::number(effect->tremolo()).toLatin1());
	array.append(QString::number(effect->isTapping()).toLatin1());
	array.append(QString::number(effect->isPopping()).toLatin1());
	array.append(QString::number(effect->isSlapping()).toLatin1());
	array.append(QString::number(effect->isStroke()).toLatin1());
	array.append(QString::number(effect->upStroke()).toLatin1());
	array.append(QString::number(effect->downStroke()).toLatin1());
	array.append(QString::number(effect->isVibrato()).toLatin1());
	array.append(QString::number(effect->isWideVibrato()).toLatin1());
	array.append(QString::number(effect->isNaturalHarmonic()).toLatin1());
	array.append(QString::number(effect->isArtificialHarmonic()).toLatin1());
	array.append(QString::number(effect->isFadeIn()).toLatin1());
	array.append(bend(effect->bend()));
	
	return array;
}

QByteArray Serialize::timeChord(const TabChord* chord)
{
	PRECONDITION(chord != 0x0 );
	
	QByteArray array;
	
	array.append(chord->name().toLatin1());
	array.append(QString::number(chord->isSharp()).toLatin1());
	array.append(QString::number(chord->root()).toLatin1());
	array.append(QString::number(chord->type()).toLatin1());
	array.append(QString::number(chord->nineElevenThirteen()).toLatin1());
	array.append(QString::number(chord->bass()).toLatin1());
	array.append(QString::number(chord->augmentedDiminished()).toLatin1());
	array.append(QString::number(chord->addedNote()).toLatin1());
	array.append(QString::number(chord->tonalityFive()).toLatin1());
	array.append(QString::number(chord->tonalityNine()).toLatin1());
	array.append(QString::number(chord->tonalityEleven()).toLatin1());
	array.append(QString::number(chord->baseFret()).toLatin1());
	for (int i = 0; i < 6; i++)
		array.append(QString::number(chord->fret(i)).toLatin1());
	array.append(QString::number(chord->numBarres()).toLatin1());
	for (int i = 0; i < 6; i++)
		array.append(QString::number(chord->barreFret(i)).toLatin1());
	for (int i = 0; i < 6; i++)
		array.append(QString::number(chord->barreStart(i)).toLatin1());
	for (int i = 0; i < 6; i++)
		array.append(QString::number(chord->barreEnd(i)).toLatin1());
	for (int i = 0; i < 6; i++)
		array.append(QString::number(chord->fingering(i)).toLatin1());
	array.append(QString::number(chord->isShowDiagram()).toLatin1());
	
	return array;
}

QByteArray Serialize::note(const TabNote* note)
{
	PRECONDITION(note != 0x0 );
	
	QByteArray array;
	
	array.append(noteEffects(note->effect()));
	array.append(QString::number(note->isEmpty()).toLatin1());
	array.append(QString::number(note->fret()).toLatin1());
	array.append(QString::number(note->duration()).toLatin1());
	array.append(QString::number(note->isDotted()).toLatin1());
	array.append(QString::number(note->nTuplet()).toLatin1());
	array.append(QString::number(note->isDeadNote()).toLatin1());
	return array;
}

QByteArray Serialize::noteEffects(const TabNoteEffect* effect)
{
	PRECONDITION(effect != 0x0 );
	
	QByteArray array;
	
	array.append(QString::number(effect->isAccentuated()).toLatin1());
	array.append(QString::number(effect->isGhostNote()).toLatin1());
	array.append(QString::number(effect->isTieNote()).toLatin1());
	array.append(QString::number(effect->isHammerOnPullOff()).toLatin1());
//	array.append(QString::number(effect->isSlide()).toLatin1());
	array.append(QString::number(effect->isLetRing()).toLatin1());
	array.append(QString::number(effect->dynamic()).toLatin1());
	array.append(QString::number(effect->fingeringLeft()).toLatin1());
	array.append(QString::number(effect->fingeringRight()).toLatin1());
	array.append(QString::number(effect->isLeftHandVibrato()).toLatin1());
	array.append(QString::number(effect->isPalmMute()).toLatin1());
	array.append(QString::number(effect->isStaccato()).toLatin1());
	array.append(QString::number(effect->slide()).toLatin1());
	array.append(QString::number(effect->tremoloPicking()).toLatin1());
	array.append(QString::number(effect->harmonic()).toLatin1());
	array.append(QString::number(effect->graceNoteDuration()).toLatin1());
	array.append(QString::number(effect->graceNoteDynamic()).toLatin1());
	array.append(QString::number(effect->graceNoteFret()).toLatin1());
	array.append(QString::number(effect->graceNoteDuration()).toLatin1());
	array.append(QString::number(effect->graceNoteTransition()).toLatin1());
	array.append(bend(effect->bend()));
	array.append(QString::number(effect->fretTrill()).toLatin1());
	array.append(QString::number(effect->period()).toLatin1());
	
	return array;
}

QByteArray Serialize::bend(const TabBend* bend)
{
	PRECONDITION(bend != 0x0 );
	
	QByteArray array;
	
	array.append(QString::number(bend->bendType()).toLatin1());
	array.append(QString::number(bend->bendValue()).toLatin1());
	
	TabBendPoint* point;
	array.append(QString::number(bend->sizeOfBendPoints()).toLatin1());
	for (int i = 0; i < bend->sizeOfBendPoints(); i++) {
		array.append(QString::number(bend->bendPoint(i)->position()).toLatin1());
		array.append(QString::number(bend->bendPoint(i)->height()).toLatin1());
		array.append(QString::number(bend->bendPoint(i)->tabVibrato()).toLatin1());
	}
	
	return array;
}
