/* osc code is partly taken from steve harris' and uwe koloska's liblo examples */

#ifdef HAVE_OSC

#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <pthread.h>
#include <string.h>
#include <malloc.h>
#include <math.h>

#include "osc.h"
#include "looperdata.h"
#include "speciallist.h"

static int osc_data_handler (const char *path, const char *types, lo_arg **argv,
                    int argc, void *data, void *user_data);

void osc_create_error(int num, const char *msg, const char *path){
    printf("liblo server error %d in path %s: %s\n", num, path, msg);
    fflush(stdout);
}

static int path_find_first(const char* path, const char* searched){
	int i = 0;
	int j = 0;
	int pos = 0;

	
	for (i = 0; i <= strlen(path); i++){
		if (!(strncmp ((char*)(path + i),"/",1)) || ((i) == strlen(path))){	
			if (i > j){
				if (strlen(searched) == (i - j - 1))
					if (!(strncasecmp((char*)(path + j + 1),searched,(i - j - 1)))){
						return pos;
					}
				pos++;
			}
			j = i;
		}
	}
	return -1;
}

static long path_pos_to_l(const char* path, int p){
	int i = 0;
	int a = -1;
	int b = -1;
	int pos = -2;
	long result = -1;
	char* substr = calloc(sizeof(char),255);

	for (i = 0; i <= strlen(path); i++){
		if (!(strncmp ((char*)(path + i),"/",1)) || (i == strlen(path))){a = b; b = i;pos++;}
		if (pos == p){
			strncpy(substr,(char*)(path + a + 1),(b-a-1));
			result = strtol(substr,NULL,0);
/*			printf ("substr:%s: %ld\n",substr,result);*/
			free(substr);
			return result;
		}
	}

	free(substr);
	return result;
	
}

osc_info_t* osc_info_new (speciallist_t* looperdatalist) {
	char port[5];
	lo_server_thread st = NULL;
  	osc_info_t* oinfo = calloc (sizeof (osc_info_t),1);
	int i = 1783;

	printf ("creating osc thread\n");

	while ((++i < 1794) && !st){
		sprintf (port,"%d",i);
/*		st     = lo_server_thread_new(&port, osc_create_error);*/
		st = lo_server_thread_new(port, NULL);
	}

	if (st) {printf ("osc server listening at port %s\n",port);}
	else { printf ("failed to create osc server!.");}
	
	if (st){
  		oinfo->quit    		= 0;
		oinfo->looperdatalist	= looperdatalist;
		oinfo->st		= st;
	
		lo_server_thread_add_method(st, NULL,NULL,osc_data_handler, (void*)oinfo);
        	lo_server_thread_start(st);
	}else{ free(oinfo); oinfo = NULL;}

  	return oinfo;  
}

void osc_info_destroy (osc_info_t* oinfo){
  	oinfo->quit = 1;
	lo_server_thread_stop(oinfo->st);
	lo_server_thread_free(oinfo->st);
	free(oinfo);
}

static int osc_data_handler(const char *path, const char *types, lo_arg **argv,
                    int argc, void *data, void *user_data){
    	/*int i;*/
	osc_info_t* oinfo = (osc_info_t*) user_data;
	looper_data_t *ld  = speciallist_get_first_nolock (oinfo->looperdatalist);

/*	
	printf ("path:%s, %d, val:%f\n",path,
		path_find_first(path,"loop"),(float)lo_hires_val(types[0],argv[0]));
*/

	if (path_find_first(path,"loop") == 1){
		long loopnr = path_pos_to_l(path,2);
/*		printf ("loop message\n");*/
		if (path_find_first(path,"Speed") == 3){
			double df = 0;
			if (argc > 0) df = (float)lo_hires_val(types[0],argv[0]);
			while(ld){
				if ((ld->id == loopnr) || (loopnr < 1)){
					looperdata_lock(ld);
					looperdata_set_speed (ld, df);
					looperdata_unlock(ld);
				}
				ld = speciallist_get_next_nolock (oinfo->looperdatalist, ld);
			}		
		}else if (path_find_first(path,"Volume") == 3){
			double df = 0;
//			printf ("nr:%ld, vol:%f\n",loopnr,df);
                        if (argc > 0) df = (float)lo_hires_val(types[0],argv[0]);
                        while(ld){
                                if ((ld->id == loopnr) || (loopnr < 1)){
					looperdata_lock(ld);
                                        looperdata_set_vol (ld, df);
					looperdata_unlock(ld);
                                }
                                ld = speciallist_get_next_nolock (oinfo->looperdatalist, ld);
                        } 
		}else if (path_find_first(path,"Pan") == 3){
                        double df = 0;
                        if (argc > 0) df = (float)lo_hires_val(types[0],argv[0]);
//			printf ("nr:%ld, pan:%f\n",loopnr,(float)df);
                        while(ld){
                                if ((ld->id == loopnr) || (loopnr < 1)){
					looperdata_lock(ld);
                                        looperdata_set_pan (ld, df);
					looperdata_unlock(ld);
                                }
                                ld = speciallist_get_next_nolock (oinfo->looperdatalist, ld);
                        }
		}else if (path_find_first(path,"NumberOfGrains") == 3){
			int i = 0;
                        if (argc > 0) i = lo_hires_val(types[0],argv[0]);
//			printf ("nr:%ld, ngrains:%d\n",loopnr,i);
                        while(ld){
                                if ((ld->id == loopnr) || (loopnr < 1)){
					looperdata_lock(ld);
                                        looperdata_set_ngrains (ld, i);
					looperdata_unlock(ld);
                                }
                                ld = speciallist_get_next_nolock (oinfo->looperdatalist, ld);
                        }
		}else if (path_find_first(path,"Play") == 3){
			int i = 0;
                        if (argc > 0) i = lo_hires_val(types[0],argv[0]);
                        while(ld){
                                if ((ld->id == loopnr) || (loopnr < 1)){
					looperdata_lock(ld);
                                        looperdata_set_playing (ld, i);
					looperdata_unlock(ld);
                                }
                                ld = speciallist_get_next_nolock (oinfo->looperdatalist, ld);
                        } 
		}else if (path_find_first(path,"Record") == 3){
			int i = 0;
                        if (argc > 0) i = lo_hires_val(types[0],argv[0]);
                        while(ld){
                                if ((ld->id == loopnr) || (loopnr < 1)){
					looperdata_lock(ld);
                                        looperdata_set_recording (ld, i);
					looperdata_unlock(ld);
                                }
                                ld = speciallist_get_next_nolock (oinfo->looperdatalist, ld);
                        }
		}
	}

/*
    	printf("path: <%s>\n", path);
    	for (i=0; i<argc; i++) {
        	printf("arg %d '%c' ", i, types[i]);
        	lo_arg_pp(types[i], argv[i]);
        	printf("\n");
    	}
    	printf ("\n\n");
    	fflush(stdout);
*/
    	return 1;
}

#endif /* HAVE_OSC */
