#include "VideoDisplay.h"

void thermoCamera::VideoDisplay::Draw(const HDC& hdc, const RECT& rect, const HDC buffer) const
{
	BitBlt(hdc,rect.left,rect.top, rect.right, rect.bottom, buffer, 0, 0, SRCCOPY);
}

bool thermoCamera::VideoDisplay::Show(int left, int top,int width, int height, int widthOut, int heightOut, unsigned short** data)
{
	if (_CheckInput(left,top,width,height,widthOut,heightOut,data) == false) return false;

	_imageBuilder.setData(width, height, *data);

	if (_isSetManualTemperatureRange)
	{
		_imageBuilder.setPaletteScalingMethod(evo::eManual);
		_imageBuilder.setManualTemperatureRange(_minMaxRangeTemp.first, _minMaxRangeTemp.second);
	}
	else
	{
		_imageBuilder.setPaletteScalingMethod(evo::eMinMax);
	}

	// Save for record
	unsigned int buff = _sizeOfInputImageDevice.cx * _sizeOfInputImageDevice.cy * sizeof(**data);
	if (buff > 1)
	{
		if (_RawData == NULL) _RawData = new unsigned short[buff];
		memcpy_s(_RawData, buff, *data, buff);
	}


	_sizeOfInputImageDevice = { width,height };

	return (_ProcessOutput(width, height, widthOut, heightOut)) ? true : false;
}

bool thermoCamera::VideoDisplay::ShowWhilePause(int left, int top, int width, int height, int widthOut, int heightOut)
{
	if (_CheckInput(left, top, width, height, widthOut, heightOut) == false) return false;

	_sizeOfInputImageDevice = { width,height };

	return (_ProcessOutput(width, height, widthOut, heightOut)) ? true : false;
}

void thermoCamera::VideoDisplay::EraseAndUpdateWindow()
{
	RECT rect;
	GetClientRect(_hWnd, &rect);
	InvalidateRect(_hWnd, &rect, true);
}

void thermoCamera::VideoDisplay::DrawTemperature(const HDC& hdc, const COLORREF color,float regionTemp)
{
	if (_absolutePositionForDisplay.size() == 0) return;

	bool isNewTemperatureNeeded = true;

	POINT p;
	GetCursorPos(&p);
	ScreenToClient(_hWnd, &p);

	if (_pointTempMouse.x == p.x && _pointTempMouse.y == p.y)
	{
		isNewTemperatureNeeded = false;
	}

	_pointTempMouse = p;
	HFONT hFont = CreateFont(40, 0, 0, 0, FW_BOLD, 0, 0, 0, 0, 0, 0, 2, 0, TEXT("SYSTEM_FIXED_FONT"));
	HFONT hTmp = (HFONT)SelectObject(hdc, hFont);
	SetBkMode(hdc, TRANSPARENT);

	int boundary[4];
	boundary[0] = _absolutePositionForDisplay[0].left + _absolutePositionForDisplay[0].right;
	boundary[1] = _absolutePositionForDisplay[0].left;
	boundary[2] = _absolutePositionForDisplay[0].top + _absolutePositionForDisplay[0].bottom;
	boundary[3] = _absolutePositionForDisplay[0].top;

	if (p.x < boundary[0] && p.x >= boundary[1] && p.y < boundary[2] && p.y >= boundary[3])
	{
		TCHAR chText[100];
		int x = (p.x) - boundary[1];
		int y = (p.y) - boundary[3];
		if(isNewTemperatureNeeded) 
		{
			_temperatureMouse = GetTemperature(x, y, true);
			//float coef, slope;
			//coef = 24.0922;
			//slope = 0.3695;

			//float emisivity_actual = 1;
			//float emisivity_body = 0.98;
			//_temperatureMouse = _temperatureMouse * pow((emisivity_actual / emisivity_body), 1.f / 4.f);

			//_temperatureMouse = slope * _temperatureMouse + coef;
			float region = regionTemp;
			region += GetCalibratedValue();
			if (_isSetRelativeTemp)
			{				
				_temperatureMouse -= region;
			}	
			_temperatureMouse += GetCalibratedValue();
		}
		
		#if UNICODE
		_snwprintf_s(chText, sizeof(chText), TEXT("%.1f"), _temperatureMouse);
		#else
		snprintf(chText, sizeof(chText), "%.1f", _temperatureMouse);
		#endif

		SetTextColor(hdc, color); 

		#if UNICODE
		int scale = 40;
		if (p.y > (boundary[3] + 100) && p.x <= (boundary[0] - 100))
			TextOutW(hdc, p.x, p.y - scale, chText, lstrlen(chText));
		else if (p.y > (boundary[3] + 100) && p.x > (boundary[0] - 100))
			TextOutW(hdc, p.x - scale, p.y - scale, chText, lstrlen(chText));
		else if (p.y < (boundary[3] + 100) && p.x >(boundary[0] - 100))
			TextOutW(hdc, p.x - scale, p.y + scale, chText, lstrlen(chText));
		else
			TextOutW(hdc, p.x, p.y + scale, chText, lstrlen(chText));
		#else
		int scale = 40;
		if (p.y > (boundary[3] + 100) && p.x <= (boundary[0] - 100))
			TextOutA(hdc, p.x, p.y - scale, chText, lstrlen(chText));
		else if (p.y > (boundary[3] + 100) && p.x > (boundary[0] - 100))
			TextOutA(hdc, p.x - scale, p.y - scale, chText, lstrlen(chText));
		else if (p.y < (boundary[3] + 100) && p.x >(boundary[0] - 100))
			TextOutA(hdc, p.x - scale, p.y + scale, chText, lstrlen(chText));
		else
			TextOutA(hdc, p.x, p.y + scale, chText, lstrlen(chText));
		#endif
	}
	DeleteObject(SelectObject(hdc, hTmp));
}

