#include "../../include/gui/gui.h"


void DrawWidget(SDL_Window* window, SDL_Renderer* renderer, SDL_Texture* font, 
		Widget* widget, AlsaData* alsa_data, PlayerData* player_data, TimelineData* timeline_data) {

	//set color, lower opacity if mouse is hovering
	if (widget->hover && widget->actionType != BUTTON_TYPE_NULL) {
		
		SDL_SetRenderDrawColor(renderer, widget->r, widget->g, widget->b, (int)((float)widget->a * 0.75));
	} else {
		SDL_SetRenderDrawColor(renderer, widget->r, widget->g, widget->b, widget->a); 
	}

	//get screen dimensions
	int stretchW, stretchH = 0;
	SDL_GetWindowSize(window, &stretchW, &stretchH);

		
	//offset from edges of window
	if (widget->offsetX) { 
		
		widget->x = stretchW - widget->savex;
	       	if (widget->dividex > 0.0) { widget->x = (int)((double)stretchW * widget->dividex) + widget->savex; }
	}
	if (widget->offsetY) { 
		
		widget->y = stretchH - widget->savey; 
	       	if (widget->dividey > 0.0) { widget->y = (int)((double)stretchH * widget->dividey) + widget->savey; }
	}


	//stretch to specified dimensions
	if (widget->stretchWidth) { 
		
		widget->w = stretchW - widget->x; 
		//if (widget->dividew > 0.0) { widget->w = (int)((double)stretchW * widget->dividew) - widget->savex; }
		if (widget->dividew > 0.0) { widget->w = (int)((double)(stretchW - widget->savex) * widget->dividew); }
	} else {
		if (widget->offsetW) { widget->w = stretchW - (widget->x + widget->savew); }
	}
	
	if (widget->stretchHeight) { 
		
		widget->h = stretchH - widget->y; 
		//if (widget->divideh > 0.0) { widget->h = (int)((double)(stretchH) * widget->divideh) - widget->savey; }
		if (widget->divideh > 0.0) { widget->h = (int)((double)(stretchH - widget->savey) * widget->divideh); }
	} else {
		if (widget->offsetH) { widget->h = stretchH - (widget->y + widget->saveh); }
	}
	
	//create drawing rectangle	
	SDL_Rect rect;
	rect.x = widget->x;
	rect.y = widget->y;
	rect.w = widget->w;
	rect.h = widget->h;
	

	//draw actual rectangle/image
	if (widget->texture != NULL) {
	
		//draw full texture
		SDL_RenderCopy(renderer, widget->texture, NULL, &rect);
	} else {
		//draw rectangle with given color, finally
		SDL_RenderFillRect(renderer, &rect);
	}


	//add gradient
	if (widget->shade != 0.0) {
		
		SDL_Rect shadeRect;
		shadeRect.x = rect.x;
		shadeRect.y = rect.y;
		shadeRect.w = 2;
		shadeRect.h = rect.h;
		
		uint16_t shadeW = widget->w*widget->shade;

		if (widget->shade > 0.0) {
		
			for (int i = 0; i < shadeW; i += 2) {
		
				SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255-(int)(255*((float)i/(float)shadeW)));
				SDL_RenderFillRect(renderer, &shadeRect);
				shadeRect.x += 2;
			}
		} else {
			shadeRect.x = (rect.x+widget->w)-2;
			for (int i = 0; i < shadeW; i += 2) {

				SDL_SetRenderDrawColor(renderer, 0, 0, 0, (int)(255*((float)i/(float)shadeW)));
				SDL_RenderFillRect(renderer, &shadeRect);
				shadeRect.x -= 2;
			}
		}
	}


	//for animations/update every frame
	switch (widget->actionType) {
	
		//list files
		case BUTTON_TYPE_FILE_SELECT:
			if (widget->list) {
			
				//draw rectangle to contain list
				rect.y += rect.h;
				rect.h = stretchH;
				if (widget->offsetY) { rect.y = 0;		     rect.h = widget->y; 
				} else {	       rect.y = widget->y+widget->h; rect.h = stretchH; }
				SDL_SetRenderDrawColor(renderer, 0, 0, 0, 128);
				SDL_RenderFillRect(renderer, &rect);
							
				if (widget->offsetY) { rect.y = widget->y-26;
				} else {	       rect.y = widget->y+widget->h; }
				rect.h = 26;
				
				//print files
				for (int i = widget->listOffset; i < player_data->fileCountCopy; i++) {
				
					//highlight currently selected file
					if (i == player_data->fileTarget) {
					
						SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
						SDL_RenderFillRect(renderer, &rect);
					}
					PrintText(player_data->fileListCopy[i], renderer, font, widget->x+widget->textx, rect.y);
				
					if (widget->offsetY) { rect.y -= 26;
					} else {	       rect.y += 26; }
				}
			}
			break;

		//file progress
		case BUTTON_TYPE_PLAYBAR:
			widget->slide = (float)((double)player_data->fileIndex / (double)player_data->fileSize);
			break;
		
		//DAW timeline
		case BUTTON_TYPE_TIMELINE:
			{
				SDL_Rect newRect;
				uint32_t guiBeatLength = (widget->w / timeline_data->scrollLength) + 1;
				double guiBeatLength16 = ((double)guiBeatLength-1)/16.0;
				
				//print mode of timeline
				PrintText("MODE: ", renderer, font, widget->x+200, widget->y);
				
				if (timeline_data->mode == 0) { 	PrintText("MOVE", renderer, font, widget->x+200+(18*6), widget->y);
				} else if (timeline_data->mode == 1) {  PrintText("CUT", renderer, font, widget->x+200+(18*6), widget->y);
				} else if (timeline_data->mode == 2) {  PrintText("COPY", renderer, font, widget->x+200+(18*6), widget->y);
				} else if (timeline_data->mode == 3) {  PrintText("DELETE", renderer, font, widget->x+200+(18*6), widget->y);
				}
				
				//PrintNumbers(timeline_data->mode, renderer, font, widget->x+200+(18*6), widget->y);
			
				//update autoscroll
				if (player_data->playing == true && timeline_data->autoScroll == true 
						&& timeline_data->currentBeat >= (timeline_data->scrollLength*8)) {
			
					timeline_data->scrollOffset = timeline_data->currentBeat-timeline_data->scrollLength*8;
				}

				
				//draw timeline beats, bars, etc.
				newRect.x = widget->x-(((int)((double)timeline_data->scrollOffset*guiBeatLength16))%guiBeatLength);
				newRect.y = widget->y + 26;
				newRect.w = guiBeatLength;
				newRect.h = 52+1;
				SDL_SetRenderDrawColor(renderer, widget->r2, widget->g2, widget->b2, widget->a2);
				
				if (guiBeatLength > 4) {

					for (int j = 0; j < timeline_data->scrollLength; j++) {
					
						//beats
						for (int i = 0; i < ((widget->h-26)/52); i++) {
					
							SDL_RenderDrawRect(renderer, &newRect);
							newRect.y += 52;
						}
						newRect.x += (newRect.w-1);
						newRect.y = widget->y + 26;
					}
				}
				
				//bars
				//newRect.x = widget->x;
				newRect.x = widget->x-(((int)((double)timeline_data->scrollOffset*guiBeatLength16))%((guiBeatLength-1)*8));
				newRect.y = widget->y + 26;
				newRect.w = (guiBeatLength-1)*4;
				newRect.h = widget->h;
				SDL_SetRenderDrawColor(renderer, 255, 255, 255, 16);
				for (int j = 0; j < timeline_data->scrollLength; j += 8) {
						
					SDL_RenderFillRect(renderer, &newRect);
					newRect.x += newRect.w*2;
				}

				
				
				newRect.x = widget->x;
				newRect.y = widget->y + 26;
				newRect.w = widget->w / (timeline_data->scrollLength*16);
				newRect.h = 52;
				SDL_SetRenderDrawColor(renderer, widget->r2, widget->g2, widget->b2, widget->a2);

				//draw tracks and samples on tracks
				for (int i = 0; i < timeline_data->sampleNum; i++) {	
		
					Sample* sample = timeline_data->samples[i];

					
					if ((sample->beatOffset+sample->beatCropFront < timeline_data->scrollOffset+(timeline_data->scrollLength*16))
					|| (sample->beatOffset+sample->beatLength-sample->beatCropBack < timeline_data->scrollOffset+(timeline_data->scrollLength*16))
					|| (sample->beatOffset+sample->beatCropFront < timeline_data->scrollOffset 
						&& sample->beatOffset+sample->beatLength-sample->beatCropBack > timeline_data->scrollOffset+(timeline_data->scrollLength*16))) {
					
						/*
						SDL_SetRenderDrawColor(renderer, timeline_data->samples[i]->color >> 24, 
										 timeline_data->samples[i]->color >> 16, 
										 timeline_data->samples[i]->color >> 8, widget->a2);
						*/
						SDL_SetRenderDrawColor(renderer, widget->r2, widget->g2, widget->b2, widget->a2/2);
						
						//newRect.w = widget->w / timeline_data->scrollLength;
						newRect.w = sample->beatLength - (sample->beatCropBack+sample->beatCropFront); 
						newRect.x = widget->x + (int)(guiBeatLength16 * (double)(sample->beatOffset+sample->beatCropFront-timeline_data->scrollOffset));
						newRect.y = widget->y + (sample->track*52)+26;
					
						if (newRect.x < widget->x) { newRect.x = widget->x; }
						
						if (newRect.w >= timeline_data->scrollLength*16) { 
 
						 	newRect.w = widget->w;
						} else {
							if ((long)((long)timeline_data->scrollOffset-(sample->beatOffset+sample->beatCropFront)) > 0) {
						
								newRect.w -= timeline_data->scrollOffset-(sample->beatOffset+sample->beatCropFront);
							}
							newRect.w = (int)((double)newRect.w * guiBeatLength16);
						}
						

						SDL_RenderFillRect(renderer, &newRect);
						SDL_SetRenderDrawColor(renderer, 255, 255, 255, 32);
						SDL_RenderFillRect(renderer, &newRect);

					
						//visualize data of audio
						SDL_SetRenderDrawColor(renderer, 255, 255, 255, 128);
					
						
						int dataSubSample = 1;
						if (newRect.w > 0) { dataSubSample = (sample->dataSize / alsa_data->buff_size) / newRect.w; }
					
						//length of data visualization in pixels	
						uint32_t frontCropOffset = (uint32_t)((double)sample->beatCropFront * guiBeatLength16);
						uint32_t realLength = (uint32_t)((((double)timeline_data->bpm) * (sample->seconds/60.0)) * guiBeatLength16 * 16.0) + 1; 
							
						if ((long)((long)timeline_data->scrollOffset-(sample->beatOffset+sample->beatCropFront)) > 0) {
						
							frontCropOffset += (uint32_t)((double)(timeline_data->scrollOffset-(sample->beatOffset+sample->beatCropFront)) * guiBeatLength16);
						}


						for (int j = frontCropOffset; j < (realLength - (uint32_t)((double)sample->beatCropBack * guiBeatLength16)); j++) {
					
							int soundDataIndex = (int)(((double)sample->dataSizeGUI) * (((double)j)/((double)realLength))) 
								+ (sample->cropOffset*16);
							
							if (soundDataIndex < sample->dataSizeGUI) {

								SDL_RenderDrawLine(renderer, (j-frontCropOffset)+newRect.x, newRect.y+(sample->dataPoints[soundDataIndex]), 
											     (j-frontCropOffset)+newRect.x, newRect.y+newRect.h);
							}
						}
				
						//print text of samples
						PrintText(timeline_data->files[i], renderer, font, newRect.x, newRect.y);
						//PrintText("CHNL: ", renderer, font, newRect.x, newRect.y+26);
						//PrintNumbers(timeline_data->samples[i]->channel, renderer, font, newRect.x+6*18, newRect.y+26);
					}
				}

				
				//highlight current track target
				SDL_SetRenderDrawColor(renderer, 255, 255, 255, 32);
				rect.y += (timeline_data->currentTrack*52)+26;
				rect.w = newRect.w*timeline_data->scrollLength*16;
				rect.h = 52;
				SDL_RenderFillRect(renderer, &rect);

					
				//marker for where current beat is
				SDL_SetRenderDrawColor(renderer, widget->g2, widget->b2, widget->r2, widget->a2);
				SDL_RenderDrawLine(renderer, 
						widget->x+(int)(((double)(timeline_data->currentBeat-timeline_data->scrollOffset)/16.0)*((double)(guiBeatLength-1))), 
						widget->y, 
						widget->x+(int)(((double)(timeline_data->currentBeat-timeline_data->scrollOffset)/16.0)*((double)(guiBeatLength-1))), 
						widget->y+widget->h);
			
			}
			break;
	}

	//draw slide
	if (widget->sliderType) {
			
		switch (widget->sliderType) {
		
			//horizontal slide
			case 1:
			case 3:
				rect.w = (int)(widget->slide*((float)widget->w));
				break;
			//vertical slide
			case 2:
			case 4:
				rect.h = (int)(widget->slide*((float)widget->h));
				rect.y += (widget->h - rect.h);
				break;
			//2d slide
			case 5:
				rect.x = (int)(widget->slide*((float)widget->w));
				rect.y = (int)(widget->slide*((float)widget->h));
				rect.w = 10;
				rect.h = 10;
				break;
			default:break;
		}
		
		//use second image for slide, 
		//or draw new rectangle
		if (widget->texture2 != NULL) {
				
			SDL_Rect slideRect = rect;

			switch (widget->sliderType) {
			
				case 3:
					slideRect.x = (rect.x+rect.w) - widget->texture2_w/2;
					slideRect.w = widget->texture2_w;
					SDL_RenderCopy(renderer, widget->texture2, NULL, &slideRect);
					break;
				case 4:
					slideRect.y = (rect.y) - widget->texture2_h/2;
					slideRect.h = widget->texture2_h;
					SDL_RenderCopy(renderer, widget->texture2, NULL, &slideRect);
					break;
				default:
					SDL_RenderCopy(renderer, widget->texture2, &rect, &rect);
					break;
			}
		} else {
			SDL_SetRenderDrawColor(renderer, widget->r2, widget->g2, widget->b2, widget->a2);
			SDL_RenderFillRect(renderer, &rect);
		}
	}
	//draw text last
	PrintText(widget->text, renderer, font, widget->x+widget->textx, widget->y+widget->texty);
}


