#include <malloc.h>
#include "eq.h"

#define EQ_COLOR 0x00CC00
#define PEAK_COLOR 0x0000CC
#define EQ_PADDING 3

EQ::EQ() : Widget()
{
	// Set default sprite state
	fftImage = NULL;
	peakImage = NULL;
	
	for(int i = 0; i < 16; i++)
	{
		// Init sprites
		fftSprite[i] = new Sprite();
		peakSprite[i] = new Sprite();
		
		// Set initial peak results
		peakResults[i] = 0;
	}
}

EQ::~EQ()
{
	// Free images
	if(fftImage) { delete fftImage; }
	if(peakImage) { delete peakImage; }
	
	for(int i = 0; i < 16; i++)
	{
		// Free sprites
		if(fftSprite[i]) { delete fftSprite[i]; }
		if(peakSprite[i]) { delete peakSprite[i]; }
	}
}

void EQ::resize(int width, int height)
{	
	// Ensure width/height is a multiple of 4
	while(width % 4) { width++; };
	while(height % 4) { height++; };
	
	// Resize widget
	_rect.width = width;
	_rect.height = height;
	
	// Calculate width of items
	itemWidth = (_rect.width - (15 * EQ_PADDING)) / 16;
}

void EQ::draw()
{
	// Grab location including parent
	Rect dLoc = getDimensions();
	
	// Ensure its been skinned
	if(!fftImage)
	{
		// It hasn't
		reskin();
	}
	
	// Grab eq results
	sound.getFFTResult(fftResults);
	
	// Calculate peaks
	for(int i = 0; i < 16; i++)
	{
		// Drop
		peakResults[i] -= (32767 / 64);
		
		// Make sure we don't go too far down
		if(peakResults[i] < 0) { peakResults[i] = 0; }
		
		// Raise if pushed
		if(peakResults[i] < fftResults[i]) { peakResults[i] = fftResults[i]; }
	}
	
	// Create a window
	LayerManager manager(32);
	
	// Set sprites
	for(int i = 0; i < 16; i++)
	{
		// Data
		peakSprite[i]->SetImage(peakImage->getImage());
		
		// Stretch horizontally
		peakSprite[i]->SetStretchWidth((double)itemWidth / (double)4);
		
		// Calculate vertical position
		double percent = (double)peakResults[i] / (double)32767;
		int newY = dLoc.height - (int)(percent * (double)dLoc.height);
		
		// Set sprites positions
		peakSprite[i]->SetPosition(dLoc.x + i * (itemWidth + EQ_PADDING), dLoc.y + newY);
		
		// Append sprite to window
		manager.Append(peakSprite[i]);
		
		// Data
		fftSprite[i]->SetImage(fftImage->getImage());
		
		// Stretch horizontally
		fftSprite[i]->SetStretchWidth((double)itemWidth / (double)4);
		
		// Calculate vertical stretch
		percent = (double)fftResults[i] / (double)32767;
		fftSprite[i]->SetStretchHeight((double)dLoc.height * percent / (double)4);
		
		// Calculate vertical position
		newY = dLoc.height - ((int)(percent * (double)dLoc.height) / 2);
		
		// Set sprites positions	
		fftSprite[i]->SetPosition(dLoc.x + i * (itemWidth + EQ_PADDING), dLoc.y + newY);
		
		// Append sprite to window
		manager.Append(fftSprite[i]);
	}
	
	// Draw to screen
	manager.Draw(settingsManager.getOffsetX(), settingsManager.getOffsetY());
}

void EQ::reskin()
{
	// Set up single drawableimage for stretching to display
	if(fftImage) { delete fftImage; }
	//if(peakImage) { delete peakImage; }
	
	// Create data structure
	fftImage = new DrawableImage();
	fftImage->createImage(4, 4);
	
	// Create blit buffer
	uint32_t *blitbuf = (uint32_t *)memalign(32, 4 * 4 * 4);
	
	// Grab color
	uint32_t tColor;
	windowManager.getLongHex("GraphicEQ.Color", &tColor, EQ_COLOR);
	tColor = (tColor << 8) | 0xFF;
	
	for(int i = 0; i < 4 * 4; i++)
	{
		// Set gx color value
		memcpy(&blitbuf[i], &tColor, 4);
	}
	
	// Copy over
	fftImage->copyBuffer((uint8_t *)blitbuf);
	
	// Grab color
	windowManager.getLongHex("GraphicEQ.PeakColor", &tColor, PEAK_COLOR);
	tColor = (tColor << 8) | 0xFF;
	
	for(int i = 0; i < 4 * 4; i++)
	{
		// Set gx color value
		memcpy(&blitbuf[i], &tColor, 4);
	}
	
	// New image
	peakImage = new DrawableImage();
	peakImage->createImage(4, 4);
	
	// Copy over
	peakImage->copyBuffer((uint8_t *)blitbuf);
	
	// Free memory
	free(blitbuf);
}