void thermoCamera::VideoDisplay::DrawMinMaxTempBar(const HDC& hdc, RECT& positonBar)
{
	if (_isSetManualTemperatureRange == false)
	{
		return;
	}

	int sizeOFFont = MARGINBAR;
	HFONT hFont = CreateFont(sizeOFFont, 0, 0, 0, FW_BOLD, 0, 0, 0, 0, 0, 0, 2, 0, TEXT("SYSTEM_FIXED_FONT"));
	HFONT hTmp = (HFONT)SelectObject(hdc, hFont);
	SetBkMode(hdc, OPAQUE);
	SetTextColor(hdc, RGBBLACK);

	TCHAR txtMin[20];
	TCHAR txtMax[20];

	#if UNICODE
		_snwprintf_s(txtMin, sizeof(txtMin), TEXT("%.1f"), _minMaxRangeTemp.first);
		_snwprintf_s(txtMax, sizeof(txtMax), TEXT("%.1f"), _minMaxRangeTemp.second);

	#else
		snprintf(txtMin, sizeof(txtMin), "%.0f", _minMaxRangeTemp.first);
		snprintf(txtMax, sizeof(txtMax), "%.0f", _minMaxRangeTemp.second);
	#endif

	TextOut(hdc, positonBar.left, positonBar.top - sizeOFFont, txtMax, lstrlen(txtMax));
	TextOut(hdc, positonBar.left, positonBar.bottom+positonBar.top, txtMin, lstrlen(txtMin));

	DeleteObject(SelectObject(hdc, hTmp));
}

bool thermoCamera::VideoDisplay::_ProcessOutput(int& width, int& height, int& widthOut, int& heightOut)
{
	if (_image == NULL)
	{
		unsigned int res = _imageBuilder.getStride() * height * 3;
		if (res > 0)
		{
			_image = new unsigned char[res];
		}
		else
		{
			return false;
		}
	}
	
	if (_backbuffer.size() >= 1)
	{
		_imageBuilder.setPalette(_palette);
		_imageBuilder.convertTemperatureToPaletteImage(_image);
		_ShowThermalImage(0, 0, width, height, widthOut, heightOut);
	}

	
	if (_backbuffer.size() >= 2)
	{
		int widthBar = _absolutePositionForDisplay[1].right;
		int heightBar = _absolutePositionForDisplay[1].bottom;
		_imageBuilder.getPaletteBar(widthBar, height, _imageBar);
		_ShowThermalImageBar(0, 0, widthBar, height, widthBar, heightBar);
		if (_imageBar) { delete[] _imageBar, _imageBar = NULL; }
	}

	if (_backbuffer.size() >= 3)
	{
		_imageBuilder.setPaletteScalingMethod(evo::eManual);
		_imageBuilder.setPalette(evo::eIron);
		_imageBuilder.setManualTemperatureRange(20, 40);
		_imageBuilder.convertTemperatureToPaletteImage(_image);
		_ShowThermalImageForDetection(0, 0, width, height, widthOut, heightOut);
	}

	return true;
}

