#include <csl_edma2.h>
#include "image_control.h"
#include "environment.h"

#pragma DATA_SECTION(ImageBuffer1, ".sdram2_image");
#pragma DATA_ALIGN(ImageBuffer1, 1024);
#pragma DATA_SECTION(ImageBuffer2, ".sdram2_image");
#pragma DATA_ALIGN(ImageBuffer2, 1024);
#pragma DATA_SECTION(ImageBuffer3, ".sdram2_image");
#pragma DATA_ALIGN(ImageBuffer3, 1024);
#pragma DATA_SECTION(ImageBuffer4, ".sdram2_image");
#pragma DATA_ALIGN(ImageBuffer4, 1024);
#pragma DATA_SECTION(DummyImage, ".sdram2_image");
#pragma DATA_ALIGN(DummyImage, 1024);
#pragma DATA_SECTION(InvalidImage, ".sdram2_image");
#pragma DATA_ALIGN(InvalidImage, 1024);
unsigned char ImageBuffer1[IMAGE_BUFFER_SIZE];
unsigned char ImageBuffer2[IMAGE_BUFFER_SIZE];
unsigned char ImageBuffer3[IMAGE_BUFFER_SIZE];
unsigned char ImageBuffer4[IMAGE_BUFFER_SIZE];
unsigned char DummyImage[4][SYSTEM_CAMERA_HD_WIDTH * SYSTEM_CAMERA_HD_HEIGHT];
unsigned char InvalidImage[SYSTEM_CAMERA_HD_WIDTH * SYSTEM_CAMERA_HD_HEIGHT];
unsigned short DefectQueueList[DEFECT_QUEUE_SIZE];
int DefectQueueStart, DefectQueueEnd;

#pragma DATA_SECTION(DefectDataList, ".sdram2_image");
TDefectData_SPB DefectDataList[MAX_IMAGE_BLOCK_INDEX][IMAGE_BUFFER_COUNT];


TImageInfo ImageInfo[IMAGE_BUFFER_COUNT];
//TImageInfo2 ImageInfo2;
TProcessingImageInfo ProcessingImageInfo;
TCalibrationImageInfo CalibrationImageInfo;

TProcessingImageBufferData ProcessingImageBufferData;

unsigned int lastCaptureStartTime;

unsigned char *RealtimeImageBuffer;
unsigned int RealtimeImageStartQueue;
unsigned int RealtimeImageEndQueue;
unsigned int ImageControlInterval;

void ImageControl_CalibMode_Clear(void);
void ClearInspectImage(void);
void ImageControl_ClearBuffer(void);
void SelectedImageControl_ClearBuffer(unsigned char *dstImage);
void BuildCalibrationImageInfo();
void BuildProcessingImageInfo();
void InitImageInfo(void)
{
	int bufferIndex;
	for (bufferIndex = 0; bufferIndex < IMAGE_BUFFER_COUNT; bufferIndex++)
	{
		ImageInfo[bufferIndex].BlockSize = 0;
		ImageInfo[bufferIndex].BlockCount = 0;
		ImageInfo[bufferIndex].Allocated = 0;
		ImageInfo[bufferIndex].ImageControlMode = IMAGE_CONTROL_MODE_NONE;
	}
	ProcessingImageInfo.ImageCount = 0;

	ImageControl_ClearBuffer();
	RealtimeImageBuffer = ImageBuffer4;
	RealtimeImageStartQueue = RealtimeImageEndQueue = 0;
	ImageControlInterval = 1;
}

void SetImageControlMode(int bufferIndex, int imageControlMode)
{
	ImageInfo[bufferIndex].ImageControlMode = imageControlMode;
}

