#include "file_cache.h"
#include "sdram_addr_map.h"
#include "lcd_base_display.h"

static uint32_t const sdram_cache_buffer_address = SDRAM_BUF_CACHE_ADDRESS;

uint8_t sector[512];
uint32_t BytesRead;

unsigned int load_file_to_sdramcache(const TCHAR* path, unsigned int cache_buffer_address, int *pState)
{
	uint32_t index = 0, file_size = 0, size = 0, i1 = 0;
	uint32_t BmpAddress;
	uint32_t Address = cache_buffer_address;
	FIL F1;
	
	if(pState != 0)return 0;

	if(f_open (&F1, path, FA_READ)){
		/* Set the Text Color */
		set_font_color(0xFFFF0000, 0xFFFFFFFF);
            
		*pState = -1;
		return 0; 
	}
	
	file_size = F1.obj.objsize;
	size = file_size;
	if(0 == size){
		*pState = -2;
		return 0; 
	}
	
	do{
		//256*2
		if (size < 512){
			i1 = size;
		}else{
			i1 = 512;//256*2
		}
		size -= i1;

		f_read (&F1, sector, i1, &BytesRead);

		for (index = 0; index < i1; index++){
			*(__IO uint8_t*) (Address) = *(__IO uint8_t *)BmpAddress;
				
			BmpAddress++;  
			Address++;
		}  
			
		BmpAddress = (uint32_t)sector;
	}while (size > 0);

	f_close (&F1);
	*pState =0;
	return file_size;
}

void load_bmpfile_to_sdramcache(const TCHAR* path,uint32_t cache_buffer_address)
{
	uint32_t index = 0, size = 0, i1 = 0;
	uint32_t BmpAddress;
	uint32_t Address = cache_buffer_address;
	FIL F1;

	if(f_open (&F1, path, FA_READ))
	{
		set_font_color(0xFFFF0000, 0xFFFFFFFF);
            
		LCD_ShowString(20,360,400,24,24,"File type or name not supported!");
		
		while(1); 
	}
	f_read (&F1, sector, 32, &BytesRead);

	BmpAddress = (uint32_t)sector;

	/* Read bitmap size */
	size = *(uint16_t *) (BmpAddress + 2);
	size |= (*(uint16_t *) (BmpAddress + 4)) << 16;  
	 
	/* Get bitmap data address offset */
	index = *(uint16_t *) (BmpAddress + 10);
	index |= (*(uint16_t *) (BmpAddress + 12)) << 16;  

	f_close (&F1);
  
  f_open (&F1, path, FA_READ);
	
	do
	{
		if (size < 512)//256*2
		{
			i1 = size;
		}
		else
		{
			i1 = 512;//256*2
		}
		size -= i1;

		f_read (&F1, sector, i1, &BytesRead);

		for (index = 0; index < i1; index++)
		{
			*(__IO uint8_t*) (Address) = *(__IO uint8_t *)BmpAddress;
				
			BmpAddress++;  
			Address++;
		}  
			
		BmpAddress = (uint32_t)sector;
	}
	while (size > 0);

	f_close (&F1);
}

