/***************************************************************************
 * playbacktracker.cpp: implementation of PlayBacktracker 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 "playbacktracker.h"
#include "util/assert.h"
#include "util/logger.h"

#include <QtDebug>

#include "tablature/tabbar.h"
#include "tablature/tabtrack.h"
#include "tablature/trackpos.h"
#include "tablatureModel/tabsongmodel.h"
#include "settings.h"
#include "songview.h"

const uint PlaybackTracker::playBackTrackCmd = 14;

PlaybackTracker::PlaybackTracker(SongView* songView, const TabSongModel* tabSong)
: TransportCallback(),
  mSongView(songView),
  mTabSong(tabSong),
  drumTrack(mTabSong->isDrumTrack()),
  drumTrackNb(mTabSong->drumTrack()),
  midiPort(Settings::getInstance()->midiPortNumber()),
  trackPos(mTabSong->size())
{
}

void PlaybackTracker::resetCursor()
{
	trackPos.resize(mTabSong->size());
	drumTrack = mTabSong->isDrumTrack();
	drumTrackNb = mTabSong->drumTrack();
	
	for (int i = 0; i < trackPos.size(); i++) {
		trackPos[i].setBar(0);
		trackPos[i].setChord(0);
		trackPos[i].setTimes(0);
	}
}

void PlaybackTracker::Transport_MidiOut(TSE3::MidiCommand c)
{
	uint realChannel;
	
	if (c.status == playBackTrackCmd) {
		TabSongModel::const_iterator it;
		uint i = 0;
		
		//ktabedit::ktabLog << "[PlaybackTracker::MidiOut] : " << c.status << " " << c.port << "\n";
		realChannel = midiChanToIntChan(c.channel);
		
		for (it = mTabSong->begin(); i < realChannel && it != mTabSong->end(); i++, ++it)
			;
		
		if (it == mTabSong->end()) {
			qDebug() << "[PlaybackTracker::Transport_MidiOut] it == mTabSong->end()\n";
			throw std::exception();
		}
		
		const TabTrack& tempTrack = **it;
		TabBar* tempBar = tempTrack.bar(trackPos[realChannel].bar());
		
		// Go to the next time
		//
		nextTime(*tempBar, realChannel);
		
		mSongView->playbackCursor(realChannel, trackPos[realChannel]);
	}
	
}

void PlaybackTracker::Transport_MidiIn(TSE3::MidiCommand) 
{
}

uint PlaybackTracker::midiChanToIntChan(uint channel)
{
	// Check the real channel
	//
	if (drumTrack) {
		if (drumTrackNb != 9) {
			if (drumTrackNb < 9) {
				if (channel == 9)
					channel = drumTrackNb;
				else if (channel > drumTrackNb && channel < 9)
					channel--;
				else if (channel >= 9)
					channel++;
			} else {
				if (channel == 9)
					channel = drumTrackNb;
				else if (channel >= 9 && channel < drumTrackNb)
					channel++;
			}
		}
	}
	
	return channel;
}

void PlaybackTracker::nextTime(const TabBar& bar, uint channel)
{
	TabSongModel::const_iterator it;
	uint i = 0;
	TrackPos tempPos(trackPos[channel]);
	
	for (it = mTabSong->begin(); i < channel && it != mTabSong->end(); i++, ++it)
		;
	
	if (it == mTabSong->end()) {
		qDebug() << "[PlaybackTracker::nextTime] it == mTabSong->end()\n";
		throw std::exception();
	}
	
	const TabTrack& tempTrack = **it;
	
	// Go to the next time
	//
	tempPos.setChord(0);
	tempPos.incTimes();
		
	if (static_cast<ulong>(tempPos.times()) == bar.size() && static_cast<ulong>(tempPos.bar() + 1) < tempTrack.size()) {
		tempPos.setTimes(0);
		tempPos.incBar();
	} else {
		if (static_cast<ulong>(tempPos.bar() + 1) == tempTrack.size()) {
			trackPos[channel] = tempPos;
			
			return ;
		}
	}
	
	trackPos[channel] = tempPos;
}