void thermoCamera::VideoDisplay::ValidateRect( const RECT& rect) const
{
	InvalidateRect(_hWnd, &rect, true);
}

float thermoCamera::VideoDisplay::ReturnTemperature(RECT rc, int method)
{
	float val = 0.f;

	switch (method)
	{
	case 0:
	{
		val = _getMaxTemperature(rc);
	}
		break;
	default:
		val = 0.f;
		break;
	}

	return val;
}

void thermoCamera::VideoDisplay::ChangePallete(int& index)
{
	_palette = (evo::EnumOptrisColoringPalette)index;
}

void thermoCamera::VideoDisplay::SaveData(const TCHAR* path, unsigned int num)
{
	if (!path) throw thermoCamera::MyError::badInput;
	if(_sizeOfInputImageDevice.cx <= 0 || _sizeOfInputImageDevice.cy <= 0) throw thermoCamera::MyError::badInput;
	if (_image == NULL) throw thermoCamera::MyError::badInput;

	--num;
	TCHAR fullPath[MAX_PATH];

	#if UNICODE
		wcscpy_s(fullPath, wcslen(path) + 1, path);

		TCHAR numStr[MAX_PATH];
		swprintf_s(numStr, sizeof(numStr), TEXT("%d"), num);

		const TCHAR* format = TEXT(".txt");
		size_t size = wcslen(fullPath) + wcslen(numStr) + wcslen(format) + 1;

		wcscat_s(fullPath, size, numStr);
		wcscat_s(fullPath, size, format);

		std::ofstream myFile;
		myFile.open(fullPath);
		if (!myFile.is_open()) throw thermoCamera::MyError::cannotOpenFile;
	#else
		strcpy_s(fullPath, strlen(path) + 1, path);

		TCHAR numStr[MAX_PATH];
		snprintf(numStr, sizeof(numStr), TEXT("%d"), num);

		const TCHAR* format = TEXT(".txt");
		size_t size = strlen(fullPath) + strlen(numStr) + strlen(format) + 1;

		strcat_s(fullPath, size, numStr);
		strcat_s(fullPath, size, format);

		std::ofstream myFile;
		myFile.open(fullPath);
		if (!myFile.is_open()) throw thermoCamera::MyError::cannotOpenFile;
	#endif
	

	unsigned int buff = _sizeOfInputImageDevice.cx * _sizeOfInputImageDevice.cy * sizeof(*_RawData);

	unsigned short* _thermalDataTemp = new unsigned short[buff];

	memcpy_s(_thermalDataTemp, buff, _RawData, buff);

	if (_thermalDataTemp)
	{
		myFile << buff << "\n";
		myFile << _sizeOfInputImageDevice.cx << "\n";
		myFile << _sizeOfInputImageDevice.cy << "\n";
		for (size_t i = 0; i < buff; i++)
		{
			myFile << _thermalDataTemp[i] << "\n";
		}
	}
	if (_thermalDataTemp) delete[] _thermalDataTemp;
	myFile.close();
}

void thermoCamera::VideoDisplay::SaveBitMap(HBITMAP hBitMap, const TCHAR* path, unsigned int num)
{
	if (!path) return;
	if (!hBitMap) return;

	TCHAR fullPath[MAX_PATH];

	CImage image;

#ifdef  UNICODE
	wcscpy_s(fullPath, wcslen(path) + 1, path);

	wcscat_s(fullPath, MAX_PATH, TEXT("\\"));

	TCHAR numStr[MAX_PATH];
	swprintf_s(numStr, sizeof(numStr), TEXT("%d"), num);

	const TCHAR* format = TEXT(".bmp");
	size_t size = wcslen(fullPath) + wcslen(numStr) + wcslen(format) + 1;

	wcscat_s(fullPath, size, numStr);
	wcscat_s(fullPath, size, format);

	image.Attach(hBitMap);
	image.Save(fullPath);
#else
	  
	strcpy_s(fullPath, strlen(path) + 1, path);

	strcat_s(fullPath, MAX_PATH, "\\");

	TCHAR numStr[MAX_PATH];
	snprintf(numStr, sizeof(numStr), TEXT("%d"), num);

	const TCHAR* format = TEXT(".bmp");
	size_t size = strlen(fullPath) + strlen(numStr) + strlen(format) + 1;

	strcat_s(fullPath, size, numStr);
	strcat_s(fullPath, size, format);

	LPCTSTR pszCharacterString = (LPCTSTR)path;
	image.Attach(hBitMap);
	image.Save(pszCharacterString);
#endif 
}

