/** \file notify.c:
 *  Contains MIOS C-Skeleton functions DIN_NotifyToggle and ENC_NotifyChange.
 *  Handles Button presses and encoder movements, including calculation of MIDI
 *  values.
 */

/**
 * This function is called by MIOS when an button has been toggled
 * pin_value is 1 when button released, and 0 when button pressed
 *
 * The main function is navigation between the menus and handling of parameters
 * that have a switch function.
 */
void DIN_NotifyToggle(unsigned char pin, unsigned char pin_value) __wparam
{
    int max,min;
	signed char incrementer;
	parameter *param;
	param = 0;
	stepwidth=0x7F;


	if(pin<52)
		pin=pin+((pin%8)<4?(pin%4):(pin%4)-3);     				// remapping of pins actual <-> logical


	//debugc(get_userdata);
	//debugc(eb_request.error);
	//debugc(send_editbuffer);
	//debugc(eb_request.active);
/*
//Debugging functions for printing memory locations on the display

	if (pin-32==4) {				//Memory Shortcuts...
		storage_view=0x7FFFFL;
		return;
	}

	if (pin-32==1) {
		storage_view=0x00000L;
		return;
	}

	if (pin-32==2) {
		storage_view=DEVICE_MENU_LENGTH;
		return;
	}

	if (pin-32==3) {
		storage_view=(DEVICE_MENU_LENGTH+MODUL_MENU_LENGTH);
		return;
	}


*/
 	/**
	 * If the MIDIbox receives or sends longer data, the pushbuttons are deactivated.
	 */
	if(get_userdata)
		return;

	//if (record_flag == 1)
	//	return;

	if(send_editbuffer)
		return;

	if(eb_request.active)
		return;

	/**
 	 * The following lines handle menu navigation with menu buttons k0-k3.
	 * knobs is a help variable that determines which or if two buttons are pressed simultaneously. 
	 */
	if(pin>=52) {
		eb_request.error=0;
		get_userdata=0x00;

		if(pin_value && !(knobs&0x10) && modus!=MOD_DEVICE) {
			if (modus==MOD_PARAMETER)
				saveParameterValues();
			bank=pin-52;
			initModulModus();
		}
		if(pin_value && (knobs&0x10)) {
			knobs&=0xef;
			if (modus==MOD_PARAMETER)
				saveParameterValues();
			initDeviceModus();
		}
		switch(pin) {
			case 52:
				if(!pin_value)
					knobs|=0x1;
				else
					knobs&=0xfe;
				break;
			case 53:
				if(!pin_value)
					knobs|=0x2;
				else
					knobs&=0xfd;
				break;
			case 54:
				if(!pin_value)
					knobs|=0x4;
				else
					knobs&=0xfb;
				break;
			case 55:
				if(!pin_value)
					knobs|=0x8;
				else
					knobs&=0xf7;
				break;
		}
		if((knobs&3)==0x03)
			knobs|=0x10;
		if(!(knobs&03))
			knobs&=0xef;
	}
	/**
	 * The following linees handle the pushbutton function of the 16 encoders.
	 * They react differently in each menu level. In device and module level they call the 
	 * following menu level, in parameter level they are optional pushbuttons for sending
 	 * MIDI Messages (alternative to turning function)
	 */
	else {
		if(eb_request.error)
			return;
		switch(modus) {
			case MOD_DEVICE:
				if(pin_value)
					break;
				device=pin-32;
				initModulModus();
				break;

			case MOD_MODUL:
				if(pin_value)
					break;
				modul=pin-32;
				initParameterModus();
				potis[17]=0x0000;
				break;
			
			/**
			 * For modifying the parameters with the pushbuttons, different attributes of the
			 * handled parameter are read out (min, max, bit resolution, sign...), and the MIDI message is 
			 * created accordingly.
			 */
			case MOD_PARAMETER:
				potis[16]|=1<<(pin-32);
				update|=0x02;
				if (pin-32<=7) {										//choosing array
					param = &parametersleft[pin-32];
				} else if (pin-32>7) {
					param = &parametersright[(pin-32)%8];
				}
				if(!(((param->messageChannel)&0xF0)&&((param->modeSelect)&0x08)))						//return if mode=OFF
					return;																				//only react if mode "Switch"
                else {
					if(!((param->modeSelect)&0x02)) {
						max=(char)(param->valueMax[0]);
						min=(char)(param->valueMin[0]);
						if((param->modeSelect)&0x01) {
							max=64+max;
							min=64-min;
						}
					} else {
						max=((int)((param->valueMax[0])<<7)|(int)(param->valueMax[1]));
						min=((int)((param->valueMin[0])<<7)|(int)(param->valueMin[1]));
						if((param->modeSelect)&0x01) {
							max=8192+max;
							min=8192-min;
						}
					}


					switch (param->messageChannel&0xF0) {
						case (0x30):
						case (0x50):
						case (0x60):
							if (param->modeSelect&0xF0) {
								if (!pin_value){
									incrementer=(1-(2*(((param->modeSelect)&0x04)>>2)));
									if (param->scale==0)
										potis[pin-32]+=incrementer;
									else
										if (param->scale!=0) {
											if(incrementer>0)
												potis[pin-32]+=param->scale*incrementer;
											if(incrementer<0)
												potis[pin-32]-=param->scale*((~incrementer)+1);
										}

									if(potis[pin-32]<min)
										potis[pin-32]=min;
									if(potis[pin-32]>max)
										potis[pin-32]=max;

									sendMessage(pin-32,(incrementer*(param->scale+(((param->scale-1)>>7)&0x01))));
								}
							break;
							}
						default:
							if ((param->modeSelect)&0x04) {
								if (!pin_value){
									if (potis[pin-32]<(min+((max-min)/2))) {
										potis[pin-32]=max;
										if(((param->modeSelect)&0x04)>>2)
											stepwidth=(0x3FFF/potis[pin-32]);
										else
											stepwidth=(0x7F/potis[pin-32]);

									} else {
										potis[pin-32]=min;
										stepwidth=0x0000;
									}
									sendMessage(pin-32,0x00);
								}
								break;
							} else {
								switch (pin_value) {
									case (0):
										potis[pin-32]=max;

										if(((param->modeSelect)&0x04)>>2)
											stepwidth=(0x3FFF/potis[pin-32]);
										else
											stepwidth=(0x7F/potis[pin-32]);
										sendMessage(pin-32,0x00);
										break;

									case (1):
										if (potis[17]&(0x01<<(pin-32))) {
											potis[pin-32]=min;
											stepwidth=0x0000;
											potis[17]&=(~(0x01<<(pin-32)));
											sendMessage(pin-32,0x00);
										}
										break;
								}


								potis[17]|=1<<(pin-32);

							}
					}
				}
		}
	}
}

