#include "stdafx.h"
#include "CompareSN.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

HINSTANCE hCompareSNLibDLL = NULL;	
CString strLibModuleName;
CString strCompareFormat;
int (*funcCompareSN)(CString&, CString&) = NULL;
CString (*funcGetPrevSN)(CString&) = NULL;
CString (*funcGetNextSN)(CString&) = NULL;

DLL_EXPORT bool InitCompareLib(CaplAPI *pAPI)
{
	if (pAPI == NULL)
		return true;	

	pAPI->m_options_mgr.GetOptionValueBN(APL_NO_T("PSS\\Íàñòðîéêè\\Ôîðìàò ñåðèéíûõ íîìåðîâ"), strCompareFormat, _T(""));
	pAPI->m_options_mgr.GetOptionValueBN(APL_NO_T("PSS\\Íàñòðîéêè\\Ôîðìàò ñåðèéíûõ íîìåðîâ\\Ìîäóëü ñåðèéíûõ íîìåðîâ"), strLibModuleName, _T(""));	

	if (!strLibModuleName.IsEmpty())
	{
		hCompareSNLibDLL = AfxLoadLibrary(strLibModuleName);

		if (hCompareSNLibDLL != NULL)
		{
			(FARPROC&)funcCompareSN = ::GetProcAddress(hCompareSNLibDLL, "CompareSN");

			if (funcCompareSN != NULL)
				return true;
		}

		if (hCompareSNLibDLL != NULL)
		{
			(FARPROC&)funcGetPrevSN = ::GetProcAddress(hCompareSNLibDLL, "GetPrevSN");

			if (funcGetPrevSN != NULL)
				return true;
		}

		if (hCompareSNLibDLL != NULL)
		{
			(FARPROC&)funcGetNextSN = ::GetProcAddress(hCompareSNLibDLL, "GetNextSN");

			if (funcGetNextSN != NULL)
				return true;
		}
	}	

	if (strCompareFormat.MakeLower() == CString(_T("kvz")))
	{
		funcCompareSN = KVZCompareSN;
		funcGetPrevSN = KVZGetPrevSN;
		funcGetNextSN = KVZGetNextSN;

		//////////////////////////////////////////////////////////////////////////
		// Äëÿ ïðîâåðêè

//*
		CString strSN1 = _T("03302129");
		CString strSN2 = _T("09305128");
		CString strValue;

		BOOL bRes = IntervalIsVerified(strSN1, strSN2);
		bRes = IntervalIsVerified(strSN1, strSN1);
		bRes = IntervalIsVerified(strSN2, strSN1);
		bRes = IntervalIsVerified(strSN2, strSN2);

		int iRes = funcCompareSN(strSN1, strSN2);
		strValue = funcGetPrevSN(strSN1);
		strValue = funcGetNextSN(strSN1);

		strSN1 = _T("09310123");
		strSN2 = _T("09305124");

		iRes = funcCompareSN(strSN1, strSN2);
		strValue = funcGetPrevSN(strSN1);
		strValue = funcGetNextSN(strSN1);

		strSN1 = _T("03302130");
		strSN2 = _T("03303120");

		iRes = funcCompareSN(strSN1, strSN2);
		strValue = funcGetPrevSN(strSN1);
		strValue = funcGetNextSN(strSN1);

		strSN1 = _T("85501124");
		strSN2 = _T("85510122");

		iRes = funcCompareSN(strSN1, strSN2);
		strValue = funcGetPrevSN(strSN1);
		strValue = funcGetNextSN(strSN1);
//*/

		return true;
	}

	return true;
}

//////////////////////////////////////////////////////////////////////////
// IsKVZSN

DLL_EXPORT BOOL IsKVZSN(CString &sn)
{
	return (IsMi8KVZSN(sn) || IsShortMi8KVZSN(sn)|| IsAnsatKVZSN(sn) || IsMi8BladesKVZSN(sn) || IsOPKVZSN(sn) || IsMi38(sn));
}

DLL_EXPORT BOOL IsShortMi8KVZSN(CString &sn)
{
	if(sn.IsEmpty() == true)
		return TRUE;
	if (sn.GetLength() != 5)
		return FALSE;
	if(!aplIsDigit(sn))
		return FALSE;

	int iSerialNumber = _atoi(sn.Right(3));
	int iProductNumber = _atoi(sn.Left(2));
	if(iProductNumber>10 || iProductNumber<1)
		return FALSE;
	if(iSerialNumber<1)
		return FALSE;

	return TRUE;
}