bool WidgetClicked(int mouseX, int mouseY, Widget* widget) {

	if (mouseX > widget->x && 
		mouseY > widget->y &&
		mouseX < (widget->x+widget->w) && 
		mouseY < (widget->y+widget->h)) {

		return true;
	}
	
	return false;
}

bool ListClicked(int mouseX, int mouseY, Widget* widget, int w, int h) {
	
	
	if (widget->list && 
		mouseX > widget->x && mouseX < (widget->x+widget->w)) {

		if (widget->offsetY == false && 
				mouseY > (widget->y+widget->h) && 
	    			mouseY < ((widget->y+widget->listNum-1)*26)) {
	
				return true;
		}
			
		if (widget->offsetY == true && 
				mouseY < widget->y &&
		   		mouseY > 0) {
		   		//mouseY > h-(widget->h+(widget->listNum*26))) {
	
			return true;
		}
	}
	return false;
}

int ListAction(int mouseX, int mouseY, Widget* widget, PlayerData* player_data, TimelineData* timeline_data) {

	int listSelect = 0;

	//calculate which object in list was selected
	if (widget->offsetY) { listSelect = widget->listOffset-((mouseY-widget->y)/26);
	} else {	       listSelect = ((mouseY-(widget->y+widget->h))/26)+widget->listOffset; }

	switch (widget->actionType) {

		case BUTTON_TYPE_FILE_SELECT:

			//select file for playback
			if (listSelect == player_data->fileTarget) {
		
				//include check if file actually exists or is readable later
				player_data->file = player_data->fileListCopy[listSelect];
			
				//interrupt current file and play the next
				player_data->stop = true;
			} else {
				//select file to highlight,
				//if clicked again, its played
				if (listSelect <= player_data->fileCountCopy) {
			
					player_data->fileTarget = listSelect;
				}
			}
			player_data->dragFile = player_data->fileListCopy[listSelect];
		break;
		default:break;
	}
	return player_data->fileTarget;
}