void thermoCamera::VideoDisplay::SaveScreenShot(HWND hWnd,RECT screen, const TCHAR* path, unsigned int num)
{
	HDC current = GetDC(hWnd);

	HDC buff = CreateCompatibleDC(current);

	HBITMAP hbitmap = CreateCompatibleBitmap(current, screen.right, screen.bottom);

	SelectObject(buff, (HGDIOBJ)hbitmap);

	BITMAPINFO bmi;
	memset(&bmi, 0, sizeof(BITMAPINFO));
	bmi.bmiHeader.biSize = sizeof(BITMAPINFO);
	bmi.bmiHeader.biWidth = screen.right;
	bmi.bmiHeader.biHeight = -screen.top;
	bmi.bmiHeader.biPlanes = 1;
	bmi.bmiHeader.biBitCount = 24;
	bmi.bmiHeader.biCompression = BI_RGB;

	BitBlt(buff, 0, 0, screen.right, screen.bottom, current, screen.left, screen.top, SRCCOPY);

	SaveBitMap(hbitmap, path, num);

	ReleaseDC(hWnd, current);

	DeleteObject(hbitmap);
	DeleteDC(buff);
}

void thermoCamera::VideoDisplay::LoadData(const TCHAR* path, unsigned int num)
{
	if (!path) throw thermoCamera::MyError::badInput;
	#if UNICODE
		// chagne bmp to txt
		std::wstring str(path);
		// find last occurrence of path separator
		size_t found = str.find_last_of(TEXT("."));
		// split off filename part of string
		str = str.substr(0, found);
		str += TEXT(".txt");
	#else
		// chagne bmp to txt
		std::string str(path);
		// find last occurrence of path separator
		size_t found = str.find_last_of(TEXT("."));
		// split off filename part of string
		str = str.substr(0, found);
		str += TEXT(".txt");
	#endif
	

	std::ifstream myFile;
	myFile.open(str);
	if (!myFile.is_open()) throw thermoCamera::MyError::cannotOpenFile;

	size_t sizeBuff = 0;
	myFile >> sizeBuff;
	myFile >> _sizeOfInputImageDevice.cx;
	myFile >> _sizeOfInputImageDevice.cy;

	if (_thermalDataFromRecord == NULL) _thermalDataFromRecord = new unsigned short[sizeBuff];
	for (int i = 0; i < sizeBuff; i++)
	{
		myFile >> _thermalDataFromRecord[i];
	}
	myFile.close();
}

void thermoCamera::VideoDisplay::LoadWidthHeight(const TCHAR* path, SIZE& sizeOfImage, size_t numberOfTxt)
{
		if (!path) throw thermoCamera::MyError::badInput;
		#if UNICODE
			std::wstring str(path);
			str += std::to_wstring(numberOfTxt);
			str += TEXT(".txt");
		#else
			std::string str(path);
			str += std::to_string(numberOfTxt);
			str +=  ".txt";
		#endif

		std::ifstream myFile;
		myFile.open(str);
		if (!myFile.is_open()) throw thermoCamera::MyError::cannotOpenFile;

		size_t sizeBuff = 0;
		myFile >> sizeBuff;
		myFile >> sizeOfImage.cx;
		myFile >> sizeOfImage.cy;
}

void thermoCamera::VideoDisplay::DeleteObjects()
{
	for (size_t i = 0; i < _backbuffer.size(); i++)
	{
		DeleteObject(_hBitMap[i]);
		DeleteDC(_backbuffer[i]);
	}
}

void thermoCamera::VideoDisplay::DeleteObjects(int index)
{
	if (_backbuffer.size() > index)
	{
		DeleteObject(_hBitMap[index]);
		DeleteDC(_backbuffer[index]);
	}
}

