#include <math.h>
#include "alphatrack_callback.h"
#include "looper.h"

looper_gui_t *get_next_rc_looper(looper_list_t *ll, looper_gui_t *looper){
	GList *tmpptr, *tp2 = NULL;

	tmpptr = g_list_first (ll->listptr);
	if (!looper){
		if (((looper_gui_t*)tmpptr->data)->remote_controlled)
                        return (looper_gui_t*)tmpptr->data;
	} else {
		while (tmpptr){
                	if ((looper_gui_t*)tmpptr->data == looper) 
				tp2 = tmpptr;
                        tmpptr = g_list_next(tmpptr);
		}
		tmpptr = tp2;
        }
	while ((tmpptr = g_list_next(tmpptr))){
		if (((looper_gui_t*)tmpptr->data)->remote_controlled)
			return (looper_gui_t*)tmpptr->data;
	}
	return NULL;
}

looper_gui_t *get_prev_rc_looper(looper_list_t *ll, looper_gui_t *looper){
        GList *tmpptr, *tp2 = NULL;

        tmpptr = g_list_first (ll->listptr);

        while (tmpptr){
		if ((looper_gui_t*)tmpptr->data == looper)
			break;
                if (((looper_gui_t*)tmpptr->data)->remote_controlled)
                        tp2 = tmpptr;
		tmpptr = g_list_next(tmpptr);
        }
	if (!tp2) return NULL; 
        return (looper_gui_t*)tp2->data;
}


looper_gui_t *get_next_looper(looper_list_t *ll, looper_gui_t *looper){
	GList *tmpptr, *tp2 = NULL;
	tmpptr = g_list_first (ll->listptr);

	if (!tmpptr) return NULL;
	if (!looper) return (looper_gui_t*)tmpptr->data;

	while (tmpptr){
		if ((looper_gui_t*)tmpptr->data == looper)
                                tp2 = tmpptr;
                tmpptr = g_list_next(tmpptr);
	}
        tmpptr = tp2;
	tmpptr = g_list_next(tmpptr);
	if (!tmpptr) return NULL;
	return (looper_gui_t*)tmpptr->data;
}

looper_gui_t *get_prev_looper(looper_list_t *ll, looper_gui_t *looper){
        GList *tmpptr, *tp2 = g_list_last(ll->listptr);
        tmpptr = g_list_first (ll->listptr);

        if (!tmpptr) return NULL;
        if (!looper) return (looper_gui_t*)(g_list_last(ll->listptr)->data);

        while (tmpptr){
                if ((looper_gui_t*)tmpptr->data == looper)
                                break;
		tp2 = tmpptr;
                tmpptr = g_list_next(tmpptr);
        }
        return (looper_gui_t*)tp2->data;
}

void setlcd_float(looper_gui_t *looper, const char *format, float f, int row){
	char *txt = calloc (20, sizeof(char));

	snprintf (txt, 17, format, f);
	alphatrack_write_lcd (looper->alphatrack,txt,0,row);
	free (txt);
}

void setlcd_int(looper_gui_t *looper, const char *format, int i, int row){
        char *txt = calloc (20, sizeof(char));

        snprintf (txt, 17, format, i);
        alphatrack_write_lcd (looper->alphatrack,txt,0,row);
        free (txt);
}

void init_alphatrack(looper_gui_t *looper){
	float f;
	if (!looper) return;

        f = gtk_range_get_value(GTK_RANGE(looper->volslider));
	if (f < -47.)  alphatrack_write_lcd(looper->alphatrack, "Volume off ...  ",0,1);
	else setlcd_float(looper, "Volume: %3.2fdb   ", f, 1);

	f += 48.;
	f *= (1023./ 66.);
	alphatrack_set_faderpos(looper->alphatrack, (int)f);

	alphatrack_clear_leds(looper->alphatrack);
	if (gtk_toggle_button_get_active((GtkToggleButton*)looper->playbutton))
		alphatrack_set_led(looper->alphatrack, ALPHATRACK_LED_READ, 1);
	else 	alphatrack_set_led(looper->alphatrack, ALPHATRACK_LED_READ, 0);

	if (gtk_toggle_button_get_active((GtkToggleButton*)looper->recbutton))
                alphatrack_set_led(looper->alphatrack, ALPHATRACK_LED_WRITE, 1);
        else    alphatrack_set_led(looper->alphatrack, ALPHATRACK_LED_WRITE, 0);

        if (looper->data){
                if (looper->data->buf){
                        alphatrack_write_lcd (looper->alphatrack,
                                looper->data->buf->shortname,0,0);
                }
        }
}
	