void AllocateImageBuffer(int bufferIndex, int imageBlockSize)
{
	int bufferBlockIndex;
	unsigned char *image_base_addr;
	unsigned int currentImageOffset;
	unsigned int buffer_max_size;

	if (bufferIndex == 0)
	{
		image_base_addr = ImageBuffer1;
		buffer_max_size = IMAGE_BUFFER_SIZE;
		memset(ImageBuffer1, 0, IMAGE_BUFFER_SIZE);
	}
	else if (bufferIndex == 1)
	{
		image_base_addr = ImageBuffer2;
		buffer_max_size = IMAGE_BUFFER_SIZE;
		memset(ImageBuffer2, 0, IMAGE_BUFFER_SIZE);
	}
	else if (bufferIndex == 2)
	{
		image_base_addr = ImageBuffer3;
		buffer_max_size = IMAGE_BUFFER_SIZE;
		memset(ImageBuffer3, 0, IMAGE_BUFFER_SIZE);
	}
	else
	{
		image_base_addr = ImageBuffer4;
		buffer_max_size = IMAGE_BUFFER_SIZE;
		memset(ImageBuffer4, 0, IMAGE_BUFFER_SIZE);
	}
	currentImageOffset = 0;
	bufferBlockIndex = 0;	

	while((currentImageOffset + imageBlockSize < buffer_max_size) && (bufferBlockIndex < MAX_IMAGE_BLOCK_INDEX - 1))
	{
		ImageInfo[bufferIndex].ImageBuffer[bufferBlockIndex] = image_base_addr + currentImageOffset;
		currentImageOffset += imageBlockSize;
		bufferBlockIndex++;
	}

	ImageInfo[bufferIndex].BlockSize = imageBlockSize;
	ImageInfo[bufferIndex].BlockCount = bufferBlockIndex;
	ImageInfo[bufferIndex].Allocated = 1;
//	ClearImageBuffer(bufferIndex);
	BuildCalibrationImageInfo();
	BuildProcessingImageInfo();
	ImageInfo[bufferIndex].ImageControlMode = IMAGE_CONTROL_MODE_FIFO;	
}

void ImageControl_ClearBuffer(void)
{
	memset(ImageBuffer1, 0, IMAGE_BUFFER_SIZE);
	memset(ImageBuffer2, 0, IMAGE_BUFFER_SIZE);
	memset(ImageBuffer3, 0, IMAGE_BUFFER_SIZE);
	memset(ImageBuffer4, 0, IMAGE_BUFFER_SIZE);
	
	/*
	Request_ClearData_Aligned(ImageBuffer1, 0, IMAGE_BUFFER_SIZE);
	Request_ClearData_Aligned(ImageBuffer2, 0, IMAGE_BUFFER_SIZE);
	Request_ClearData_Aligned(ImageBuffer3, 0, IMAGE_BUFFER_SIZE);
	Request_ClearData_Aligned(ImageBuffer4, 0, IMAGE_BUFFER_SIZE);
	*/
}

void SelectedImageControl_ClearBuffer(unsigned char *dstImage)
{
	//memset(dstImage, 0, IMAGE_BUFFER_SIZE);
	Request_ClearData_Aligned(dstImage, 0, IMAGE_BUFFER_SIZE);
}

void BuildCalibrationImageInfo(void)
{
	int imageIndex, bufferIndex;
	
	for (bufferIndex = 0; bufferIndex < IMAGE_BUFFER_COUNT; bufferIndex++)
	{
		if (!ImageInfo[bufferIndex].Allocated) 
		{
			CalibrationImageInfo.MaxFrameCount[bufferIndex] = 0;
			continue;
		}
		for (imageIndex = 0; imageIndex < ImageInfo[bufferIndex].BlockCount - 1; imageIndex++)
		{
			CalibrationImageInfo.ImageBuffer[imageIndex][bufferIndex] = ImageInfo[bufferIndex].ImageBuffer[imageIndex];
			CalibrationImageInfo.DummyBuffer[bufferIndex] = ImageInfo[bufferIndex].ImageBuffer[ImageInfo[bufferIndex].BlockCount - 1];
		}
		CalibrationImageInfo.MaxFrameCount[bufferIndex] = ImageInfo[bufferIndex].BlockCount - 1;
	}
	ImageControl_CalibMode_Clear();
}