void ButtonAction(int mouseX, int mouseY,
		Widget* widget,	
		AlsaData* alsa_data,
		PlayerData* player_data, 
		TimelineData* timeline_data, 
		uint8_t button) {

	if (button == 0) {
	
		//determine slider level if there	
		switch (widget->sliderType) {
		
			case 1:
			case 3:
				widget->slide = ((float)(mouseX-widget->x))/((float)widget->w);
				break;
			case 2:
			case 4:
				widget->slide = 1.0 - ((float)(mouseY-widget->y))/((float)widget->h);
				break;
			default:break;
		}

		//what happens when a user clicks on button?
		switch (widget->actionType) {
	
			case BUTTON_TYPE_FILE_SELECT:
				
				widget->list ^= 1;
				break;

			case BUTTON_TYPE_PAUSE:
				
				player_data->playing ^= 1;
				if (player_data->playing) { UpdateWidgetText("Pause ||", widget);
				} else { 		    UpdateWidgetText("Play |>", widget); }

				//recet timeline bpm marker
				gettimeofday(&(timeline_data->t0), NULL);
				break;

			case BUTTON_TYPE_PLAYBAR:
				
				player_data->fileIndex = (uint32_t)((float)player_data->fileSize * widget->slide);
				break;

			case BUTTON_TYPE_VOLUME:
				
				//y = 0.01*e^(x*4.615) is a nice curve, 
				//subtracting 0.01 makes no slide 0, and full slide very close to 1
				player_data->volume = (0.01 * exp(widget->slide * 4.615)) - 0.01;
			
				//slider is close enough, make it full vol
				if ((1.0 - player_data->volume) < 0.0005) {
			
					player_data->volume = 1.0;
				}

				//slider is close enough, make it mute
				if ((1.0 - player_data->volume) > 0.9995) {
			
					player_data->volume = 0.0;
				}
				break;

			case BUTTON_TYPE_FILE_SEARCH:
				
				for (int i = 0; i < 64; i++) { player_data->fileSearch[i] = '\0'; }
				player_data->fileSearchIndex = 0;
				UpdateWidgetText("_", widget);
				break;

			case BUTTON_TYPE_AUDIO_RATE:
				
				for (int i = 0; i < 6; i++) { player_data->rateStr[i] = '\0'; }
				player_data->rateInputIndex = 0;
				player_data->rate = 44100;
				UpdateWidgetText("44100", widget);
				break;
			
			case BUTTON_TYPE_TIMELINE:
				{
				timeline_data->previousBeat = timeline_data->currentBeat;
				timeline_data->currentBeat = (uint32_t)((((double)(mouseX-widget->x)/((double)widget->w))*((double)(timeline_data->scrollLength*16))));
				timeline_data->currentBeat += timeline_data->scrollOffset+1;
				
				//current beat snaps to 16th or whole depending on scroll length
				if (timeline_data->scrollLength > 16) {

					uint8_t snapBeat = timeline_data->currentBeat % 16;
					if (snapBeat < 8) { timeline_data->currentBeat -= snapBeat; 
					} else { 	    timeline_data->currentBeat += 16-snapBeat; }
				}
			
				gettimeofday(&(timeline_data->t0), NULL);
				
			
				//reset sample playing so timeline can play appropriate audio date when currentBeat changes
				for (int i = 0; i < timeline_data->sampleNum; i++) { timeline_data->samples[i]->playing = false; }


				if ((mouseY-widget->y) >= 26) {
					
					timeline_data->previousTrack = timeline_data->currentTrack;	
					timeline_data->currentTrack = ((float)((mouseY-widget->y)-26))/(52.0);
					
					//move sample on timeline
					if (timeline_data->sampleTarget != NULL && timeline_data->mode == 0) {
				
						Sample* sample = timeline_data->sampleTarget;
				
						//change track of sample
						sample->track = timeline_data->currentTrack;
						int beatDifference = timeline_data->currentBeat - timeline_data->previousBeat;

						if (sample->beatOffset+sample->beatCropFront+beatDifference < 0) {
						
							timeline_data->currentBeat = timeline_data->previousBeat;
							beatDifference = 0;
						}


						//cropping audio samples
						//cropping the front
						if ((timeline_data->targetBeat >= sample->beatOffset + sample->beatCropFront)
							&& (timeline_data->targetBeat < sample->beatOffset + sample->beatCropFront + timeline_data->scrollLength / 8)) {
								
							if ((beatDifference > 0 && sample->beatCropFront < (sample->beatLength - sample->beatCropBack) - (beatDifference + 1))
								|| (beatDifference < 0 && sample->beatCropFront > -beatDifference)) {
							
								sample->beatCropFront += beatDifference;
							}

						//cropping the back
						} else if ((timeline_data->targetBeat < (sample->beatOffset + sample->beatLength - sample->beatCropBack)) 
							&& (timeline_data->targetBeat >= (sample->beatOffset + sample->beatLength 
									- sample->beatCropBack) - timeline_data->scrollLength / 8)) {
						
							if ((beatDifference < 0 && sample->beatCropBack < sample->beatLength - sample->beatCropFront) 
								|| (beatDifference > 0 && sample->beatCropBack > beatDifference + 1)) {
							
								sample->beatCropBack -= beatDifference;
							}

						//moving audio samples
						} else {
							if ((beatDifference > 0 && sample->beatOffset + sample->beatLength+beatDifference < 4096*16)
								|| (beatDifference < 0 && sample->beatOffset + sample->beatCropFront+beatDifference >= 0)) { 
								
								sample->beatOffset += beatDifference;
							}
						}
						
						//prevent sample from being dragged beyond timeline	
						if ((int32_t)((int32_t)sample->beatOffset + sample->beatCropFront) < 0) {
						
							sample->beatOffset = (int32_t)(-sample->beatCropFront);
							timeline_data->sampleTarget = NULL;
						}
					}

								
					//cutting samples
					if (timeline_data->mode == 1 && timeline_data->sampleLastClicked != NULL) {
						
						Sample* sample = timeline_data->sampleLastClicked;
						
						if (timeline_data->currentBeat > sample->beatOffset+sample->beatCropFront
						&& timeline_data->currentBeat < sample->beatOffset+sample->beatLength-sample->beatCropBack) {
							
				
							//create new one from the last cut
							timeline_data->samples[timeline_data->sampleNum] = CreateSample(NULL, timeline_data, sample,
								(timeline_data->currentBeat-sample->beatCropFront),
								//timeline_data->currentBeat-((timeline_data->currentBeat-sample->beatOffset)),
								sample->cropOffset,
								(timeline_data->currentBeat-sample->beatOffset),
								//(timeline_data->currentBeat-sample->beatOffset)+sample->beatCropBack,
								sample->beatCropBack,
								//sample->beatCropBack - sample->beatLength-((timeline_data->currentBeat-sample->beatOffset)+sample->beatCropBack),
								sample->track);
						
							//newRect.w = sample->beatLength - (sample->beatCropBack + sample->beatCropFront); 
						
							if (timeline_data->samples[timeline_data->sampleNum] != NULL) {
									
								timeline_data->files[timeline_data->sampleNum] = 
									timeline_data->files[timeline_data->samples[timeline_data->sampleNum]->fileIndex];
								
								timeline_data->sampleNum++;
							} else {
								timeline_data->files[timeline_data->sampleNum] = NULL;
							}
							
							//cut original sample	
							sample->beatCropBack += sample->beatLength-((timeline_data->currentBeat-sample->beatOffset)+sample->beatCropBack);
						}
					}

					
					
					//copying samples
					if (timeline_data->sampleLastClicked != NULL && timeline_data->mode == 2) {
				
						bool copy = true;
						for (int i = 0; i < timeline_data->sampleNum; i++) {
						
							Sample* sample = timeline_data->samples[i];

							if (timeline_data->currentBeat >= sample->beatOffset+sample->beatCropFront
							&& timeline_data->currentBeat < sample->beatOffset+sample->beatLength-sample->beatCropBack
							&& timeline_data->currentTrack == sample->track) {
							
								copy = false;
								break;
							}
						}

						if (copy == true) {

							timeline_data->samples[timeline_data->sampleNum] = CreateSample(NULL, 
													timeline_data, 
													timeline_data->sampleLastClicked,
													timeline_data->currentBeat-timeline_data->sampleLastClicked->beatCropFront,
													timeline_data->sampleLastClicked->cropOffset,
													timeline_data->sampleLastClicked->beatCropFront,
													timeline_data->sampleLastClicked->beatCropBack,
													timeline_data->currentTrack);
							int i = 0;
							for (i; i < timeline_data->sampleNum; i++) {
								if (timeline_data->samples[i] == timeline_data->sampleLastClicked) { break; }
							}

							if (timeline_data->samples[timeline_data->sampleNum] != NULL) {
						
								timeline_data->files[timeline_data->sampleNum] = timeline_data->files[i];
								timeline_data->sampleNum++;
							} else {
								timeline_data->files[timeline_data->sampleNum] = NULL;
							}
						}
					}
					

					//init and find max length for project length
					timeline_data->projectLength = 0;

					//go through samples
					for (int i = 0; i < timeline_data->sampleNum; i++) {
				
						Sample* sample = timeline_data->samples[i];

						//target sample
						if (timeline_data->currentBeat >= sample->beatOffset+sample->beatCropFront
						&& timeline_data->currentBeat < sample->beatOffset+sample->beatLength-sample->beatCropBack) {
						
							if (sample->track == timeline_data->currentTrack) {
								
								timeline_data->sampleTarget = sample;
								timeline_data->sampleLastClicked = sample;
								timeline_data->previousBeat = timeline_data->currentBeat;
								timeline_data->targetBeat = timeline_data->currentBeat;
					

								//delete samples
								if (timeline_data->mode == 3) {
						
									timeline_data->files[i] = NULL;	
									bool copyStr = false;

									for (int j = 0; j < timeline_data->sampleNum; j++) {
										
										if (timeline_data->samples[i]->fileIndex == timeline_data->samples[j]->fileIndex && i != j) {
										
											copyStr = true;
										}
									}
									if (copyStr == false) { free(timeline_data->files[i]); }
									
									DestroySample(timeline_data->samples[i]);
									
									timeline_data->files[i] = NULL;
									timeline_data->samples[i] = NULL;
									timeline_data->sampleTarget = NULL;
									timeline_data->sampleLastClicked = NULL;
								
									for (int j = i; j < timeline_data->sampleNum; j++) {
								
										timeline_data->files[j] = timeline_data->files[j+1];
										timeline_data->samples[j] = timeline_data->samples[j+1];
									}
									timeline_data->sampleNum--;
									
									printf("Sample \"%s\" deleted from project.\n", timeline_data->files[i]);
								}
							}
						}

						//find real project length
						if (sample->beatOffset+sample->beatLength-sample->beatCropBack > timeline_data->projectLength) {

							timeline_data->projectLength = sample->beatOffset+sample->beatLength-sample->beatCropBack;
						}
					}
				}
				
				}
				break;

			case BUTTON_TYPE_SCROLL:
				
				if (timeline_data->projectLength > timeline_data->scrollLength) {
				
					timeline_data->scrollOffset = (uint32_t)((double)timeline_data->projectLength * widget->slide);
				} else {
					timeline_data->scrollOffset = 0;
				}
				break;
			
			case BUTTON_TYPE_BPM:
				break;
			
			case BUTTON_TYPE_RESET:
				
				timeline_data->currentBeat = 0;
				timeline_data->scrollOffset = 0;
				gettimeofday(&(timeline_data->t0), NULL);
				//player_data->playing = false;
				//UpdateWidgetText("Play |>", widget);
				
				break;


			case BUTTON_TYPE_PROJECT_FILE:
				break;
			
			case BUTTON_TYPE_SAVE_PROJECT:

				if (timeline_data->projectFile[0] != '\0') {
					/*
					timeline_data->projectFile[timeline_data->projectFileIndex] = '.';
					timeline_data->projectFile[timeline_data->projectFileIndex+1] = 'k';
					timeline_data->projectFile[timeline_data->projectFileIndex+2] = 'y';
					timeline_data->projectFile[timeline_data->projectFileIndex+3] = 's';
					timeline_data->projectFile[timeline_data->projectFileIndex+4] = '\0';
					*/
					memcpy(timeline_data->projectFile+timeline_data->projectFileIndex, ".kys\0", 5);

					if (SaveProject(timeline_data->projectFile, player_data, timeline_data)) 
						{printf("Unable to save project.\n");
					} else { printf("Project has been saved.\n"); }
				}
				break;
			
			case BUTTON_TYPE_READ_PROJECT:
				
				if (timeline_data->projectFile[0] != '\0') {	
					/*
					timeline_data->projectFile[timeline_data->projectFileIndex] = '.';
					timeline_data->projectFile[timeline_data->projectFileIndex+1] = 'k';
					timeline_data->projectFile[timeline_data->projectFileIndex+2] = 'y';
					timeline_data->projectFile[timeline_data->projectFileIndex+3] = 's';
					timeline_data->projectFile[timeline_data->projectFileIndex+4] = '\0';
					*/
					memcpy(timeline_data->projectFile+timeline_data->projectFileIndex, ".kys\0", 5);
				
					if (ReadProject(timeline_data->projectFile, player_data, timeline_data)) 
						{printf("Unable to read project.\n");
					} else { printf("Project successfully loaded.\n"); }
				}
				break;
			
			case BUTTON_TYPE_EXPORT_PROJECT:

				if (timeline_data->projectFile[0] != '\0') {	
					
					memcpy(timeline_data->projectFile+timeline_data->projectFileIndex, ".wav\0", 5);
					
					if (ExportProject(timeline_data->projectFile, player_data, timeline_data, alsa_data)) 
						{printf("Unable to export project.\n");
					} else { printf("Project successfully exported.\n"); }
				}
				break;
			
			//nonbutton for drawing images
			case BUTTON_TYPE_NULL:break;
		
			default:break;
		}

	//mouse scroll
	} else if (button == 1) {

		switch (widget->actionType) {
		
			case BUTTON_TYPE_TIMELINE:
				{
				if ((mouseY-widget->y) >= 26) {
					
					timeline_data->previousTrack = timeline_data->currentTrack;
					timeline_data->currentTrack = ((float)((mouseY-widget->y)-26))/(52.0);
				}	
				bool scrollUp = player_data->event.wheel.y < 0;
				bool sampleFound = false;

				//target sample
				for (int i = 0; i < timeline_data->sampleNum; i++) {
					
					if (timeline_data->samples[i]->track == timeline_data->currentTrack 
					&& timeline_data->currentBeat >= timeline_data->samples[i]->beatOffset+timeline_data->samples[i]->beatCropFront
					&& timeline_data->currentBeat < timeline_data->samples[i]->beatOffset+
									timeline_data->samples[i]->beatLength-timeline_data->samples[i]->beatCropBack) {

						//if (scrollUp) { timeline_data->samples[i]->channel -= (1 * timeline_data->samples[i]->channel > 0); 
						//} else { 	timeline_data->samples[i]->channel += (1 * timeline_data->samples[i]->channel < 100); }
						sampleFound = true;
						
						if (scrollUp) { timeline_data->samples[i]->cropOffset -= (1 * timeline_data->samples[i]->cropOffset > 0); 
						} else { 	timeline_data->samples[i]->cropOffset += (1 * timeline_data->samples[i]->cropOffset < 
								(timeline_data->samples[i]->dataSize / alsa_data->buff_size) - 1); }
					}
				}

				//zoom in or out
				if (scrollUp) {
					if (!sampleFound && timeline_data->scrollLength < 4096) { timeline_data->scrollLength *= 2; }
				} else {
					if (!sampleFound && timeline_data->scrollLength > 8) { timeline_data->scrollLength /= 2; }
				}
				
				}
				break;
			
			case BUTTON_TYPE_SCROLL:
				break;
			
			case BUTTON_TYPE_BPM:
				
				if (player_data->event.wheel.y >= 0) {
					
					timeline_data->bpm++;
				} else {
					timeline_data->bpm--;
				}
				
				//set new beat length for samples in new bpm
				AdjustSampleBeats(alsa_data, timeline_data);
				
				timeline_data->bpmStr[5] = '0'+(timeline_data->bpm/100);
				timeline_data->bpmStr[6] = '0'+((timeline_data->bpm%100)/10);
				timeline_data->bpmStr[7] = '0'+(timeline_data->bpm%10);
				UpdateWidgetText(timeline_data->bpmStr, widget);

				break;

			default:break;
		}

	//mouse button up
	} else {
		switch (widget->actionType) {
			
			case BUTTON_TYPE_TIMELINE:
				
				if ((mouseY-widget->y) > 26) {
				
					timeline_data->currentTrack = ((float)((mouseY-widget->y)-26))/(52.0);
				}
				timeline_data->previousBeat = timeline_data->currentBeat;
				timeline_data->currentBeat = (uint32_t)(((double)(mouseX-widget->x)/((double)widget->w)*((double)(timeline_data->scrollLength*16))));
				timeline_data->currentBeat += timeline_data->scrollOffset;
				
				//current beat snaps to 16th or whole depending on scroll length
				if (timeline_data->scrollLength > 16) { 
					
					uint8_t snapBeat = timeline_data->currentBeat % 16;
					if (snapBeat < 8) { timeline_data->currentBeat -= snapBeat; 
					} else { 	    timeline_data->currentBeat += 16-snapBeat; }
				}	
				
				//import audio file as sample
				if (player_data->dragFile != NULL) {
			
					if (ImportSample(timeline_data, player_data->dragFile, 0, 0) < 0) {
					
						//error here
					}
				}
				
				//check for new project length
				for (int i = 0; i < timeline_data->sampleNum; i++) { 
					
					Sample* sample = timeline_data->samples[i];

					//find real project length
					if (sample->beatOffset+sample->beatLength-sample->beatCropBack > timeline_data->projectLength) {

						timeline_data->projectLength = sample->beatOffset+sample->beatLength-sample->beatCropBack;
					}
				}

				break;
		
			default:break;
		}
		player_data->dragFile = NULL;
		timeline_data->sampleTarget = NULL;
		timeline_data->targetBeat = 0;
	}
}


