#include <clib/alib_protos.h>
#include <clib/exec_protos.h>
#include <clib/graphics_protos.h>
#include <clib/intuition_protos.h>
#include <clib/cybergraphics_protos.h>
#include <cybergraphx/cybergraphics.h>
#include <pragmas/cybergraphics_pragmas.h>
#include <libraries/mui.h>
#include <graphics/gfx.h>
#include <iostream.h>

#include "basic.h"

BasicOutput::BasicOutput(){
	curPen=1;
	curX=0;
	oa_SetName("VU Output");
	oa_Author="T.Miles";
	oa_Version="1.0";
	op_Type=MAKE_TYPE('V','U');
	pixels[0]=NULL;
	pixels[1]=NULL;
	curPixels=0;
	barHeights=NULL;
	maxBars=0;
	framesPerBeat=1;
	op_Configured=TRUE;
}

BasicOutput::~BasicOutput(){
	if (pixels[0])
		delete[] pixels[0];
	if (pixels[1])
		delete[] pixels[1];
	if (barHeights)
		delete[] barHeights;
}

BOOL BasicOutput::StartUp(){
	oa_SetStatus(APP_STATUS_REALTIME,TRUE);	// Say that we want to use the timer
	if(OmegaOutput::StartUp()){
		maxBars=op_Tracks.GetSize();
		barHeights=new UINT[maxBars];
		for (UINT n=0;n<maxBars;n++){
			barHeights[n]=0;
		}
		gui_SetSliderValue(maxBars);
		return TRUE;	
	}
	return FALSE;
}

void BasicOutput::DrawNextFrame(UINT trackNo){ 
	UINT x1,y1,x2,y2,n;
	UINT bpr=o_Width*3;
	UINT sizeX, sizeY;
	FLOAT scale=(FLOAT)o_Height/25.0;
	FLOAT barScale=(FLOAT)o_Height/255.0;
	
	for (n=0;n<maxBars;n++)
		if (barHeights[n]>0)
			barHeights[n]--;
	
	// Track no -1 is the track that we get sent with a tempo event!
	if (trackNo!=-1){		
		barHeights[trackNo]=(UBYTE)(o_GetCurrentValue(trackNo)*barScale);

		if (barHeights[trackNo]>o_Height)
			barHeights[trackNo]=o_Height;	
	}
	// Clear the screen and draw the horizontal lines
	FillPixelArray(&o_RPort, 0,0,o_Width,o_Height, 0x0);	
	for (FLOAT f=0;(UINT)f<o_Height;f+=scale)
		FillPixelArray(&o_RPort,0,(UINT)f,o_Width,1,0xFFFFFFFF);

	// Draw the bars in
	for (n=0;n<maxBars;n++){
		x1=n*barWidth;
		x2=n*barWidth+barWidth-1;
		y1=o_Height-barHeights[n];
		y2=o_Height;
		sizeX=x2-x1;
		sizeY=y2-y1;
		WritePixelArray((APTR)pixels[curPixels],x1,y1,bpr,
									&o_RPort,x1,y1,
									sizeX,sizeY,RECTFMT_RGB);
	}
}


// Set up the bar color values 
void BasicOutput::OnInit(){
	UINT width;
	FLOAT scale, rf=255.0, gf=255.0;
	
	if (pixels[0])
		delete[] pixels[0];
	if (pixels[1])
		delete[] pixels[1];
		
	if (o_mainScr){
		width=o_Width*3;
		scale=255.0/(FLOAT)o_Height;
		pixels[0]=new UBYTE[width*o_Height];
		pixels[1]=new UBYTE[width*o_Height];
		if (maxBars!=0)
			barWidth=o_Width/maxBars;
		else
			barWidth=1;
		if (pixels[0] && pixels[1]){	
			for (UINT n=0;n<o_Height;n++){
				for (UINT f=0;f<width;f+=3){
					pixels[0][width*n+f]=(UBYTE)rf;
					pixels[0][width*n+f+1]=(UBYTE)gf;
					pixels[0][width*n+f+2]=255;
					
					pixels[1][width*n+f]=255;
					pixels[1][width*n+f+1]=(UBYTE)gf;
					pixels[1][width*n+f+2]=(UBYTE)rf;
				}
				rf-=scale;
				gf-=scale;
			}
		}
		else
			Error("Unable to Initialise Pixel Array","Try a Smaller Screen");
	}
	else
		Error("Screen Not Initialised",NULL);
}

void BasicOutput::SetTracks(){
	char *buffer=new char[20];
	UINT size=op_Tracks.GetSize();
	UINT n;
	
	if (maxBars!=size){
		// Clear the list
		for (n=0;n<size;n++)
			op_Tracks.DeleteItem(0);
		
		barHeights=new UINT[maxBars];
		
		for (UINT n=0;n<maxBars;n++){
			barHeights[n]=0;
			sprintf(buffer,"Bar_%d",n);
			AddTrackName(buffer);
		}
	}
	delete[]buffer;
}	

void BasicOutput::OnConfig(){
	char *buffer=new char[20];
	BOOL loop=TRUE;
	ULONG id, gui_Sig=0; 
	FILE *f;
	
	gui_OpenWin();
	
	while(loop){
		id=DoMethod((Object *)app, MUIM_Application_NewInput, &gui_Sig);
		switch (id){
		case ID_USE:
			maxBars=gui_GetSliderValue();
		case ID_CANCEL:
			loop=FALSE;
			break;
		case ID_SAVE:
			maxBars=gui_GetSliderValue();
			SetTracks();
			if (f=OpenConfigFile(TRUE,TRUE)){
				OnSaveConfig(f);
				fclose(f);
			}
			break;
		case ID_LOAD:
			if(f=OpenConfigFile(TRUE,FALSE)){
				OnLoadConfig(f);
				fclose(f);
			}
			break;
		}
		if (loop && gui_Sig)
			Wait(gui_Sig);		
	}
	
	gui_CloseWin();
	if (id=ID_USE){
		SetTracks();		
	}
	delete[]buffer;
}

void BasicOutput::OnBeat(){
	curPixels=!curPixels;
	DrawNextFrame(-1);
}

void BasicOutput::OnLoadConfig(FILE *file){
	if (file){
		fscanf(file,"%d\n",&maxBars);
		cout << "Bars " << maxBars << endl;
		SetTracks();
		gui_SetSliderValue(op_Tracks.GetSize());
		OmegaOutput::OnLoadConfig(file);
	}
}

void BasicOutput::OnSaveConfig(FILE *file){
	if (file){
		fprintf(file,"%d\n",maxBars);
		OmegaOutput::OnSaveConfig(file);
	}
}

void BasicOutput::InitialConfig(){
	FILE *f;
	
	if(f=OpenConfigFile(FALSE,FALSE)){
		OnLoadConfig(f);
		fclose(f);
	}
}

void BasicOutput::OnStart(){
	for (UINT n=0;n<maxBars;n++){
		barHeights[n]=0;
	}
}