void load_bmpfile_sdramcache_to_sdramaddress(uint32_t BmpCacheAddress,Bmp_Parameter_TypeDef* bmp_parameter)//24bit bmp
{
	uint16_t temp_rg;
	uint16_t temp_b;
	uint32_t temp;
	
	uint16_t temp_r;
	uint16_t temp_g;
	
	uint32_t index = 0, size = 0, width = 0, height = 0, bit_pixel = 0;
	uint32_t Address;
	uint32_t currentline = 0, linenumber = 0;
	
	uint32_t read_width = 0;
	uint32_t index_width = 0;
	uint32_t index_height = 0;
	
	uint32_t fifo_32bit = 0;
	uint32_t point_32bit_data = 0;
	uint32_t bit1_index = 0;
	uint32_t bit1_size = 0;
	uint32_t bit4_index = 0;
	uint32_t bit4_size = 0;
	uint32_t Bmp4BitColor = 0;
	uint32_t read_width_index = 0;
	uint32_t max_value = 0;
	uint32_t i = 0;
 
	Address = bmp_parameter->start_address;

	/* Read bitmap size */
	size = *(__IO uint16_t *) (BmpCacheAddress + 2);
	size |= (*(__IO uint16_t *) (BmpCacheAddress + 4)) << 16;
  
	/* Get bitmap data address offset */
	index = *(__IO uint16_t *) (BmpCacheAddress + 10);
	index |= (*(__IO uint16_t *) (BmpCacheAddress + 12)) << 16;

	/* Read bitmap width */
	width = *(uint16_t *) (BmpCacheAddress + 18);
	width |= (*(uint16_t *) (BmpCacheAddress + 20)) << 16;

	/* Read bitmap height */
	height = *(uint16_t *) (BmpCacheAddress + 22);
	height |= (*(uint16_t *) (BmpCacheAddress + 24)) << 16;
	
	bmp_parameter->pic_width = width;
	bmp_parameter->pic_height= height;

	/* Read bit/pixel */
	bit_pixel = *(uint16_t *) (BmpCacheAddress + 28);  
 
	/* compute the real size of the picture (without the header)) */  
	size = (size - index); 

	/* bypass the bitmap header */
	BmpCacheAddress += index;
	
	//16bit bmp
	if(16 == bit_pixel)
	{
		if(width & 0x01)
		{
			read_width = width + 1;// 2 byte
		}
		else
		{
			read_width = width + 0;
		}
		size = read_width*height*2;
		BmpCacheAddress+=(size-(read_width*2));
		
		for(index_height = 0; index_height < height; index_height++)
		{
			for(index_width = 0; index_width < width; index_width++)
			{
				temp = *(__IO uint16_t *)BmpCacheAddress;
				temp_r = (temp&0x7C00)>>7;
				temp_g = (temp&0x03E0)>>2;
				temp_b = (temp&0x001F)<<3;
				temp = temp_r;
				temp<<=8;
				temp|=temp_g;
				temp<<=8;
				temp|=temp_b;
				*(__IO uint32_t*) (Address) = (temp | 0xFF000000);
				//jump on point pixel 
				BmpCacheAddress+=2;
				Address+=4;
			}
			BmpCacheAddress-=((read_width + width)*2);
		}
	}
	
	//24bit bmp
	else if(24 == bit_pixel)
	{	
		if((width * 3) & 0x03)
		{
			read_width = (((width * 3)>>2) + 1)<<2;// 4 byte
		}
		else
		{
			read_width = width * 3;
		}
		size = read_width*height;
		BmpCacheAddress+=(size-read_width);
		
		for(index_height = 0; index_height < height; index_height++)
		{
			for(index_width = 0; index_width < width; index_width++)
			{
				temp_b = *(__IO uint8_t *)BmpCacheAddress;
				BmpCacheAddress++;
				temp_g = *(__IO uint8_t *)BmpCacheAddress;
				BmpCacheAddress++;
				temp_r = *(__IO uint8_t *)BmpCacheAddress;
				BmpCacheAddress++;
				temp = temp_r;
				temp<<=8;
				temp|=temp_g;
				temp<<=8;
				temp|=temp_b;
				*(__IO uint32_t*) (Address) = (temp | 0xFF000000);
				//jump on point pixel 
				Address+=4;
			}
			BmpCacheAddress-=(read_width + width * 3);
		}
	}
	
	//4bit bmp
	else if(4 == bit_pixel)
	{
		if(width & 0x07)
		{
			read_width = (width>>3) + 1;//read length 32bit
		}
		else
		{
			read_width = (width>>3) + 0;
		}
		size = read_width * height * 4;// 4 byte
		BmpCacheAddress +=(size - (read_width * 4));//from bottom to top
		bit4_size = width * height;//total 4bit size
		index_height = height;
		read_width_index = read_width;
		do
		{
			point_32bit_data = (*(__IO uint8_t *)BmpCacheAddress);
			BmpCacheAddress++;
			point_32bit_data = (point_32bit_data<<8) | (*(__IO uint8_t *)BmpCacheAddress);
			BmpCacheAddress++;
			point_32bit_data = (point_32bit_data<<8) | (*(__IO uint8_t *)BmpCacheAddress);
			BmpCacheAddress++;
			point_32bit_data = (point_32bit_data<<8) | (*(__IO uint8_t *)BmpCacheAddress);
			BmpCacheAddress++;
			
			read_width_index--;
			if(0 == read_width_index)
			{
				max_value = width - ((read_width-1)<<3);
				read_width_index = read_width;
				index_height--;
				BmpCacheAddress -=(read_width * 4 * 2);//read from bottom address to top address
				if(0 == index_height)
				{
					;
				}
			}
			else
			{
				max_value = 8;
			}		
			
			for(i = 0;i < max_value;i++)
			{
				switch((point_32bit_data & 0xF0000000)>>28){
					case 0 : *(__IO uint32_t*)(Address) = 0xFF000000;break;
					case 1 : *(__IO uint32_t*)(Address) = 0xFF800000;break;
					case 2 : *(__IO uint32_t*)(Address) = 0xFF008000;break;
					case 3 : *(__IO uint32_t*)(Address) = 0xFF808000;break;
					case 4 : *(__IO uint32_t*)(Address) = 0xFF000080;break;
					case 5 : *(__IO uint32_t*)(Address) = 0xFF800080;break;
					case 6 : *(__IO uint32_t*)(Address) = 0xFF008080;break;
					case 7 : *(__IO uint32_t*)(Address) = 0xFF808080;break;
					case 8 : *(__IO uint32_t*)(Address) = 0xFFC0C0C0;break;
					case 9 : *(__IO uint32_t*)(Address) = 0xFFFF0000;break;
					case 10: *(__IO uint32_t*)(Address) = 0xFF00FF00;break;
					case 11: *(__IO uint32_t*)(Address) = 0xFFFFFF00;break;
					case 12: *(__IO uint32_t*)(Address) = 0xFF0000FF;break;
					case 13: *(__IO uint32_t*)(Address) = 0xFFFF00FF;break;
					case 14: *(__IO uint32_t*)(Address) = 0xFF00FFFF;break;
					case 15: *(__IO uint32_t*)(Address) = 0xFFFFFFFF;break;
					default : break;
				}
				point_32bit_data<<=4;
				bit4_index++;
				Address+=4;
				if(bit4_index == bit4_size)
				{
					break;
				}
			}
		}while(bit4_index < bit4_size);
	}
	
	//1bit bmp
	else if(1 == bit_pixel)
	{
		if(width & 0x1F)
		{
			read_width = (width>>5) + 1;//read length 32bit
		}
		else
		{
			read_width = (width>>5) + 0;
		}
		size = read_width * height * 4;// 4 byte
		BmpCacheAddress +=(size - (read_width * 4));//from bottom to top
		bit1_size = width * height;//total bit size
		index_height = height;
		read_width_index = read_width;
		do
		{
			point_32bit_data = (*(__IO uint8_t *)BmpCacheAddress);
			BmpCacheAddress++;
			point_32bit_data = (point_32bit_data<<8) | (*(__IO uint8_t *)BmpCacheAddress);
			BmpCacheAddress++;
			point_32bit_data = (point_32bit_data<<8) | (*(__IO uint8_t *)BmpCacheAddress);
			BmpCacheAddress++;
			point_32bit_data = (point_32bit_data<<8) | (*(__IO uint8_t *)BmpCacheAddress);
			BmpCacheAddress++;
			
			read_width_index--;
			if(0 == read_width_index)
			{
				max_value = width - ((read_width-1)<<5);
				read_width_index = read_width;
				index_height--;
				BmpCacheAddress -=(read_width * 4 * 2);//read from bottom address to top address
				if(0 == index_height)
				{
					;
				}
			}
			else
			{
				max_value = 32;
			}		
			
			for(i = 0;i < max_value;i++)
			{
				fifo_32bit<<=1;
				if(point_32bit_data & 0x80000000)
				{
					fifo_32bit|=0x01;
				}
				else
				{
					fifo_32bit&=~0x01;
				}
				point_32bit_data<<=1;
				bit1_index++;
				if(!(bit1_index & 0x1f))
				{
					*(__IO uint32_t*)(Address) = fifo_32bit;
					Address+=4;
				}
				else if(bit1_index == bit1_size)
				{
					fifo_32bit<<=(32-(bit1_index & 0x1F));
					*(__IO uint32_t*)(Address) = fifo_32bit;
					Address+=4;
					break;
				}
			}
		}while(bit1_index < bit1_size);
	}
}

void load_bmpfile_to_sdram(Bmp_Parameter_TypeDef* BmpFileParameter)
{
	load_bmpfile_to_sdramcache((const char *)BmpFileParameter->name_str,sdram_cache_buffer_address);
	load_bmpfile_sdramcache_to_sdramaddress(sdram_cache_buffer_address,BmpFileParameter);
}