void BuildProcessingImageInfo(void)
{
	int imageIndex, bufferIndex, minbufferCount;
	
	minbufferCount = ImageInfo[0].BlockCount - 1;
	for (bufferIndex = 0; bufferIndex < IMAGE_BUFFER_COUNT; bufferIndex++)
	{
		if (!ImageInfo[bufferIndex].Allocated) continue;
		for (imageIndex = 0; imageIndex < ImageInfo[bufferIndex].BlockCount - 1; imageIndex++)
		{
			ProcessingImageInfo.ImageBuffer[imageIndex][bufferIndex] = ImageInfo[bufferIndex].ImageBuffer[imageIndex];
			ProcessingImageInfo.DummyBuffer[bufferIndex] = ImageInfo[bufferIndex].ImageBuffer[ImageInfo[bufferIndex].BlockCount - 1];
		}

		if (minbufferCount > ImageInfo[bufferIndex].BlockCount - 1)
		{
			minbufferCount = ImageInfo[bufferIndex].BlockCount - 1;
		}
	}
	ProcessingImageInfo.ImageCount = minbufferCount;
	ClearInspectImage();
}

int GetBufferIndexLimit(int bufferIndex)
{
	return ImageInfo[bufferIndex].BlockCount;
}

int GetImageBlockSize(int bufferIndex)
{
	return ImageInfo[bufferIndex].BlockSize;
}

void ClearInspectImage(void)
{
	int imageIndex;

	for (imageIndex = 0; imageIndex < ProcessingImageInfo.ImageCount; imageIndex++)
	{
		ProcessingImageInfo.ImageState[imageIndex] = IMAGE_STATE_EMPTY;
	}

//	ProcessingImageInfo.DefectImageIndex = 0;
	ProcessingImageInfo.DefectUploadIndex = 0;
	ProcessingImageInfo.CaptureImageIndex = -1;
	ProcessingImageInfo.ProcessingBufferFindingIndex = 0;
	DefectQueueStart = DefectQueueEnd = 0;
}

int GetProcessingImageBufferIndex(void)
{
	int imageIndex, checkingImageIndex;
	//int processingImageIndex;
	for (imageIndex = 0; imageIndex < ProcessingImageInfo.ImageCount; imageIndex++)
	{
//		if (ProcessingImageInfo.ImageState[imageIndex] == IMAGE_STATE_EMPTY)
//		{
//			break;
//		}		

		if (ProcessingImageInfo.ImageState[ProcessingImageInfo.ProcessingBufferFindingIndex] == IMAGE_STATE_EMPTY)
		{
			break;
		}
		else
		{
			ProcessingImageInfo.ProcessingBufferFindingIndex++;
			if (ProcessingImageInfo.ProcessingBufferFindingIndex == ProcessingImageInfo.ImageCount)
			{
				ProcessingImageInfo.ProcessingBufferFindingIndex = 0;
			}
		}
	}	
	if (imageIndex == ProcessingImageInfo.ImageCount)
	{
		if (DefectQueueStart == DefectQueueEnd)	// defect list is empty
		{
			ProcessingImageInfo.CaptureImageIndex = -1;
		}
		else
		{
			checkingImageIndex = DefectQueueList[(DefectQueueEnd - 1) & DEFECT_QUEUE_MASK];		// 가장 최근 불량 이미지를 지운다.
			if (ProcessingImageInfo.ImageState[checkingImageIndex] == IMAGE_STATE_DEFECT)	// not uploading
			{
				DefectQueueEnd = (DefectQueueEnd - 1) & DEFECT_QUEUE_MASK;
				ProcessingImageInfo.ImageState[checkingImageIndex] = IMAGE_STATE_ON_CAPTURE;
				ProcessingImageInfo.CaptureImageIndex = checkingImageIndex;
			}
			else
			{
				ProcessingImageInfo.CaptureImageIndex = -1;
			}
		}
	}
	else
	{
		//ProcessingImageInfo.CaptureImageIndex = imageIndex;
		ProcessingImageInfo.CaptureImageIndex = ProcessingImageInfo.ProcessingBufferFindingIndex;
		ProcessingImageInfo.ImageState[ProcessingImageInfo.CaptureImageIndex] = IMAGE_STATE_ON_CAPTURE;

		ProcessingImageInfo.ProcessingBufferFindingIndex++;
		if (ProcessingImageInfo.ProcessingBufferFindingIndex == ProcessingImageInfo.ImageCount)
		{
			ProcessingImageInfo.ProcessingBufferFindingIndex = 0;
		}
		//return ProcessingImageInfo[bufferIndex].ImageBuffer[imageIndex];
	}	
	return ProcessingImageInfo.CaptureImageIndex;
//	return ProcessingImageInfo[bufferIndex].DummyBuffer;

}

