/*---------------------------------------------------------------------------*\

    This program is used for testing Voicetronix hardware.

    1. It waits for ringing on FXO port, or for an FXS port to go off hook.
    2. It then records audio for 4 seconds.  You can stop recording early by
       pressing any digit on the phone handset.
    3. It then plays back the recorded speech and hangs up.
    4. Press any key to finish, otherwise it will wait for further events
       and repeat the steps above.


         Voicetronix Voice Processing Board (VPB) Software

         Copyright (C) 1999-2008 Voicetronix www.voicetronix.com.au

         This library is free software; you can redistribute it and/or
         modify it under the terms of the GNU Lesser General Public
         License as published by the Free Software Foundation; either
         version 2.1 of the License, or (at your option) any later version.

         This library 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
         Lesser General Public License for more details.

         You should have received a copy of the GNU Lesser General Public
         License along with this library; if not, write to the Free Software
         Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
         MA  02110-1301  USA

\*---------------------------------------------------------------------------*/

#include "vpbapi.h"
#include "verbose.h"
#include "kbhit.h"
//#include "threads.h"  // for billware

#include <cstdio>
#include <cstdlib>
#include <cstring>


// This was used for testing line voltage issues with OpenLine cards,
// it shouldn't be needed any longer, but hang onto it a while more.
//static int LV = 0;


static int waitforevent(int h, int event_type, int timeout_ms)
{ //{{{
	void  *timer;
	int    event;

	if(timeout_ms) {
		vpb_timer_open(&timer, h, 0, timeout_ms);
		vpb_timer_start(timer);
	}
	for(;;)
	{
		VPB_EVENT   e;
		if(vpb_get_event_ch_sync(h, &e, 100) == VPB_OK)
		{
			char  s[VPB_MAX_STR];

			vpb_translate_event(&e, s);
			printf("%s",s);

			//if( LV == 1 ) {
			//	short   volts;
			//	vpb_loopvolt_get(h, &volts);
			//	printf("[%02d] Hook Level = %d\n",h, volts);
			//}

			if( e.type == event_type
			 || e.type == VPB_TIMEREXP
			 || e.type == VPB_STATION_OFFHOOK )
			{
				event = e.type;
				break;
			}
		}

		//if( h == 0 && LV == 1) {
		//	short   volts;
		//	vpb_loopvolt_get(h, &volts);
		//	printf("[%02d] Hook Level = %d\015",h, volts);
		//}
	}
	if(timeout_ms) vpb_timer_close(timer);

	return event;
} //}}}

static void port_thread_cleanup( void *p ) { vpb_reset( (intptr_t)p ); }

static void *port_thread(void *p)
{ //{{{
	char        file_name[VPB_MAX_STR];
	int         h    = (long)p;
	VPB_PORT    type = vpb_get_port_type(h);

	sprintf(file_name, "linear%02d.wav", h);

	//if( LV == 1 )
	//{
	//	short   volts;
	//      int	ms;

	//	vpb_loop_get_onhookwindow(h, &ms);
	//	printf("[%02d] onhook window = %d\n",h, ms);
	//	vpb_loop_get_offhookwindow(h, &ms);
	//	printf("[%02d] offhook window = %d\n",h, ms);
	//	vpb_loopvolt_get_threshold(h, &volts);
	//	printf("[%02d] hook threshold = %d\n",h, volts);
	//}

	// Ensure we clean up the port state if terminated.
	pthread_cleanup_push(port_thread_cleanup, p);

	for(;;)
	{
		int ev = waitforevent(h, VPB_RING, 0);

		if( ev == VPB_RING) ev = waitforevent(h, VPB_RING, 6000);
		if( ev == VPB_RING || ev == VPB_STATION_OFFHOOK )
		{
			if( type == VPB_FXO ) {
				printf("[%02d] answering.....\n",h);
				vpb_sethook_sync(h,VPB_OFFHOOK);
			}
			else    printf("[%02d] pickup.....\n",h);

			printf("[%02d] recording.....\n",h);
			vpb_record_file_sync(h, file_name, VPB_LINEAR);

			printf("[%02d] playing.....\n",h);
			vpb_play_file_sync(h, file_name);

			if( type == VPB_FXO )
				vpb_sethook_sync(h,VPB_ONHOOK);

			printf("[%02d] done.....\n",h);
		}
	}
	pthread_cleanup_pop(1);

	return NULL;
} //}}}

static int arg_exists(int argc, char *argv[], const char *arg)
{ //{{{
	for(int i = 0; i < argc; ++i)
		if(strcmp(argv[i],arg) == 0) return i;

	return 0;
} //}}}

int main(int argc, char *argv[])
{ //{{{
	if(arg_exists(argc, argv, "-?") || arg_exists(argc, argv, "--help"))
	{
		//printf("%s: [-? | --help] [-v | --verbose] [--hookthreshold] [--hookwindow]\n",
		printf("%s: [-? | --help] [-v | --verbose]\n", argv[0]);
		return EXIT_SUCCESS;
	}
	if(arg_exists(argc, argv, "-v") || arg_exists(argc, argv, "--verbose"))
		verbose(1);

	// open driver to determine how many ports
	int num_cards = vpb_get_num_cards();
	int num_ch    = 0;

	int ports_per_card[num_cards];

	for(int i = 0; i < num_cards; ++i)
		num_ch += (ports_per_card[i] = vpb_get_ports_per_card(i));

	if( num_ch == 0 ) {
		printf("No ports found.  Exiting.\n");
		vpb_close();
		return EXIT_FAILURE;
	}


	printf("initialising %d ports, please wait...\n",num_ch);

	pthread_t   port_threads[num_ch];
	VPB_RECORD  record;

	record.term_digits = "1234567890*#"; // any digit terminates record
	record.time_out    = 4000;           // record finishes after 4 seconds

	// now init each port and start one thread per port
	int x = 0;
	for(int i = 0; i < num_cards; ++i)
	{
		for(int j = 0; j < ports_per_card[i]; ++j)
		{
			int h = vpb_open(i,j);

			vpb_record_set(h, record);
			pthread_create(&port_threads[x++], NULL, port_thread, (void*)(intptr_t)h);

			//int y = arg_exists(argc, argv, "--hookthreshold");
			//if( y != 0 && (y+1) < argc)
			//{
			//	int k = atoi(argv[y+1]);
			//	if( k > 2 && k < 128 )
			//	{
			//		vpb_loopvolt_set_threshold(h, k);
			//		LV = 1;
			//	}
			//	else
			//		printf("Range error for hook threshold (%d)\n",k);
			//}
			//y = arg_exists(argc, argv, "--hookwindow");
			//if( y != 0 && (y+1) < argc )
			//{
			//	int k = atoi(argv[y+1]);
			//	LV = 1;
			//	vpb_loop_set_onhookwindow(h, k);
			//	vpb_loop_set_offhookwindow(h, k);
			//}
		}
	}
	printf("%d ports opened!\n", num_ch);

	// do nothing in the main thread until a key is pressed
	getkey();

	printf("shutting down....\n");
	for( int i = 0; i < num_ch; ++i )
	{
		pthread_cancel( port_threads[i] );
		pthread_join( port_threads[i], NULL );
	}
	vpb_close();

	return EXIT_SUCCESS;
} //}}}