void alphatrack_event_callback(alphatrack_event_t *ev, void *ptr){
	looper_list_t *ll = (looper_list_t*)ptr;
	looper_gui_t *looper = NULL;
	float f = 0.;
/*	printf ("callback event: %010Lx (%010Lx)\n", ev->mask, ev->states);	*/

	if ((ev->mask & ALPHATRACK_BUTTON_TRACKR) && (ev->states & ALPHATRACK_BUTTON_TRACKR)){
		looper = get_next_rc_looper(ll,NULL);
		if (looper){
			/* remove rc_flag and search for next looper in the list */
			g_mutex_lock(ll->listmutex);
			looper_set_remote_controlled(looper,0);
			g_mutex_unlock(ll->listmutex);
			looper = get_next_looper(ll,looper);
			if (looper){
				g_mutex_lock(ll->listmutex);
				looper_set_remote_controlled(looper,1);
                		g_mutex_unlock(ll->listmutex);
			}else{
				/* no next looper - try first one */
				looper = get_next_looper(ll,NULL);
				if (looper){
                                	g_mutex_lock(ll->listmutex);
                                	looper_set_remote_controlled(looper,1);
                                	g_mutex_unlock(ll->listmutex);
                        	}
			}
		} else {
			looper = get_next_looper(ll,NULL);
			g_mutex_lock(ll->listmutex);
			if (looper)looper_set_remote_controlled(looper,1);
                        g_mutex_unlock(ll->listmutex);
		}		
		if (looper) init_alphatrack(looper);
	} else if ((ev->mask & ALPHATRACK_BUTTON_TRACKL) && (ev->states & ALPHATRACK_BUTTON_TRACKL)){
                looper = get_prev_rc_looper(ll,NULL);
                if (looper){
                        /* remove rc_flag and search for next looper in the list */
                        g_mutex_lock(ll->listmutex);
                        looper_set_remote_controlled(looper,0);
                        g_mutex_unlock(ll->listmutex);
                        looper = get_prev_looper(ll,looper);
                        if (looper){
                                g_mutex_lock(ll->listmutex);
                                looper_set_remote_controlled(looper,1);
                                g_mutex_unlock(ll->listmutex);
                        }else{
                                /* no next looper - try last one */
                                looper = get_prev_looper(ll,NULL);
                                if (looper){
                                        g_mutex_lock(ll->listmutex);
                                        looper_set_remote_controlled(looper,1);
                                        g_mutex_unlock(ll->listmutex);
                                }
                        }
                } else {
                        looper = get_prev_looper(ll,NULL);
                        g_mutex_lock(ll->listmutex);
                        if (looper)looper_set_remote_controlled(looper,1);
                        g_mutex_unlock(ll->listmutex);
                }
                if (looper) init_alphatrack(looper);
	}

	g_mutex_lock(ll->listmutex);

/* encoders: */
	if (ev->encoderdelta_l){
		looper = NULL;
                while ((looper = get_next_rc_looper(ll, looper))){
			looper->encoderdelta_l += ev->encoderdelta_l;
			setlcd_int(looper, "select Grains:%2d",
				gtk_range_get_value ((GtkRange*)looper->ngrainslider) + 
					looper->encoderdelta_l, 1);
		}
	}	
	if (ev->states & ALPHATRACK_BUTTON_ENCODER_L){
		looper = NULL;
                while ((looper = get_next_rc_looper(ll, looper))){
/*			if (ev->leds[ALPHATRACK_LED_SHIFT]){*/
			if (ev->states & ALPHATRACK_BUTTON_FLIP){
				gtk_range_set_value ((GtkRange*)looper->ngrainslider, 0);
				looper->encoderdelta_l = 0;
				setlcd_int(looper, "set Grains:  %02d", 0, 1);
                        } else if (looper->encoderdelta_l){
				gtk_range_set_value ((GtkRange*)looper->ngrainslider,
					gtk_range_get_value ((GtkRange*)looper->ngrainslider) +
                                        looper->encoderdelta_l);
				looper->encoderdelta_l = 0;
				setlcd_int(looper, "set Grains:   %02d",
                                	gtk_range_get_value ((GtkRange*)looper->ngrainslider) +
                                       	 looper->encoderdelta_l, 1);
			}
		}
	}

	if (ev->encoderdelta_m){
                looper = NULL;
                while ((looper = get_next_rc_looper(ll, looper))){
                        looper->encoderdelta_m += ev->encoderdelta_m * ev->encoderdelta_m * ev->encoderdelta_m;
                        setlcd_int(looper, "sel Graindns:%03d",
				gtk_spin_button_get_value ((GtkSpinButton*)looper->densityspin) +
                                        looper->encoderdelta_m,1);
                }
        }
        if (ev->states & ALPHATRACK_BUTTON_ENCODER_M){
                looper = NULL;
                while ((looper = get_next_rc_looper(ll, looper))){
/*                        if (ev->leds[ALPHATRACK_LED_SHIFT]){*/
			if (ev->states & ALPHATRACK_BUTTON_FLIP){
				if (looper->data){
					looperdata_lock(looper->data);
                               		looper->encoderdelta_m = 0;
					looperdata_set_graindensity(looper->data, 100);
                               		setlcd_int(looper, "Graindensity:%03d   ", 100, 1);
					looperdata_unlock(looper->data);
					looper->dirty = 1;
				}
                        } else if (looper->encoderdelta_m){
				if (looper->data){
                                        looperdata_lock(looper->data);
                                        looperdata_set_graindensity(looper->data,
                                                looperdata_get_graindensity(looper->data) +
                                                looper->encoderdelta_m);
                                        	looper->encoderdelta_m = 0;
                                        setlcd_int(looper, "Graindensity:%03d   ",
						looperdata_get_graindensity(looper->data), 1); 
					/*printf ("dens:%d\n",looperdata_get_graindensity(looper->data));*/
					looperdata_unlock(looper->data);
                                        looper->dirty = 1;
                               }
                        }
                }
        }
        if (ev->encoderdelta_r){
                looper = NULL;
                while ((looper = get_next_rc_looper(ll, looper))){
			if (alphatrack_get_led(looper->alphatrack, ALPHATRACK_LED_AUTO)){
				looper->encoderdelta_r += ev->encoderdelta_r * ev->encoderdelta_r * ev->encoderdelta_r;
				setlcd_float(looper, "sel GrnSpd:%03.3f",
                                                        looperdata_get_mingrainspeed(looper->data) *
                                                        powf(1.011, (float)looper->encoderdelta_r),1);

			} else {
                        	looper->encoderdelta_r += ev->encoderdelta_r * ev->encoderdelta_r * ev->encoderdelta_r;
                        	setlcd_float(looper, "sel Sped:%3.3f   ",
					(float)gtk_spin_button_get_value ((GtkSpinButton*)looper->speedspin) *
						powf(1.011, (float)looper->encoderdelta_r), 1);
			}
                }
        }
        if (ev->states & ALPHATRACK_BUTTON_ENCODER_R){
                looper = NULL;
                while ((looper = get_next_rc_looper(ll, looper))){
/*			if (ev->leds[ALPHATRACK_LED_SHIFT]){*/
			if (alphatrack_get_led(looper->alphatrack, ALPHATRACK_LED_AUTO)){
				if (ev->states & ALPHATRACK_BUTTON_FLIP){
					/* reset grainspeed */
					if (looper->data){
						looperdata_lock(looper->data);
						looperdata_set_mingrainspeed(looper->data, 1.);
						looperdata_set_maxgrainspeed(looper->data, 1.);
						looperdata_unlock(looper->data);
						setlcd_float(looper, "Grainspeed:%03.3f",1.0,1);
					}
					looper->encoderdelta_r = 0;
				} else if (looper->encoderdelta_r) {
					if (looper->data){
                                                looperdata_lock(looper->data);
                                                looperdata_set_mingrainspeed(looper->data, 
							looperdata_get_mingrainspeed(looper->data) *
                                                	powf(1.011, (float)looper->encoderdelta_r));
						looperdata_set_maxgrainspeed(looper->data,
                                                        looperdata_get_mingrainspeed(looper->data) *
                                                        powf(1.011, (float)looper->encoderdelta_r));	
                                                looperdata_unlock(looper->data);
                                                setlcd_float(looper, "Grainspeed:%03.3f",
							looperdata_get_mingrainspeed(looper->data),1);
                                        }
                                        looper->encoderdelta_r = 0;
				}
			} else {
				if (ev->states & ALPHATRACK_BUTTON_FLIP){
					if (looper->data){
						looperdata_lock(looper->data);
                                        	looperdata_set_speed(looper->data,1.0);
                                        	looperdata_unlock(looper->data);
						looper->dirty = 1;
						setlcd_float(looper, "Speed:  %03.3f   ", 1.0, 1);
					}
				} else if (looper->encoderdelta_r){	
					if (looper->data){
						looperdata_lock(looper->data);
						looperdata_set_speed(looper->data, 
							looperdata_get_speed(looper->data) * 
                                                	powf(1.011, (float)looper->encoderdelta_r));
						looper->encoderdelta_r = 0;
						looperdata_unlock(looper->data);
						looper->dirty = 1;
						setlcd_float(looper, "Speed:  %03.3f   ",
                                                	(float)gtk_spin_button_get_value ((GtkSpinButton*)looper->speedspin) *
                                                	powf(1.011, (float)looper->encoderdelta_r), 1);
					}
                        	}
			}
                }
        }
/* touchstrip and buttons: */
	if ((ev->mask & ALPHATRACK_CONTACT_TOUCHSTRIP_1) && 
		(ev->states & ALPHATRACK_CONTACT_TOUCHSTRIP_1)){
		looper = NULL;
               	while ((looper = get_next_rc_looper(ll, looper))){
			if (!ev->leds[ALPHATRACK_LED_SHIFT]){
				/* semitones pitch / speed change: */
				printf ("touchstrip\n");
				double f = (float)((ev->touchpos / 64) - 2);
				if (f >= 0.) f += 1.;
				f = pow(2.,f / 12.);
				if (looper->data){
					looperdata_lock(looper->data);
					f *= (float)looperdata_get_speed(looper->data);
					looperdata_set_speed(looper->data,(double)f);
					looperdata_unlock(looper->data);
					setlcd_float(looper, "Speed:  %3.3f   ",(float)f,1);
					looper->dirty = 1;
				}
			} else { /* just store the touch position */
                                looper->touchstrippos = ev->touchpos /* + 1*/;
                                if (looper->data){
                                        looper->touchstripposval = looperdata_get_loopstart(looper->data);
                                        looper->touchstripposrange = looperdata_get_loopend(looper->data) - 
                                                                looper->touchstripposval;
                                }
			}
		}	
	}
#if 0 /* don't know what touchstrip2 is good for - seems to be the volume fader on touch*/
	if ((ev->mask & ALPHATRACK_CONTACT_TOUCHSTRIP_2) && 
		(ev->states & ALPHATRACK_CONTACT_TOUCHSTRIP_2)){
               	looper = NULL;
               	while ((looper = get_next_rc_looper(ll, looper))){
			if (!ev->leds[ALPHATRACK_LED_SHIFT]){
                		/* full tones pitch / speed change */
				printf ("touchstrip2\n");
                       		double f = (float)((ev->touchpos / 64) - 2);
                       		if (f >= 0.) f += 1.;
                       		f = pow(2.,f / 6.);
				if (looper->data){
                                        looperdata_lock(looper->data);
                                        f *= (float)looperdata_get_speed(looper->data);
                                        looperdata_set_speed(looper->data,(double)f);
                                        looperdata_unlock(looper->data);
                                        setlcd_float(looper, "Speed:  %3.3f   ",(float)f,1);
					looper->dirty = 1;
                                }
			} else { /* just store the touch position */
                                looper->touchstrippos = ev->touchpos /* + 1*/;
				if (looper->data){
					looper->touchstripposval = looperdata_get_loopstart(looper->data);
					looper->touchstripposrange = looperdata_get_loopend(looper->data) - 
								looper->touchstripposval;
				}
                        }
               	}
       	} 
#endif
	if ((ev->mask & ALPHATRACK_POS_TOUCHSTRIP) && ev->leds[ALPHATRACK_LED_SHIFT]){
		/* change loop */
		looper = NULL; 
                while ((looper = get_next_rc_looper(ll, looper))){
			if (ev->states & ALPHATRACK_CONTACT_TOUCHSTRIP_1){
				/* set loopstart and keep the length intact */
				float f = ((float)ev->touchpos - (float)looper->touchstrippos) / 256.;
				f = (float)looper->touchstripposval + (float)(looper->touchstripposrange  * f);

				if (looper->data){
					looperdata_lock(looper->data);
					looperdata_set_loopend(looper->data,
						(long)(f + looper->touchstripposrange));
					looperdata_set_loopstart(looper->data,(long)f);
					if (looper->data->linkrec2play){
						looperdata_set_recstart(looper->data,
							looperdata_get_loopstart(looper->data));
						looperdata_set_recend(looper->data,
                                                        looperdata_get_loopend(looper->data));
					}
					looperdata_unlock(looper->data);
					looper->dirty = 1;
				}
			} else if  (ev->states & ALPHATRACK_CONTACT_TOUCHSTRIP_2){
				/* set the length */
				float f = ((float)ev->touchpos - (float)looper->touchstrippos) / 256.;
                                f = (float)looper->touchstripposrange + (float)(looper->touchstripposrange  * f);

				if (looper->data){
					looperdata_lock(looper->data);
                                        looperdata_set_loopend(looper->data,(long)f + looperdata_get_loopstart(looper->data));
					if (looper->data->linkrec2play)
                                                looperdata_set_recend(looper->data,
							looperdata_get_loopend(looper->data));
					looperdata_unlock(looper->data);
					looper->dirty = 1;
                                }
			} /*else printf ("strange: touch without finger info\n");*/
		}
	}
	if ((ev->mask & ALPHATRACK_BUTTON_SHIFT) && (ev->states & ALPHATRACK_BUTTON_SHIFT)){
		looper = NULL;
                while ((looper = get_next_rc_looper(ll, looper))){
			if (ev->leds[ALPHATRACK_LED_SHIFT])
				alphatrack_set_led(looper->alphatrack, ALPHATRACK_LED_SHIFT, 0);
			else 	alphatrack_set_led(looper->alphatrack, ALPHATRACK_LED_SHIFT, 1);
		}
	}
	if ((ev->mask & ALPHATRACK_BUTTON_PLAY) && (ev->states & ALPHATRACK_BUTTON_PLAY)){
		looper = NULL;
                while ((looper = get_next_rc_looper(ll, looper))){
			if (gtk_toggle_button_get_active((GtkToggleButton*)looper->playbutton)) {
				gtk_toggle_button_set_active((GtkToggleButton*)looper->playbutton, FALSE);
				alphatrack_set_led(looper->alphatrack, ALPHATRACK_LED_READ, 0);

			} else	{
				gtk_toggle_button_set_active((GtkToggleButton*)looper->playbutton, TRUE);
				alphatrack_set_led(looper->alphatrack, ALPHATRACK_LED_READ, 1);

			}
		}	
	}
	if ((ev->mask & ALPHATRACK_BUTTON_RECORD) && (ev->states & ALPHATRACK_BUTTON_RECORD)){
                looper = NULL;
                while ((looper = get_next_rc_looper(ll, looper))){
                        if (gtk_toggle_button_get_active((GtkToggleButton*)looper->recbutton)){
                                gtk_toggle_button_set_active((GtkToggleButton*)looper->recbutton, FALSE);
				alphatrack_set_led(looper->alphatrack, ALPHATRACK_LED_WRITE, 0);
                        } else  {
				gtk_toggle_button_set_active((GtkToggleButton*)looper->recbutton, TRUE);
		                alphatrack_set_led(looper->alphatrack, ALPHATRACK_LED_WRITE, 1);
			}
                }
        }
	if (ev->mask & ALPHATRACK_BUTTON_FLIP){
		looper = NULL;
                while ((looper = get_next_rc_looper(ll, looper))){
			if (ev->states & ALPHATRACK_BUTTON_FLIP)
				alphatrack_set_led(looper->alphatrack, ALPHATRACK_LED_FLIP, 1);
			else	alphatrack_set_led(looper->alphatrack, ALPHATRACK_LED_FLIP, 0);
		}
	}
	if ((ev->mask & ALPHATRACK_BUTTON_AUTO) && (ev->states & ALPHATRACK_BUTTON_AUTO)){
                looper = NULL;
                while ((looper = get_next_rc_looper(ll, looper))){
			if (alphatrack_get_led(looper->alphatrack, ALPHATRACK_LED_AUTO))
				alphatrack_set_led(looper->alphatrack, ALPHATRACK_LED_AUTO, 0);
			else	alphatrack_set_led(looper->alphatrack, ALPHATRACK_LED_AUTO, 1);
		}	
	}

/*  fader: */
        if (ev->mask & ALPHATRACK_POS_FADER){
                looper = NULL;
                while ((looper = get_next_rc_looper(ll, looper))){
                        f = ((float)ev->faderpos / 1023. * 66.) - 48.;
                        if (looper->data){
                                looperdata_lock(looper->data);
                                if (f > -47.0) {
                                        setlcd_float(looper, "Volume: %3.2fdb   ",f,1);
                                        looperdata_set_vol(looper->data, powf(10.0f, f * 0.05f));
                                } else {
					alphatrack_write_lcd(looper->alphatrack, "Volume off ...  ",0,1);
                                        looperdata_set_vol(looper->data, 0.);
                                }
                                looperdata_unlock(looper->data);
                                looper->dirty = 1;
                        }
                }
        }

	g_mutex_unlock(ll->listmutex);
}