unsigned char* GetProcessingImageBufferPtr(int camIndex, int frameIndex)
{
	if (frameIndex != -1)
	{		
		return ProcessingImageInfo.ImageBuffer[frameIndex][camIndex];
	}
	else
	{
		return ProcessingImageInfo.DummyBuffer[camIndex];
	}
}



/*
void Set_TabletIndex(int bufferIndex, unsigned int tabletIndex)
{
	ProcessingImageInfo[bufferIndex].TabletIndex[ProcessingImageInfo[bufferIndex].CaptureImageIndex] = tabletIndex;
}
*/

void SearchDefectImage(int minDefectTabletNumber, TDefectImageInfo *defectImageInfo)
{
	int camIndex;
	int anyDefectExist;
	int imageIndex;
	unsigned int gie;

//	gie = IRQ_globalDisable();
	anyDefectExist = 0;

	for (camIndex = 0; camIndex < SYSTEM_SPB_CAMERA_MAX_COUNT; camIndex++)
	{
		defectImageInfo->DefectCameraMask[camIndex] = 0;
	}

	// make uploding status complete
	if (DefectQueueStart != DefectQueueEnd)
	{
		imageIndex = DefectQueueList[DefectQueueStart];
		if (ProcessingImageInfo.ImageState[imageIndex] == IMAGE_STATE_UPLOADING)
		{
			ProcessingImageInfo.ImageState[imageIndex] = IMAGE_STATE_EMPTY;
			DefectQueueStart = (DefectQueueStart + 1) & DEFECT_QUEUE_MASK;
		}
	}


	//if (DefectQueueStart != DefectQueueEnd)
	while (DefectQueueStart != DefectQueueEnd)
	{
		imageIndex = DefectQueueList[DefectQueueStart];

		if (ProcessingImageInfo.TabletNumber[imageIndex] < minDefectTabletNumber)
		{
			ProcessingImageInfo.ImageState[imageIndex] = IMAGE_STATE_EMPTY;
			DefectQueueStart = (DefectQueueStart + 1) & DEFECT_QUEUE_MASK;
		}
		else
		{
			for (camIndex = 0; camIndex < SYSTEM_SPB_CAMERA_MAX_COUNT; camIndex++)
			{
				if (ProcessingImageInfo.ImageInspectState[imageIndex][camIndex] == IMAGE_RESULT_DEFECT)
				{
					defectImageInfo->DefectCameraMask[camIndex] = 1;
					anyDefectExist = 1;
				}
			}

			if (!anyDefectExist)
			{
				DefectQueueStart = (DefectQueueStart + 1) & DEFECT_QUEUE_MASK;
				ProcessingImageInfo.ImageState[imageIndex] = IMAGE_STATE_EMPTY;
			}
			else
			{
				break;
			}
		}
	}

	if (anyDefectExist)
	{			
		defectImageInfo->DefectExists = 1;
		defectImageInfo->DefectTabletNumber = ProcessingImageInfo.TabletNumber[imageIndex];
//		ProcessingImageInfo.ImageState[imageIndex] = IMAGE_STATE_UPLOADING;
		ProcessingImageInfo.DefectUploadIndex = imageIndex;
	}
	else
	{
		defectImageInfo->DefectExists = 0;
		defectImageInfo->DefectTabletNumber = 0;
	}

//	IRQ_globalRestore(gie);
}

