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

    FILE....: bridging.cpp
    TYPE....: C++ Console program
    AUTHOR..: Ben Kramer
    DATE....: xx/11/2004

    This program is used for testing Voicetronix.  It works like this:

    1. It waits for ringing on any channel.
    2. It then takes the channel off hook.
    3. When the next call comes in, it will be bridged with it.
    3. It waits untill you hangup.
    4. Press return to finish, otherwise it waits for the next ring (step 1)


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

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

         Voicetronix Voice Processing Board (VPB) Software

         Copyright (C) 1999-2004 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307
	 USA

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

#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <unistd.h>

#include "vpbapi.h"
#include "../../src/libvpb/verbose.h"
#include "../kbhit.h"
#include "../threads.h"

int ctwaitforevent(int h, int event_type, int timeout_ms);
void *port_thread(void *pv);

int             threads_active; // the number of active threads.
pthread_mutex_t mutex;          // mutex to protect shared data
int             finito;         // flag to signal the program is finished.
float           gain;           // option software record gain
int		call_count;	// Number of calls on the system
int		echo_en;	// enable echo cancelor ?

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[])
{
	int	        *h,i,j,x;
	VPB_RECORD	record;
	pthread_t       *aport_thread;
	int 		arg;

	call_count=-1;
	// verbose(1);
	record.term_digits = "1234567890*#";  // any digit terminates record
	record.time_out = 4000;               // record finishes after 4 seconds
	pthread_mutex_init(&mutex,NULL);
	finito = 0;
	
	if ((arg = arg_exists(argc, argv, "--ec")) != 0) {
		echo_en=1;
	}
	else {
		echo_en=0;
	}

	// count the cards and 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));

	printf("Found [%d] channels...\n",num_ch);

	h = new int[num_ch];
	aport_thread = new pthread_t[num_ch];
	
	// now init each port and start one thread per port
	x=0;
	for(i=0; i<num_cards; i++) {
		for(j=0;j<ports_per_card[i];j++){
			h[x] = vpb_open(i,j);
			pthread_create(&aport_thread[x], NULL, port_thread, (void*)&h[x]);
			x++;
		}
	}
	printf("%d ports opened!\n", num_ch);

	// do nothing in main loop until return pressed
	while(!kbhit()){
		vpb_sleep(500);
	}
	finito = 1;

	printf("shutting down....\n");
	while(threads_active) {
		vpb_sleep(100);
		printf("threads active: %d\r", threads_active);
	}

	for(i=0; i<num_ch; i++) {
		vpb_close(h[i]);
	}
	delete h;

	return 0;
}

void *port_thread(void *pv) {
	int       h = *(int*)pv;
	int       ev;
	char      file_name[VPB_MAX_STR];


	pthread_mutex_lock(&mutex);
	threads_active++;
	pthread_mutex_unlock(&mutex);
	sprintf(file_name,"linear%02d.wav",h);

	while(!finito) {

		if(VPB_RING == (ev= ctwaitforevent(h, VPB_RING, 0)))
			vpb_sleep(500);
		if ((ev == VPB_RING) || (ev == VPB_STATION_OFFHOOK)) {
			printf("[%02d] answering.....\n",h);
			vpb_sethook_sync(h,VPB_OFFHOOK);
			
			if (echo_en == 1)
				vpb_hostecho_on(h);

			
			if (call_count == -1){
				call_count=h;
				printf("[%02d] waiting for call.....\n",h);
				while(call_count == h)
					vpb_sleep(250);
			}
			else {
				printf("[%02d] bridging to [%d].....\n",h,call_count);
				vpb_bridge(h,call_count,VPB_BRIDGE_ON);
				call_count = -1;
			}
			printf("Sleeping for 20000ms");
			vpb_sleep(20000);


			if (echo_en == 1)
				vpb_hostecho_off(h);
			vpb_sethook_sync(h, VPB_ONHOOK);
			printf("[%02d] done.....\n",h);
		}
	}

	pthread_mutex_lock(&mutex);
	threads_active--;
	pthread_mutex_unlock(&mutex);

	return NULL;
}
	
int ctwaitforevent(int h, int event_type, int timeout_ms) {
	char      s[VPB_MAX_STR];
	int       ret, state;
	VPB_EVENT e;   
	void      *timer;

	vpb_timer_open(&timer, h, 0, timeout_ms);
	if (timeout_ms != 0)
		vpb_timer_start(timer);

	state = 1;
	while(state && !finito) {
		ret = vpb_get_event_ch_async(h, &e);

		if (ret == VPB_OK) {
			vpb_translate_event(&e, s);
			printf("%s",s);

			if (e.type == event_type) {
				state = 0;
			}
			if (e.type == VPB_TIMEREXP) {
				state = 0;
			}
			if(e.type == VPB_STATION_OFFHOOK) {
				state = 0;
			}	
		}
		else
			vpb_sleep(100);
	}
	  
	vpb_timer_close(timer);	
	if (state == 0)
		return e.type;
	else
		return -1;
}