DLL_EXPORT BOOL IsMi38(CString &sn)
{
	if(sn.IsEmpty() == true)
		return TRUE;

	if (sn.GetLength() != 5)
		return FALSE;

	if (sn.Left(2) != "26")
		return FALSE;

	return TRUE;
}

DLL_EXPORT BOOL IsMi8KVZSN(CString &sn)
{
	if(sn.IsEmpty() == true)
		return TRUE;

	if (sn.GetLength() != 8)
		return FALSE;

	if (sn.Find(_T("093")) != 0)
		return FALSE;

	int iSerialNumber = _atoi(sn.Right(3));
	int iProductNumber = _atoi(sn.Mid(3, 2));

	for (int iIndex = 0; iIndex < sn.GetLength(); iIndex++)
	{
		if ((sn[iIndex] < _T('0')) || (sn[iIndex] > _T('9')))
			return FALSE;
	}

	if ((iProductNumber < 1) || (iProductNumber > 10))
		return FALSE;

	return TRUE;
}

DLL_EXPORT BOOL IsAnsatKVZSN(CString &sn)
{
	if(sn.IsEmpty() == true)
		return TRUE;

//	if (sn.GetLength() != 8)
	if (sn.GetLength() != 7)
		return FALSE;

	if (sn.Find(_T("033")) != 0)
		return FALSE;

//	int iSerialNumber = atoi(sn.Right(3));
	int iSerialNumber = _atoi(sn.Right(2));
	int iProductNumber = _atoi(sn.Mid(3, 2));

	for (int iIndex = 0; iIndex < sn.GetLength(); iIndex++)
	{
		if ((sn[iIndex] < _T('0')) || (sn[iIndex] > _T('9')))
			return FALSE;
	}

	if ((iProductNumber < 1) || (iProductNumber > 3))
		return FALSE;

	return TRUE;
}

DLL_EXPORT BOOL IsMi8BladesKVZSN(CString &sn)
{
	if(sn.IsEmpty() == true)
		return TRUE;

	if (sn.GetLength() != 8)
		return FALSE;

	if (sn.Find(_T("855")) != 0)
		return FALSE;

	int iSerialNumber = _atoi(sn.Right(3));
	int iProductNumber = _atoi(sn.Mid(3, 2));

	for (int iIndex = 0; iIndex < sn.GetLength(); iIndex++)
	{
		if ((iIndex == 5) && (sn[iIndex] != _T('-')))
			return FALSE;
		else if ((sn[iIndex] < _T('0')) || (sn[iIndex] > _T('9')))
			return FALSE;
	}

	if ((iProductNumber < 1) || (iProductNumber > 20))
		return FALSE;

	return TRUE;
}

DLL_EXPORT BOOL IsOPKVZSN(CString &sn)
{
	if(sn.IsEmpty() == true)
		return TRUE;

	CString strPrototypeDescr = sn.Left(2);

	strPrototypeDescr.MakeLower();

	if ((strPrototypeDescr == CString(APL_NO_T("ïò"))) && (sn.GetLength() == 5))
	{
		int iProductNumber = _atoi(sn.Mid(3, 2));

		if ((sn[3] == _T('0')) && ((iProductNumber < 1) || (iProductNumber > 9)))
			return FALSE;

		return TRUE;
	}

	if ((strPrototypeDescr == CString(APL_NO_T("îï"))) && (sn.GetLength() == 4))
	{
		int iProductNumber = _atoi(sn.Mid(3, 1));

		if ((iProductNumber < 1) || (iProductNumber > 9))
			return FALSE;

		return TRUE;
	}

	return FALSE;
}

DLL_EXPORT BOOL IntervalIsVerified(CString &sn1, CString &sn2)
{
	if (!((IsAnsatKVZSN(sn1) && IsAnsatKVZSN(sn2)) ||
		  (IsMi8KVZSN(sn1) && IsMi8KVZSN(sn2)) ||
		  (IsShortMi8KVZSN(sn1) && IsShortMi8KVZSN(sn2))	||
		  (IsMi8BladesKVZSN(sn1) && IsMi8BladesKVZSN(sn2)) ||
		  (IsOPKVZSN(sn1) && IsOPKVZSN(sn2))))
		return FALSE;
	else
		return TRUE;
}

//////////////////////////////////////////////////////////////////////////
// CompareSN

DLL_EXPORT int CompareSN(CString &sn1, CString &sn2)
{
	if (funcCompareSN != NULL)
		return funcCompareSN(sn1, sn2);
	
	if (sn1.GetLength() != sn2.GetLength())
	{
		if (sn1.GetLength() > sn2.GetLength())
			return 1;
		else
			return -1;
	}

	return sn1.Compare(sn2);
}