unsigned char *GetDefectImageAddr(int bufferIndex)
{
//	return ProcessingImageInfo.ImageBuffer[ProcessingImageInfo.DefectImageIndex][bufferIndex];
	ProcessingImageInfo.ImageState[ProcessingImageInfo.DefectUploadIndex] = IMAGE_STATE_UPLOADING;		// 실제로 가져갈 때 uploading 으로 state 변환
	return ProcessingImageInfo.ImageBuffer[ProcessingImageInfo.DefectUploadIndex][bufferIndex];
}

unsigned char *GetDefectDataAddr(int bufferIndex)
{
	return (unsigned char *)&(DefectDataList[ProcessingImageInfo.DefectUploadIndex][bufferIndex]);
}

void DiscardDefectImage(void)
{
	ProcessingImageInfo.ImageState[ProcessingImageInfo.DefectUploadIndex] = IMAGE_STATE_EMPTY;
	DefectQueueStart = (DefectQueueStart + 1) & DEFECT_QUEUE_MASK;
}

TProcessingImageBufferData *MakeInformationData(void)
{
	int imageIndex;
	ProcessingImageBufferData.ImageCount = ProcessingImageInfo.ImageCount;
	for (imageIndex = 0; imageIndex < ProcessingImageInfo.ImageCount; imageIndex++)
	{
		ProcessingImageBufferData.ImageStatus[imageIndex] = ProcessingImageInfo.ImageState[imageIndex];
	}
	return &ProcessingImageBufferData;
}

void ImageControl_CalibMode_Clear(void)
{
	int bufferIndex, frameIndex;
	for (bufferIndex = 0; bufferIndex < IMAGE_BUFFER_COUNT; bufferIndex++)
	{
		CalibrationImageInfo.FIFOModeStart[bufferIndex] = CalibrationImageInfo.FIFOModeEnd[bufferIndex] = 0;
		for (frameIndex = 0; frameIndex < CalibrationImageInfo.MaxFrameCount[bufferIndex]; frameIndex++)
		{
			CalibrationImageInfo.FIFOState[frameIndex][bufferIndex] = IC_CALIB_STATE_NONE;
		}
	}
}

void ImageControl_CalibMode_IncreaseFIFO(int bufferIndex)
{
	CalibrationImageInfo.FIFOModeEnd[bufferIndex]++;
	if (CalibrationImageInfo.FIFOModeEnd[bufferIndex] == CalibrationImageInfo.MaxFrameCount[bufferIndex])
	{
		CalibrationImageInfo.FIFOModeEnd[bufferIndex] = 0;
	}
	CalibrationImageInfo.FIFOState[CalibrationImageInfo.FIFOModeEnd[bufferIndex]][bufferIndex] = IC_CALIB_STATE_NONE;
}


unsigned char* ImageControl_CalibMode_GetLastFrameBuffer(int bufferIndex)
{
	return CalibrationImageInfo.ImageBuffer[CalibrationImageInfo.FIFOModeEnd[bufferIndex]][bufferIndex];
}

int ImageControl_CalibMode_GetLastFrameIndex(int bufferIndex)
{
	return CalibrationImageInfo.FIFOModeEnd[bufferIndex];
}


int ImageControl_CalibMode_GetFilledFrameCount(int bufferIndex)
{
	int indexCount = CalibrationImageInfo.FIFOModeEnd[bufferIndex] - CalibrationImageInfo.FIFOModeStart[bufferIndex];
	if (indexCount < 0)
	{
		indexCount += CalibrationImageInfo.MaxFrameCount[bufferIndex];
	}
	return indexCount;
}

void ImageControl_CalibMode_SetLastBufferState(int bufferIndex, int state)
{
	CalibrationImageInfo.FIFOState[CalibrationImageInfo.FIFOModeEnd[bufferIndex]][bufferIndex] = state;
}