float thermoCamera::VideoDisplay::GetTemperature(int x, int y, bool isStretchCoordinatesNeeded)
{
	if (isStretchCoordinatesNeeded)
	{
		int xReal = 0;
		int yReal = 0;
		_fromStretched2RealCoordinates(x, y, xReal, yReal);
		float temp = _imageBuilder.getTemperatureAt(xReal, yReal);
		return temp;
	}
	else
	{
		float temp = _imageBuilder.getTemperatureAt(x, y);
		return temp;
	}
}

HDC thermoCamera::VideoDisplay::GetHDC(int index)
{
	if (_backbuffer.size() > index)
	{
		return _backbuffer[index];
	}
	else
	{
		return NULL;
	}
}

HBITMAP thermoCamera::VideoDisplay::GetHBITMAP(int index)
{
	if (_hBitMap.size() > index)
	{
		return _hBitMap[index];
	}
	else
	{
		return NULL;
	}
}

RECT thermoCamera::VideoDisplay::GetSizeOfVideo(int index)
{
	if (_absolutePositionForDisplay.size() > index)
	{
		return _absolutePositionForDisplay[index];
	}
	else
	{
		RECT rec = { 0,0,0,0 };
		return rec;
	}
}

void thermoCamera::VideoDisplay::SetPosition(RECT& rect, int index)
{
	if (_absolutePositionForDisplay.size() > index)
	{
		_absolutePositionForDisplay[index] = { rect.left,rect.top,rect.right,rect.bottom };
	}
}

void thermoCamera::VideoDisplay::EraseHDC(int index)
{
	if (_backbuffer.size() > index)
	{
		DeleteObjects(index);
		_backbuffer.erase(_backbuffer.begin() + index);
	}
}

void thermoCamera::VideoDisplay::EraseBitMap(int index)
{
	if (_hBitMap.size() > index)
	{
		_hBitMap.erase(_hBitMap.begin() + index);
	}
}

void thermoCamera::VideoDisplay::_ShowThermalImage(int x, int y,int width, int height, int widthOut, int heightOut )
{
	if (_image)
	{
		BITMAPINFO bmi;
		memset(&bmi, 0, sizeof(BITMAPINFO));
		bmi.bmiHeader.biSize = sizeof(BITMAPINFO);
		bmi.bmiHeader.biWidth = _imageBuilder.getStride();
		bmi.bmiHeader.biHeight = -height;
		bmi.bmiHeader.biPlanes = 1;
		bmi.bmiHeader.biBitCount = 24;
		bmi.bmiHeader.biCompression = BI_RGB;

		StretchDIBits(_backbuffer[INDEX_HBITMAP_OF_VIDEO], x, y, widthOut, heightOut, x, y, width, height, _image, &bmi, DIB_RGB_COLORS, SRCCOPY);

		RECT invalid = { _absolutePositionForDisplay[INDEX_HBITMAP_OF_VIDEO].left,_absolutePositionForDisplay[INDEX_HBITMAP_OF_VIDEO].top,_absolutePositionForDisplay[INDEX_HBITMAP_OF_VIDEO].left + widthOut,_absolutePositionForDisplay[INDEX_HBITMAP_OF_VIDEO].top + heightOut };
		InvalidateRect(_hWnd, &invalid, false);
	}
}

void thermoCamera::VideoDisplay::_ShowThermalImageForDetection(int x, int y, int width, int height, int widthOut, int heightOut)
{
	if (_image)
	{
		BITMAPINFO bmi;
		memset(&bmi, 0, sizeof(BITMAPINFO));
		bmi.bmiHeader.biSize = sizeof(BITMAPINFO);
		bmi.bmiHeader.biWidth = _imageBuilder.getStride();
		bmi.bmiHeader.biHeight = -height;
		bmi.bmiHeader.biPlanes = 1;
		bmi.bmiHeader.biBitCount = 24;
		bmi.bmiHeader.biCompression = BI_RGB;

		StretchDIBits(_backbuffer[INDEX_HBITMAP_OF_DETECTION], x, y, width, height, x, y, width, height, _image, &bmi, DIB_RGB_COLORS, SRCCOPY);

		RECT invalid = { _absolutePositionForDisplay[INDEX_HBITMAP_OF_DETECTION].left,_absolutePositionForDisplay[INDEX_HBITMAP_OF_DETECTION].top,_absolutePositionForDisplay[INDEX_HBITMAP_OF_DETECTION].left+width,_absolutePositionForDisplay[INDEX_HBITMAP_OF_DETECTION].top + height };
		InvalidateRect(_hWnd, &invalid, false);
	}
}