int KVZCompareSN(CString &sn1Orign, CString &sn2Orign)
{	
	CString sn1 = sn1Orign;
	CString sn2 = sn2Orign;

	if(sn1.GetLength() == 8 && 0 == sn1.Left(3).CompareNoCase(_T("093")))
		sn1 = sn1.Right(5);

	if(sn2.GetLength() == 8 && 0 == sn2.Left(3).CompareNoCase(_T("093")))
		sn2 = sn2.Right(5);

	if (sn1.GetLength() != sn2.GetLength())
	{
		if (sn1.GetLength() > sn2.GetLength() && !sn2.IsEmpty())
			return 1;
		else
			return -1;
	}

	if (!IntervalIsVerified(sn1, sn2))
		return sn1.Compare(sn2);
	
	int iSerialNumber1 = -1;
	int iSerialNumber2 = -1;
	int iProductNumber1 = -1;
	int iProductNumber2 = -1;	
	
	if(sn1.GetLength()==8)
	{
		iSerialNumber1 = _atoi(sn1.Right(3));
		iSerialNumber2 = _atoi(sn2.Right(3));
		iProductNumber1 = _atoi(sn1.Mid(3, 2));
		iProductNumber2 = _atoi(sn2.Mid(3, 2));	
	}
	else if(sn1.GetLength()==7)
	{
		iSerialNumber1 = _atoi(sn1.Right(2));
		iSerialNumber2 = _atoi(sn2.Right(2));
		iProductNumber1 = _atoi(sn1.Mid(3, 2));
		iProductNumber2 = _atoi(sn2.Mid(3, 2));	
	}
	else if(sn1.GetLength()==5)
	{
		iSerialNumber1 = _atoi(sn1.Right(3));
		iSerialNumber2 = _atoi(sn2.Right(3));
		iProductNumber1 = _atoi(sn1.Mid(0, 2));
		iProductNumber2 = _atoi(sn2.Mid(0, 2));			
	}
	else
		return sn1.Compare(sn2);

	// Ñðàâíåíèå ñåðèé
	if (iSerialNumber1 > iSerialNumber2)
		return 1;
	else if (iSerialNumber1 < iSerialNumber2)
		return -1;

	// Ñðàâíåíèå íîìåðîâ
	if (iProductNumber1 > iProductNumber2)
		return 1;
	else if (iProductNumber1 < iProductNumber2)
		return -1;

	return 0;
}

//
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
// GetPrevSN

DLL_EXPORT CString GetPrevSN(CString &sn)
{
	if (funcGetPrevSN != NULL)
		return funcGetPrevSN(sn);

	return GetStringPrevSN(sn);
}

