/********************************************************************

PhatBeat - A simple beat-counter for producers, DJs, or anybody else.
Copyright (C) 2004 Jack Chatterton <chattj AT postreal.org>

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.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  
02111-1307, USA.

*********************************************************************/

// This is Yet Another Frontend for the BeatCounter class
#include "BeatCounter.h" 
using namespace std;

#include <stdlib.h>
using namespace std;
#include <stdio.h>
using namespace std;
#include <unistd.h>
using namespace std;

#include <sys/time.h>
using namespace std;
#include <iostream>
using namespace std;

#include <sys/poll.h>
using namespace std;
#include <sys/select.h>
using namespace std;

// 100,000 ms in 1 second.
#define MS_DIVIDER .000001

// This routine waits 3 seconds for the user to press enter. That's 
// pretty much all there is to it.
int getEnterEvent() { 
	char k = 'a';
	int retval;
	
	// Select stuff
	// Partially taken from the select(2) man page.
	fd_set rdfs;
	struct timeval tv;
	
	// Set this to watch 
	FD_ZERO(&rdfs);
	FD_SET(0, &rdfs);
	
	// Initialize wait loop to wait 3 s.
	tv.tv_sec = 3;
	tv.tv_usec = 0;

	retval = select(1, &rdfs, NULL, NULL, &tv);
	
	switch(retval) {
		case -1: return -1;
		case 0: return -1; //Timed out
		// Default case is to keep going -- fall thru.
	}
	
	// We know something is there due to not failing in the
	// cases listed above. Moreover, we must get rid of it by
	// reading so that the program won't get stuck looping on
	// the filled buffer.
	read(0,&k,1);
	return 1;
}

BeatCounter getBeats(int howmany, int sig) {
	BeatCounter returnme(sig);
	timeval t,u;
	int i = -1, k = 0;
	double oldtime, newtime, difference;
	bool quit = false;

	// Initialize t, basically. Notice that v is used without any
	// initialization, as the timezone doesn't really matter
	// in this application.	
	gettimeofday(&t, NULL);

	// Initial output of beat to count:
	cout << "Begin tapping [Enter] when ready." << endl;
	
	while(!quit) {

		// Wait until an actual event rather than a timeout.
		while(i == -1) 
			i = getEnterEvent();
		i = -1;
		
		// Needed for continuation on each loop.
		u = t;
		
		gettimeofday(&t,NULL);
		oldtime = (double)(u.tv_sec + (double)(u.tv_usec * MS_DIVIDER));
		newtime = (double)(t.tv_sec + (double)(t.tv_usec * MS_DIVIDER));
		difference = newtime - oldtime;
		
		// Discard values too small to be inter-beat intervals,
		// by simply ignoring their existance.
		if (difference > .001) {
			returnme.AddBeat(newtime);
			k++;
			if (k >= howmany) {
				cout << k << ": " << returnme.getLastDiff() << endl;       
				quit = true;
			}	
			else
				cout << k << ": " << returnme.getLastDiff() << endl;
		}
	}
	return returnme;
}	

// Get a console input integer. Actually, get a *positive*
// console integer, but let's not pick nits.
int getUserInt(int def) {
	int returnme;
	char input[10];
	cin.getline(input, 10);
	returnme = atoi(input);	
		
	if (returnme < 1)
		return def;

	return returnme;
}

int main(int argc, char *argv[]) {
	BeatCounter phat(4);
	int howmany, sig;
	
	cout << "Number of beats in each measure [4]: ";
	sig = getUserInt(4);
	cout << "Number of beats to count [8]: ";
	howmany = getUserInt(8);
	if (howmany > MAX_BEATS)
		howmany = MAX_BEATS;
	if (howmany < 2)
		howmany = 2;
	cout << "Couting " << howmany << " beats at " << sig \
		<< " beats per measure." << endl;
	
	phat = getBeats(howmany,sig);

	cout << endl << "BPM: " << phat.getRA_BPM() << endl;
	cout << "Seconds per measure: "<< phat.getMeasureSecs() << endl;	
	return EXIT_SUCCESS;
}
