// pgmfileOperations.cpp: implementation of the CpgmfileOperations class.
//
//////////////////////////////////////////////////////////////////////

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include "pgmfile.h"
#include "pgmfileOperations.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CpgmfileOperations::CpgmfileOperations()
{

}

CpgmfileOperations::~CpgmfileOperations()
{

}

void CpgmfileOperations::Invert(Cpgmfile & file)
{
	int iSize = file.getDataSize();
	unsigned char chMax = file.getMaxGrayVal();
	unsigned char *pTmp = (unsigned char*)malloc( iSize);
	file.getData(pTmp, iSize);
	for(int i=0;i<iSize;i++){
		pTmp[i] = chMax - pTmp[i];
	}
	file.setData( pTmp, file.getWidth(), file.getHeight());
	free(pTmp);

}//Invert

void CpgmfileOperations::FlipHorizontal(Cpgmfile & file)
{
	int iSize = file.getDataSize();
	int iWidth = file.getWidth();
	int iHeight = file.getHeight();

	unsigned char *pTmp = (unsigned char*)malloc( iSize);
	file.getData(pTmp, iSize);

	unsigned char c;

	for(int j=0;j<iHeight;j++){
		for(int i=0;i<iWidth/2;i++){				//Loop for every horizontal line
			int iInd1, iInd2;
			iInd1 = iWidth-i + (iWidth*j) - 1;
			iInd2 = j*iWidth + i;
			
			c = pTmp[iInd1];
			pTmp[iInd1] = pTmp[iInd2];
			pTmp[iInd2] = c;
		}//for
	}//for

	file.setData( pTmp, file.getWidth(), file.getHeight());
	free(pTmp);
}//FlipHorizontal

void CpgmfileOperations::FlipVertical(Cpgmfile & file)
{
	int iSize = file.getDataSize();
	int iWidth = file.getWidth();
	int iHeight = file.getHeight();

	unsigned char *pTmp = (unsigned char*)malloc( iSize);
	file.getData(pTmp, iSize);
	unsigned char *pLine = (unsigned char*)malloc(iWidth);

	for(int j=0;j<iHeight/2;j++){

		int i1, i2;
		i1 = iWidth*j;
		i2 = (iHeight-j-1)*iWidth;
		memcpy(pLine, &pTmp[i1], iWidth);			//Buffer a line
		memcpy(&pTmp[i1], &pTmp[i2], iWidth);
		memcpy(&pTmp[i2], pLine, iWidth);
			
	}//for

	file.setData( pTmp, file.getWidth(), file.getHeight());
	free(pTmp);
	free(pLine);
}//FlipVertical

void CpgmfileOperations::Rotate90(Cpgmfile &file, bool bClockwise, int iCt){

	if(iCt > 3)
		iCt = iCt%4;

	if(!bClockwise)
		iCt = 4-iCt;			//Convert to clockwise rotation

	if(iCt <= 0)
		return;					//Stops recursion and does sanity check

	int iHeight = file.getHeight();
	int iWidth = file.getWidth();
	int iSize = file.getDataSize();
	
	unsigned char *pTmp = (unsigned char*)malloc( iSize);
	unsigned char *pTmp2 = (unsigned char*)malloc( iSize);
	file.getData(pTmp, iSize);
	unsigned char *pLine = (unsigned char*)malloc(iWidth);

	for(int j=0;j<iHeight;j++){

		for(int i=0;i<iWidth;i++){
			int iSrc = iWidth*j + i;
			int iDest = (iHeight*(i+1))-j-1;//- (iWidth*j);

			pTmp2[iDest] = pTmp[iSrc];

		}//for
	}//for

	file.setData( pTmp2, file.getHeight(), file.getWidth());
	free(pTmp);
	free(pTmp2);
	free(pLine);
	
	Rotate90(file, true, iCt-1);			//Recurse in for additional rotates

}//Rotate90 

void CpgmfileOperations::AdjustBrightness(Cpgmfile & file, int iAmt)
{
	if(iAmt > file.getMaxGrayVal())				//Sanity check
		iAmt = file.getMaxGrayVal();

	if(iAmt < -1*file.getMaxGrayVal())			//Sanity check
		iAmt = -1*file.getMaxGrayVal();

	int iSize = file.getDataSize();
	unsigned char *pTmp = (unsigned char*)malloc( iSize);
	file.getData(pTmp, iSize);

	for(int i=0;i<iSize;i++){
		int val = pTmp[i] + iAmt;
		if(val < 0)
			val = 0;
		else if(val > file.getMaxGrayVal())
			val = file.getMaxGrayVal();

		pTmp[i] = (unsigned char)val;
	}//for

	file.setData( pTmp, file.getWidth(), file.getHeight());
	free(pTmp);

}//AdjustBrightness 

/* Note: This is probably not a proper implementation of contrast adjustment.
   I was just guessing/playing around here and do not claim that this
   is a proper implementation. jjp */
void CpgmfileOperations::AdjustContrast(Cpgmfile & file, int iAmt)
{
	int mgv = file.getMaxGrayVal();
	if(iAmt > mgv/2)				//Sanity check
		iAmt = mgv/2;

	if(iAmt < -1*mgv/2)			//Sanity check
		iAmt = -1*mgv/2;

	int iSize = file.getDataSize();
	unsigned char *pTmp = (unsigned char*)malloc( iSize);
	file.getData(pTmp, iSize);

	for(int i=0;i<iSize;i++){
		int val;
		if(pTmp[i] > mgv/2){				//If on high end...
			val = pTmp[i] + iAmt;
			if(val > mgv)
				val = mgv;
			else if(val < mgv/2)
				val = mgv/2;
		}//else
		else{								//Else on low end...
			val = pTmp[i] - iAmt;
			if(val < 0)
				val = 0;
			else if(val > mgv/2)
				val = mgv/2;
		}//else
		

		pTmp[i] = (unsigned char)val;
	}//for

	file.setData( pTmp, file.getWidth(), file.getHeight());
	free(pTmp);

}//AdjustContrast

void CpgmfileOperations::Resize(Cpgmfile & file, int iHeight, int iWidth)
{

}//Resize