DLL_EXPORT CString KVZGetPrevSN(CString &sn)
{
	if (!IsKVZSN(sn))
		return GetStringPrevSN(sn);

	CString strPrev;	

	if (IsMi8KVZSN(sn))
	{
		int iSerialNumber = _atoi(sn.Right(3));
		int iProductNumber = _atoi(sn.Mid(3, 2)) - 1;

		if (iProductNumber < 1)
		{
			if (iSerialNumber > 0)
			{
				iSerialNumber--;
				iProductNumber = 10;
			}
			else
				iProductNumber = 1;
		}

		strPrev.Format(_T("093%.2d%.3d"), iProductNumber, iSerialNumber);
	}
	else if(IsMi38(sn))
	{
		int iSerialNumber = _atoi(sn.Right(3));

		if(iSerialNumber == 1)
			iSerialNumber = 999;
		else
			iSerialNumber--;

		strPrev.Format(_T("%s%.3d"), sn.Left(2), iSerialNumber);
	}
	else if(IsShortMi8KVZSN(sn))
	{
		int iSerialNumber = _atoi(sn.Right(3));
		int iProductNumber = _atoi(sn.Mid(0, 2)) - 1;
		if (iProductNumber < 1)
		{
			if (iSerialNumber > 0)
			{
				iSerialNumber--;
				iProductNumber = 10;
			}
			else
				iProductNumber = 1;
		}
		strPrev.Format(_T("%.2d%.3d"), iProductNumber, iSerialNumber);
	}
	else if (IsMi8BladesKVZSN(sn))
	{
		int iSerialNumber = _atoi(sn.Right(3));
		int iProductNumber = _atoi(sn.Mid(3, 2)) - 1;

		if (iProductNumber < 1)
		{
			if (iSerialNumber > 0)
			{
				iSerialNumber--;
				iProductNumber = 20;
			}
			else
				iProductNumber = 1;
		}

		strPrev.Format(_T("855%.2d-%.3d"), iProductNumber, iSerialNumber);
	}
	else if (IsAnsatKVZSN(sn))
	{
//		int iSerialNumber = _atoi(sn.Right(3));
		int iSerialNumber = _atoi(sn.Right(2));
		int iProductNumber = _atoi(sn.Mid(3, 2)) - 1;

		if (iProductNumber < 1)
		{
			if (iSerialNumber > 0)
			{
				iSerialNumber--;
				iProductNumber = 3;
			}
			else
				iProductNumber = 1;
		}

//		strPrev.Format(_T("033%.2d%.3d"), iProductNumber, iSerialNumber);
		strPrev.Format(_T("033%.2d%.2d"), iProductNumber, iSerialNumber);
	}
	else if (IsOPKVZSN(sn))
	{
		CString strPrefix = sn.Left(2);
		int iProductNumber = 0;

		strPrefix.MakeLower();

		if (strPrefix[0] == _T('î'))
		{
			iProductNumber = _atoi(sn.Mid(3, 1)) - 1;

			if (iProductNumber < 1)
				iProductNumber = 1;

			strPrev.Format(APL_NO_T("ÎÏ-%.1d"), iProductNumber);
		}
		else
		{
			iProductNumber = _atoi(sn.Mid(3, 2)) - 1;

			if (iProductNumber < 1)
				iProductNumber = 1;

			strPrev.Format(APL_NO_T("ÏÒ-%.2d"), iProductNumber);
		}
	}

	return strPrev;
}
DLL_EXPORT CString GetStringPrevSN(CString &sn)
{
	CString strSymbol = APL_NO_T("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZàáâãäå¸æçèéêëìíîïðñòóôõö÷øùüûúýþÿÀÁÂÃÄÅ¨ÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÜÛÚÝÞß");
	if(sn.IsEmpty())
		return _T("");
	CString strPrev = sn;
	BOOL bShouldBeCut = TRUE;

	if (strPrev.IsEmpty())
		return strPrev;

	for (int iIndex = 0; iIndex < strPrev.GetLength(); iIndex++)
	{
		if (strPrev[iIndex] != strSymbol[0])
		{
			bShouldBeCut = FALSE;
			break;
		}
	}

	if (bShouldBeCut)
	{
		strPrev.Empty();

		for (int iIndex = 0; iIndex < (sn.GetLength() - 1); iIndex++)
			strPrev += strSymbol[strSymbol.GetLength() - 1];

		return strPrev;
	}

	for (int iIndex = 0; iIndex < strPrev.GetLength(); iIndex++)
	{
		BOOL bChangePrevSymbol = FALSE;
		int  iFoundItemIndex = strSymbol.Find(strPrev[strPrev.GetLength() - iIndex - 1]);

		if (iFoundItemIndex != -1)
		{
			if (iFoundItemIndex == 0)				
			{
				strPrev.SetAt(strPrev.GetLength() - iIndex - 1, strSymbol[strSymbol.GetLength() - 1]);
				bChangePrevSymbol = TRUE;
			}
			else
				strPrev.SetAt(strPrev.GetLength() - iIndex - 1, strSymbol[iFoundItemIndex - 1]);
		}
		else
			strPrev.SetAt(strPrev.GetLength() - iIndex - 1, strSymbol[strSymbol.GetLength() - 1]);

		if (!bChangePrevSymbol)
			break;
	}

	return strPrev;
}

//
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
// GetNextSN

DLL_EXPORT CString GetNextSN(CString &sn)
{
	if (funcGetNextSN != NULL)
		return funcGetNextSN(sn);

	return GetStringNextSN(sn);
}