void ImageControl_CalibMode_SetBufferState(int bufferIndex, int frameIndex, int state)
{
	CalibrationImageInfo.FIFOState[frameIndex][bufferIndex] = state;
}

unsigned char* ImageControl_CalibMode_GetFirstValidFrameBuffer(int bufferIndex)
{
	int frameCount, frameIndex;
	frameIndex = CalibrationImageInfo.FIFOModeStart[bufferIndex];
	for (frameCount = 0; frameCount < CalibrationImageInfo.MaxFrameCount[bufferIndex]; frameCount++)
	{
		if (frameIndex == CalibrationImageInfo.FIFOModeEnd[bufferIndex])
		{
			return CalibrationImageInfo.DummyBuffer[bufferIndex];
		}
		if (CalibrationImageInfo.FIFOState[frameIndex][bufferIndex] == IC_CALIB_STATE_ON_CAPTURE || 
			CalibrationImageInfo.FIFOState[frameIndex][bufferIndex] == IC_CALIB_STATE_NONE)
		{
			//return CalibrationImageInfo.DummyBuffer[bufferIndex];
		}
		else if (CalibrationImageInfo.FIFOState[frameIndex][bufferIndex] == IC_CALIB_STATE_CAPTURE_COMPLETE)
		{
			return CalibrationImageInfo.ImageBuffer[frameIndex][bufferIndex];
		}

		frameIndex = frameIndex + 1;
		if (frameIndex == CalibrationImageInfo.MaxFrameCount[bufferIndex])
		{
			frameIndex = 0;
		} 
	}

	return CalibrationImageInfo.DummyBuffer[bufferIndex];
}

void ImageControl_CalibMode_DecreaseToNextValidFrame(int bufferIndex)
{
	int frameCount;
	int bRemoved = FALSE;
	for (frameCount = 0; frameCount < CalibrationImageInfo.MaxFrameCount[bufferIndex]; frameCount++)
	{
		if (CalibrationImageInfo.FIFOModeStart[bufferIndex] == CalibrationImageInfo.FIFOModeEnd[bufferIndex])
		{
			break;
		}
		
		if (CalibrationImageInfo.FIFOState[CalibrationImageInfo.FIFOModeStart[bufferIndex]][bufferIndex] == IC_CALIB_STATE_CAPTURE_COMPLETE)
		{
			bRemoved = TRUE;
		}
		
		CalibrationImageInfo.FIFOModeStart[bufferIndex] = CalibrationImageInfo.FIFOModeStart[bufferIndex] + 1;
		
		if (CalibrationImageInfo.FIFOModeStart[bufferIndex] == CalibrationImageInfo.MaxFrameCount[bufferIndex])
		{
			CalibrationImageInfo.FIFOModeStart[bufferIndex] = 0;
		}
		if (bRemoved) break;
	}
}

int ImageControl_CalibMode_GetCapturedFrameCount(int bufferIndex)
{
	int frameCount, frameIndex, validFrameCount;
	validFrameCount = 0;
	frameIndex = CalibrationImageInfo.FIFOModeStart[bufferIndex];

	for (frameCount = 0; frameCount < CalibrationImageInfo.MaxFrameCount[bufferIndex]; frameCount++)
	{
		if (frameIndex == CalibrationImageInfo.FIFOModeEnd[bufferIndex])
		{
			break;
		}

		if (CalibrationImageInfo.FIFOState[frameIndex][bufferIndex] == IC_CALIB_STATE_CAPTURE_COMPLETE)
		{
			validFrameCount++;
		}

		frameIndex = frameIndex + 1;
		if (frameIndex == CalibrationImageInfo.MaxFrameCount[bufferIndex])
		{
			frameIndex = 0;
		} 
	}
	
	return validFrameCount;
}

int ImageControl_CalibMode_GetMaxFrameCount(int bufferIndex)
{
	return CalibrationImageInfo.MaxFrameCount[bufferIndex];
}