void GraphicalInput(char key, Widget* widget, uint8_t* strIndex, uint8_t maxIndex, char* str) {

	switch (key) {
		
		case '\b':
			if (*strIndex > 0) {
				
				str[*strIndex] = '\0';
				
				*strIndex -= 1;
				str[*strIndex] = '_';
			}
			break;
		default:
			if (key >= 32 && key <= 126 && *strIndex < maxIndex) {
				
				str[*strIndex] = key;
				
				*strIndex += 1;
				str[*strIndex] = '_';
				
				str[*strIndex + 1] = '\0';
			}
			break;
	}
	UpdateWidgetText(str, widget);
	str[*strIndex] = '\0';
}


void KeyboardAction(char key, Widget* widget, AlsaData* alsa_data, PlayerData* player_data, TimelineData* timeline_data) {

	switch (widget->actionType) {
	
		case BUTTON_TYPE_FILE_SELECT:
			break;
		
		case BUTTON_TYPE_PAUSE:
			
			if (key == ' ') {
				ButtonAction(widget->x, widget->y, widget, alsa_data, player_data, timeline_data, true);	
			}
			break;
		
		case BUTTON_TYPE_FILE_SEARCH:
			
			GraphicalInput(key, widget, &(player_data->fileSearchIndex), 64, player_data->fileSearch);
			player_data->fileCountCopy = 0;

			//check if file matches search
			if (player_data->fileSearch[0] != '\0') {	
					
				for (int i = 0; i < player_data->fileCount; i++) {

					if (strstr(player_data->fileList[i], player_data->fileSearch) != NULL) {
						
						player_data->fileListCopy[player_data->fileCountCopy] = player_data->fileList[i];
						player_data->fileCountCopy++;
					}
				}
			} else {
				for (int i = 0; i < player_data->fileCount; i++) {
					
					player_data->fileListCopy[i] = player_data->fileList[i];
					player_data->fileCountCopy++;
				}
				UpdateWidgetText("Search for files", widget);
			}
			break;
		
		case BUTTON_TYPE_AUDIO_RATE:
			
			GraphicalInput(key, widget, &(player_data->rateInputIndex), 6, player_data->rateStr);
			player_data->rate = atoi(player_data->rateStr);
			if (player_data->rate < 1) { player_data->rate = 44100; }
			break;
		
		case BUTTON_TYPE_TIMELINE:
			
			if (key == '1') { 	 timeline_data->mode = 0;
			} else if (key == '2') { timeline_data->mode = 1;
			} else if (key == '3') { timeline_data->mode = 2;
			} else if (key == '4') { timeline_data->mode = 3; }

			break;

		case BUTTON_TYPE_BPM:
			break;
		
		case BUTTON_TYPE_PROJECT_FILE:
			GraphicalInput(key, widget, &(timeline_data->projectFileIndex), 128-5, timeline_data->projectFile);
			break;
		
		
		default:break;
	}
}