void thermoCamera::VideoDisplay::_ShowThermalImageBar(int x, int y, int width, int height, int widthOut, int heightOut)
{
	if (_imageBar)
	{
		BITMAPINFO bmi;
		memset(&bmi, 0, sizeof(BITMAPINFO));
		bmi.bmiHeader.biSize = sizeof(BITMAPINFO);
		bmi.bmiHeader.biWidth = width;
		bmi.bmiHeader.biHeight = -height;
		bmi.bmiHeader.biPlanes = 1;
		bmi.bmiHeader.biBitCount = 24;
		bmi.bmiHeader.biCompression = BI_RGB;

		StretchDIBits(_backbuffer[INDEX_HBITMAP_OF_BAR], x, y, widthOut, heightOut, x, y, width, height, _imageBar, &bmi, DIB_RGB_COLORS, SRCCOPY);

		RECT invalid = { _absolutePositionForDisplay[INDEX_HBITMAP_OF_BAR].left,_absolutePositionForDisplay[INDEX_HBITMAP_OF_BAR].top-MARGINBAR,_absolutePositionForDisplay[INDEX_HBITMAP_OF_BAR].left + widthOut,_absolutePositionForDisplay[INDEX_HBITMAP_OF_BAR].top + heightOut +MARGINBAR};
		InvalidateRect(_hWnd, &invalid, false);
	}
}

bool thermoCamera::VideoDisplay::_CheckInput(int& left, int& top, int& width, int& height, int& widthOut, int& heightOut, unsigned short**& data)
{
	if (*data == NULL) return false;

	if (left <= 0 || top <= 0 || width <= 0 || height <= 0 || widthOut <= 0 || heightOut <= 0) return false;

	return true;
}

bool thermoCamera::VideoDisplay::_CheckInput(int& left, int& top, int& width, int& height, int& widthOut, int& heightOut)
{
	if (left <= 0 || top <= 0 || width <= 0 || height <= 0 || widthOut <= 0 || heightOut <= 0) return false;

	return true;
}

void thermoCamera::VideoDisplay::_fromStretched2RealCoordinates(int& x, int& y, int& xReal, int& yReal) 
{
	if (_absolutePositionForDisplay.size() == 0) return;
	// for x
	float inlox = 0;
	float inupx = _absolutePositionForDisplay[0].right;
	float outlox = 0;
	float outupx = _sizeOfInputImageDevice.cx;
	float spanx = ((outupx - outlox) / (inupx - inlox));
	xReal = (x - inlox) * ((outupx - outlox) / (inupx - inlox)) + outlox;
	//for y
	float inloy = 0;
	float inupy = _absolutePositionForDisplay[0].bottom;
	float outloy = 0;
	float outupy = _sizeOfInputImageDevice.cy;
	yReal = (y - inloy) * ((outupy - outloy) / (inupy - inloy)) + outloy;
}

void thermoCamera::VideoDisplay::_transformLinear2D(int& x, int& y, int& xReal, int& yReal, float inlox, float inupx, float outlox, float outupx, float inloy, float inupy, float outloy, float outupy)
{
	// for x
	float spanx = ((outupx - outlox) / (inupx - inlox));
	xReal = (x - inlox) * spanx + outlox;
	//for y
	float spany = ((outupy - outloy) / (inupy - inloy));
	yReal = (y - inloy) * spany + outloy;
}

float thermoCamera::VideoDisplay::_getMaxTemperature(RECT& rc)
{
	int left = _absolutePositionForDisplay[0].left;
	int top = _absolutePositionForDisplay[0].top;

	int x = rc.left - left;
	int y = rc.top - top;

	int width = rc.right - _absolutePositionForDisplay[0].left;
	int height = rc.bottom - _absolutePositionForDisplay[0].top;

	float max = 0.f;
	float val = 0.f;


	for (size_t i = x; i < width; i++)
	{
		for (size_t j = y; j < height; j++)
		{
			val = GetTemperature(i, j,true);
			if (val > max)
				max = val;
		}
	}

	return max;
}