DLL_EXPORT CString KVZGetNextSN(CString &sn)
{
	if (!IsKVZSN(sn))
		return GetStringNextSN(sn);

	CString strNext;	

	if (IsMi8KVZSN(sn))
	{
		int iSerialNumber = _atoi(sn.Right(3));
		int iProductNumber = _atoi(sn.Mid(3, 2)) + 1;

		if (iProductNumber > 10)
		{
			if (iSerialNumber < 999)
			{
				iSerialNumber++;
				iProductNumber = 1;
			}
			else
				iProductNumber = 10;
		}

		strNext.Format(_T("093%.2d%.3d"), iProductNumber, iSerialNumber);
	}
	else if(IsMi38(sn))
	{
		int iSerialNumber = _atoi(sn.Right(3));

		if(iSerialNumber == 999)
			iSerialNumber = 1;
		else
			iSerialNumber++;

		strNext.Format(_T("%s%.3d"), sn.Left(2), iSerialNumber);
	}
	else if(IsShortMi8KVZSN(sn))
	{
		int iSerialNumber = _atoi(sn.Right(3));
		int iProductNumber = _atoi(sn.Mid(0, 2)) + 1;
		if (iProductNumber > 10)
		{
			if (iSerialNumber < 999)
			{
				iSerialNumber++;
				iProductNumber = 1;
			}
			else
				iProductNumber = 10;
		}
		strNext.Format(_T("%.2d%.3d"), iProductNumber, iSerialNumber);
	}
	else if (IsMi8BladesKVZSN(sn))
	{
		int iSerialNumber = _atoi(sn.Right(3));
		int iProductNumber = _atoi(sn.Mid(3, 2)) + 1;

		if (iProductNumber > 20)
		{
			if (iSerialNumber < 999)
			{
				iSerialNumber++;
				iProductNumber = 1;
			}
			else
				iProductNumber = 20;
		}

		strNext.Format(_T("855%.2d-%.3d"), iProductNumber, iSerialNumber);
	}
	else if (IsAnsatKVZSN(sn))
	{
//		int iSerialNumber = _atoi(sn.Right(3));
		int iSerialNumber = _atoi(sn.Right(2));
		int iProductNumber = _atoi(sn.Mid(3, 2)) + 1;

		if (iProductNumber > 3)
		{
			if (iSerialNumber < 999)
			{
				iSerialNumber++;
				iProductNumber = 1;
			}
			else
				iProductNumber = 3;
		}

//		strNext.Format(_T("033%.2d%.3d"), iProductNumber, iSerialNumber);
		strNext.Format(_T("033%.2d%.2d"), iProductNumber, iSerialNumber);
	}
	else if (IsOPKVZSN(sn))
	{
		CString strPrefix = sn.Left(2);
		int iProductNumber = 0;

		strPrefix.MakeLower();

		if (strPrefix[0] == _T('î'))
		{
			iProductNumber = _atoi(sn.Mid(3, 1)) + 1;

// 			if (iProductNumber > 3)
// 				iProductNumber = 3;

			strNext.Format(APL_NO_T("ÎÏ-%.1d"), iProductNumber);
		}
		else
		{
			iProductNumber = _atoi(sn.Mid(3, 2)) + 1;

// 			if (iProductNumber > 5)
// 				iProductNumber = 5;

			strNext.Format(APL_NO_T("ÏÒ-%.2d"), iProductNumber);
		}			
	}

	return strNext;
}

DLL_EXPORT CString GetStringNextSN(CString &sn)
{
	CString strSymbol = APL_NO_T("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZàáâãäå¸æçèéêëìíîïðñòóôõö÷øùüûúýþÿÀÁÂÃÄÅ¨ÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÜÛÚÝÞß");
	if(sn.IsEmpty())
		return _T("");
	CString strNext = sn;

	BOOL bShouldBeExpanded = TRUE;

	for (int iIndex = 0; iIndex < strNext.GetLength(); iIndex++)
	{
		if (strNext[iIndex] != strSymbol[strSymbol.GetLength() - 1])
		{
			bShouldBeExpanded = FALSE;
			break;
		}
	}

	if (bShouldBeExpanded)
	{
		strNext.Empty();

		for (int iIndex = 0; iIndex < (sn.GetLength() + 1); iIndex++)
			strNext += strSymbol[0];

		return strNext;
	}

	for (int iIndex = 0; iIndex < strNext.GetLength(); iIndex++)
	{
		BOOL bChangePrevSymbol = FALSE;
		int  iFoundItemIndex = strSymbol.Find(strNext[strNext.GetLength() - iIndex - 1]);

		if (iFoundItemIndex != -1)
		{
			if (iFoundItemIndex == (strSymbol.GetLength() - 1))
			{
				strNext.SetAt(strNext.GetLength() - iIndex - 1, strSymbol[0]);
				bChangePrevSymbol = TRUE;
			}
			else
				strNext.SetAt(strNext.GetLength() - iIndex - 1, strSymbol[iFoundItemIndex + 1]);
		}
		else
			strNext.SetAt(strNext.GetLength() - iIndex - 1, strSymbol[0]);

		if (!bChangePrevSymbol)
			break;
	}

	return strNext;
}