void PrintText(char* str, SDL_Renderer* renderer, SDL_Texture* font, 
		uint16_t textx, uint16_t texty) {

	if (str == NULL || str[0] == '\0') { return; }

	//find length of directory
	int dirLength = 0;
	for (int i = 0; str[i] != '\0'; i++) {
	
		if (str[i] == '/') { dirLength = i+1; }
	}


	SDL_Rect letter;
	letter.x = textx; letter.y = texty;
	letter.w = 22; letter.h = 26;

	SDL_Rect crop;
	crop.x = 0; crop.y = 0;
	crop.w = 22; crop.h = 26;

	for (int i = dirLength; str[i] != '\0'; i++) {
		
		//newline
		if (str[i] == '\\' && str[i+1] == 'n') {
				
			letter.y += 26;
			i += 2;
			letter.x -= 18;
		}

		//print letter
		if (str[i] >= 32 && str[i] < 127) {
		
			crop.x = (str[i]-32)*22;
		}
		SDL_RenderCopy(renderer, font, &crop, &letter);
		letter.x += 18;
	}
}

void PrintNumbers(int number, SDL_Renderer* renderer, SDL_Texture* font, 
			uint16_t textx, uint16_t texty) {

	SDL_Rect letter;
	letter.x = textx; letter.y = texty;
	letter.w = 22; letter.h = 26;

	SDL_Rect crop;
	crop.x = 0; crop.y = 0;
	crop.w = 22; crop.h = 26;

	int log = (int)log10((double)number);
	int printNum = 0;

	for (int i = log; i >= 0; i--) {

		if (i > 0) { printNum = number / 10*i;
		} else {     printNum = number % 10; }
		crop.x = (printNum+'0'-32)*22;

		//print letter
		SDL_RenderCopy(renderer, font, &crop, &letter);
		letter.x += 18;
	}
}