/**
 * This function is called by MIOS when an encoder has been moved
 * incrementer is positive when encoder has been turned clockwise, else
 * it is negative
 */
void ENC_NotifyChange(unsigned char encoder, char incrementer) __wparam
{
	//if (record_flag == 1)
		//	return;
	    int max,min;
	    //unsigned long addr;
	    unsigned char bitmode, encoderold, byte;
	    parameter *param;

		param=0;
		min=0;
		max=0;
		encoderold=encoder;							//keeping original encoder number (needed for MIOS Speed Set)
		encoder=encoder+((encoder%8)<4?(encoder%4):(encoder%4)-3);		//remapping of encoder actual <-> logical
		byte=0;

	/*	if(encoder==5){
			if(incrementer>=1) {
				byte=readEditBuffer(buffer_view);
				debugi(buffer_view);
				if(buffer_view<512)
					buffer_view++;
				debugb(byte);
			}
			else {
				byte=readEditBuffer(buffer_view);
				debugi(buffer_view);
				if(buffer_view)
					buffer_view--;
				debugb(byte);
			}
		return;
		}


		writeBank(0x7FFFFL,0xFF);

		if(encoder==6){
			if(incrementer>=1) {
//				if(storage_view<512)
				storage_view++;
				byte=readBank(storage_view);
//				debugl(storage_view);
				debugb(byte);
			}
			else {
				if(storage_view)
					storage_view--;
				byte=readBank(storage_view);
//				debugl(storage_view);
				debugb(byte);
			}
		return;
		}

*/

		//like in DIN_NotifyToggle
		if(get_userdata)
			return;

		if (eb_request.active)
			return;

		if (eb_request.error)
			return;

		//like in DIN_NotifyToggle
		if(modus==MOD_PARAMETER) {

			if (encoder<=7) {										//choosing array of left or right encoders
				param = &parametersleft[encoder];
			}
			else
			if (encoder>7) {
				param = &parametersright[encoder%8];
			}

			if(!((param->messageChannel)&0xF0))						//return if mode=OFF
				return;

			if((param->modeSelect)&0x08)							//only react if mode "Encoder"
				return;

			if((param->modeSelect)&0x04)							//Set acceleration 2 for 7Bit, 6 for 14Bit
				MIOS_ENC_SpeedSet(encoderold, MIOS_ENC_SPEED_FAST, ((param->modeSelect)&0x02)*2+2);
			else
				MIOS_ENC_SpeedSet(encoderold, MIOS_ENC_SPEED_NORMAL,0);

			if(!((param->modeSelect)&0x02)) {					//check 7Bit
				max=(char)(param->valueMax[0]);
				min=(char)(param->valueMin[0]);

				if((param->modeSelect)&0x01) {					//check negative
					max=64+max;
					min=64-min;
				}

				if(param->scale==0x00) {								//Max and Min for 7 and 14 Bit depending on scale
					if (max==min)										//prevent division through zero
						max++;
					stepwidth=(max-min);
					min=0x00;
					max=0x7F;
				}
			}
			else
				if((param->modeSelect)&0x02) {						//check 14Bit
					max=((int)((param->valueMax[0])<<7)|(int)(param->valueMax[1]));
					min=((int)((param->valueMin[0])<<7)|(int)(param->valueMin[1]));
					if((param->modeSelect)&0x01) {					//check negative
						max=8192+max;
						min=8192-min;
						}
					if(param->scale==0x00) {								//Max and Min for 7 and 14 Bit depending on scale

						if (max==min)										//prevent division through zero
							max++;
						stepwidth=(max-min);
						min=0x00;
						max=((((param->modeSelect)&0x02)>>1)*0x7F)<<7|0x7F;
					}
				}

			if (param->scale==0)
				potis[encoder]+=incrementer;
			else
				if (param->scale!=0) {
					if(incrementer>0)
						potis[encoder]+=param->scale*incrementer;
					if(incrementer<0)
						potis[encoder]-=param->scale*((~incrementer)+1);
				}

			if(potis[encoder]<min)
				potis[encoder]=min;
			if(potis[encoder]>max)
				potis[encoder]=max;

			potis[16]|=1<<encoder;
			update|=0x02;

			//addr+=(unsigned long)(incrementer);
			//debugl(addr);
			//writeBank(addr,0x00);


			sendMessage(encoder,(incrementer*(param->scale+(((param->scale-1)>>7)&0x01))));  //sendMessage build & send dynamic midi message depending on encoder nr
	}

}