void UpdateWidgetText(char* str, Widget* widget) {

	if (widget->text != NULL) { free(widget->text); }
	widget->text = malloc(sizeof(char)*strlen(str)+1);
	strcpy(widget->text, str);
}


//main drawing function
void Draw(SDL_Window* window, SDL_Renderer* renderer, 
	  SDL_Texture* background, SDL_Texture* font,
	  Widget* arr[256], uint8_t widgetNum,
	  char* filename,
	  PlayerData* player_data,
	  AlsaData* data,
	  TimelineData* timeline_data) {

	SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
	SDL_RenderFillRect(renderer, NULL);

	int w, h = 0;
	SDL_GetWindowSize(window, &w, &h);
	player_data->w = w;
	player_data->h = h;


	//get screen offset for wave amp		
	int offset = 0;
	if (player_data->waveAmp > 0) {
		
		if (player_data->waveVert == true) { offset = w/(player_data->waveAmp*2);
		} else {			     offset = h/(player_data->waveAmp*2); }
	} else {
		if (player_data->waveVert == true) { offset = w/2;
		} else {			     offset = h/2; }
	}


	//draw background
	if (player_data->background != NULL) { SDL_RenderCopy(renderer, player_data->background, NULL, NULL);
	} else { 			       SDL_RenderCopy(renderer, background, NULL, NULL); }


	//choose color
	SDL_SetRenderDrawColor(renderer, player_data->r, player_data->g, player_data->b, 255);


	//draw audio wave form
	if (player_data->file != NULL && data->buff != NULL && player_data->waveAmp > 0) {
	
		//vertical wave
		if (player_data->waveVert == true) {
			
			int oldx = (data->buff[0]+offset)*player_data->waveAmp;
			int oldy = 0;
			int drawLimit = data->buff_size/player_data->waveFreq < h ? data->buff_size : h;
	
			//draw wave
			for (int i = player_data->waveFreq; i < drawLimit; i += player_data->waveFreq) {
	
				SDL_RenderDrawLine(renderer, oldx, oldy, (data->buff[i]+offset)*player_data->waveAmp, i);
				oldx = (data->buff[i]+offset)*player_data->waveAmp;
				oldy = i;
			}
		//horizontal wave
		} else {
			int oldx = 0;
			int oldy = (data->buff[0]+offset)*player_data->waveAmp;
			int drawLimit = data->buff_size/player_data->waveFreq < w ? data->buff_size : w;
	
			//draw wave
			for (int i = player_data->waveFreq; i < drawLimit; i += player_data->waveFreq) {
	
				SDL_RenderDrawLine(renderer, oldx, oldy, i, (data->buff[i]+offset)*player_data->waveAmp);
				oldx = i;
				oldy = (data->buff[i]+offset)*player_data->waveAmp;
			}
		}
	}



	//add opacity to wave
	if (player_data->waveFade == true) {
			
		SDL_Rect rect;

		//vertical fade
		if (player_data->waveVert == true) {
			
			rect.y = 0;
			rect.x = offset-(128*player_data->waveAmp);
			rect.h = h;
			rect.w = player_data->waveAmp;

			//fade in/out
			for (int i = 0; i < player_data->waveAmp*256; i++) {
		
				if (i < player_data->waveAmp*128) { SDL_SetRenderDrawColor(renderer, 0, 0, 0, ((player_data->waveAmp*128)-1)-(i*player_data->waveAmp));
				} else {	   		    SDL_SetRenderDrawColor(renderer, 0, 0, 0, ((i-(128*player_data->waveAmp)))); }

				SDL_RenderFillRect(renderer, &rect);
				rect.x += player_data->waveAmp;
			}

			SDL_SetRenderDrawColor(renderer, 0, 0, 0, 128);
			rect.w = w - rect.x;
			SDL_RenderFillRect(renderer, &rect);
		
			rect.x = 0;
			rect.w = offset-(128*player_data->waveAmp);
		
		//horizontal wave
		} else {
			rect.x = 0;
			rect.y = offset-(128*player_data->waveAmp);
			rect.w = w;
			rect.h = player_data->waveAmp;

			//fade in/out
			for (int i = 0; i < player_data->waveAmp*256; i++) {
		
				if (i < player_data->waveAmp*128) { SDL_SetRenderDrawColor(renderer, 0, 0, 0, ((player_data->waveAmp*128)-1)-(i*player_data->waveAmp));
				} else {	   		    SDL_SetRenderDrawColor(renderer, 0, 0, 0, ((i-(128*player_data->waveAmp)))); }

				SDL_RenderFillRect(renderer, &rect);
				rect.y += player_data->waveAmp;
			}

			SDL_SetRenderDrawColor(renderer, 0, 0, 0, 128);
			rect.h = h - rect.y;
			SDL_RenderFillRect(renderer, &rect);
		
			rect.y = 0;
			rect.h = offset-(128*player_data->waveAmp);
		}
		SDL_RenderFillRect(renderer, &rect);
	}


	//draw given widgets
	for (int i = 0; i < widgetNum; i++) {
	
		if (arr[i] != NULL && arr[i]->active == true) { 
			
			DrawWidget(window, renderer, font, arr[i], data, player_data, timeline_data); 
		}
	}
	SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);

	
	//draw draggables
	if (player_data->dragFile != NULL) {
		PrintText(player_data->dragFile, renderer, font, player_data->x, player_data->y);
	}



	//draw to screen
	SDL_RenderPresent(renderer);
	SDL_RenderClear(renderer);
}
