// GrayCode.cpp

#include "GrayCode.h"
#include "IO.h"
#include "Intervals.h"

GrayCode::GrayCode(){}
GrayCode::~GrayCode(){}

vector<bool> GrayCode::Base2ToGray(vector<bool> vBase2)	// XOR(vBase2[n-1], vBase2[n])
{
	vector<bool> vGray(vBase2.size(), false);

	for (uint n = 0; n < vBase2.size(); n++)
	{
		if (n == 0)
			vGray[0] = vBase2[0];
		else
		{
			if (vBase2[n - 1] != vBase2[n])	// XOR(vBase2[n-1], vBase2[n])
				vGray[n] = true;
			//else							// already false
			//	vGray[n] = false;				
		}
	}
	return vGray;
}

vector<bool> GrayCode::GrayToBase2(vector<bool> vGray)	// XOR(vBase2[n-1], vGray[n])
{
	vector<bool> vBase2(vGray.size(), false);

	for (uint n = 0; n < vGray.size(); n++)
	{
		if (n == 0)
			vBase2[0] = vGray[0];
		else
		{
			if (vBase2[n - 1] != vGray[n])	// XOR(vBase2[n-1], vGray[n])
				vBase2[n] = true;
			//else							// already false
			//	vBase2[n] = false;				
		}
	}
	return vBase2;
}

map<vector<bool>, vector<uint>> GrayCode::Base2ToGray(map<vector<bool>, vector<uint>> mBase2)
{
	map<vector<bool>, vector<uint>> mGray;
	map<vector<bool>, vector<uint>>::iterator i;
	for (i = mBase2.begin(); i != mBase2.end(); i++)
	{
		vector<bool> vBase2 = i->first;
		mGray.insert(make_pair(Base2ToGray(vBase2), i->second));
	}
	return mGray;
}

map<vector<bool>, vector<uint>> GrayCode::GrayToBase2(map<vector<bool>, vector<uint>> mGray)
{
	map<vector<bool>, vector<uint>> mBase2;
	map<vector<bool>, vector<uint>>::iterator i;
	for (i = mGray.begin(); i != mGray.end(); i++)
	{
		vector<bool> vGray = i->first;
		mBase2.insert(make_pair(GrayToBase2(vGray), i->second));
	}
	return mBase2;
}

uint GrayCode::AbsoluteValue(uint a, uint b)
{
	if (a < b)
		return b - a;
	return a - b;
}

uint GrayCode::AbsoluteValue(vector<uint> v1, vector<uint> v2)
{
	uint nAbsValue = 0;
	if (v1.size() == v2.size())
	{
		for (uint n = 0; n < v1.size(); n++)
		{
			nAbsValue += AbsoluteValue(v1[n], v2[n]);
		}
	}
	return nAbsValue;
}

uint GrayCode::RandomClass(uint nTotal)
{
	return (uint)rand() % nTotal;
}

vector<bool> GrayCode::RandomVector(uint nBits)
{
	//srand((unsigned)time(NULL));
	vector<bool> v(nBits, false);
	for (uint n = 0; n < nBits; n++)
	{
		if (rand() % 2 == 1)
			v[n] = true;
	}
	return v;
}

vector<bool> GrayCode::RandomVector(uint nSum, uint nBits)
{
	vector<bool> v(nBits, false);
	vector<bool> vError(nBits, false);
	uint nCount = nBits;
	if (nSum < nBits)
	{
		while (GraySum(v) < nSum)
		{
			uint nPos = rand() % nBits;
			v[nPos] = true;

			nCount++;
			if (nCount > nBits * 2)
			{
				cout << "\n***Error- GrayCode::RandomVector(uint nSum, uint nBits), nCount > nBits x 2***\n";
				return vError;
			}
		}
		return v;
	}
	cout << "\n***Error- GrayCode::RandomVector(uint nSum, uint nBits), nSum >= nBits***\n";
	return vError;
}

vector<bool> GrayCode::RandomKey(vector<uint>& vData, map<vector<bool>, vector<uint>> m)
{
	vData.clear();
	if(m.size() == 0)
		return vector<bool>();

	uint nStop = (uint)rand() % m.size();

	uint nCount = 0;
	map<vector<bool>, vector<uint>>::iterator i;
	for (i = m.begin(); i != m.end(); i++)
	{
		if (nCount == nStop)
		{
			vData = i->second;
			return i->first;
		}
		nCount++;
	}
	return vector<bool>();
}

vector<bool>  GrayCode::GetKey(uint nIndexPosition, uint nIndex, vector<uint>& vIndexClass, map<vector<bool>, vector<uint>> m)
{
	vIndexClass.clear();
	map<vector<bool> , vector<uint>>::iterator i;
	for (i = m.begin(); i != m.end(); i++)
	{
		vector<uint> vIC = i->second;
		if (nIndexPosition < vIC.size())
		{
			if (vIC[nIndexPosition] == nIndex)
			{
				vIndexClass = i->second;
				return i->first;
			}
		}
	}
	return vector<bool>();
}


bool GrayCode::CheckGrayCode(uint& nFail, map<uint, vector<uint>> m)
{
	nFail = 0;
	uint nCount = 0;
	vector<uint> vPrev;
	map<uint, vector<uint>>::iterator i;
	for (i = m.begin(); i != m.end(); i++)
	{
		vector<uint> vNext = i->second;
		if (i != m.begin())
		{
			if (AbsoluteValue(vNext, vPrev) != 1)
			{
				nFail = nCount;
				return false;
			}
		}
		nCount++;
		vPrev = vNext;
	}
	return true;
}

bool GrayCode::CheckGrayCode(uint& nFail, map<vector<bool>, vector<uint>> m)
{
	nFail = 0;
	uint nCount = 0;
	vector<uint> vPrev;
	map<vector<bool>, vector<uint>>::iterator i;
	for (i = m.begin(); i != m.end(); i++)
	{
		vector<uint> vNext = i->second;
		if (i != m.begin())
		{
			if (AbsoluteValue(vNext, vPrev) != 1)
			{
				nFail = nCount;
				return false;
			}
		}
		nCount++;
		vPrev = vNext;
	}
	return true;
}

uint GrayCode::GraySum(vector<bool> vGray)		// count the 1's
{
	uint nSum = 0;
	for (uint n = 0; n < vGray.size(); n++)
	{
		if (vGray[n])
			nSum++;
	}
	return nSum;
}

uint GrayCode::Base2Sum(vector<bool> vBase2)	// change to gray and count the 1's
{
	vector<bool> vGray = Base2ToGray(vBase2);
	return GraySum(vGray);
}

uint GrayCode::SumVector(vector<uint> v)
{
	uint nTotal = 0;
	for (uint n = 0; n < v.size(); n++)
	{
		nTotal += v[n];
	}
	return nTotal;
}

uint GrayCode::Base2MapMaxSum(uint& nMinSum, map<vector<bool>, vector<uint>> mBase2)
{
	uint nMaxSum = 0;
	nMinSum = 0;

	map<vector<bool>, vector<uint>>::iterator i;
	for (i = mBase2.begin(); i != mBase2.end(); i++)
	{
		uint nSum = Base2Sum(i->first);
		if (i == mBase2.begin())
		{
			nMaxSum = nSum;
			nMinSum = nSum;
		}
		else
		{
			if (nMaxSum < nSum)
				nMaxSum = nSum;

			if(nMinSum > nSum)
				nMinSum = nSum;
		}
	}
	return nMaxSum;
}

uint GrayCode::GrayMapMaxSum(uint& nMinSum, map<vector<bool>, vector<uint>> mGray)
{
	uint nMaxSum = 0;
	nMinSum = 0;

	map<vector<bool>, vector<uint>>::iterator i;
	for (i = mGray.begin(); i != mGray.end(); i++)
	{
		uint nSum = GraySum(i->first);
		if (i == mGray.begin())
		{
			nMaxSum = nSum;
			nMinSum = nSum;
		}
		else
		{
			if (nMaxSum < nSum)
				nMaxSum = nSum;

			if (nMinSum > nSum)
				nMinSum = nSum;
		}
	}
	return nMaxSum;
}

vector<uint> GrayCode::GraySums(vector<uint> vGrayStart, vector<uint> vGraySize, vector<bool> vGray)
{
	vector<uint> vGraySums(vGrayStart.size(), 0);

	if (vGrayStart.size() == vGraySize.size())
	{
		for (uint n = 0; n < vGrayStart.size(); n++)
		{
			uint nPos = vGrayStart[n];
			uint nSize = vGraySize[n];

			if (nPos + nSize <= (uint)vGray.size())
			{
				vector<bool> vGraySegment;
				vGraySegment.assign(vGray.begin() + nPos, vGray.begin() + nPos + nSize);
				vGraySums[n] = GraySum(vGraySegment);
			}
		}
	}
	return vGraySums;
}

vector<uint> GrayCode::Base2MapMaxSums(vector<uint>& vMinSums, vector<uint> vGrayStart, vector<uint> vGraySize, map<vector<bool>, vector<uint>> mBase2)
{
	vector<uint> vMaxSums(vGrayStart.size(), 0);
	vMinSums.assign(vGrayStart.size(), 0);

	if (vGrayStart.size() == vGraySize.size())
	{
		map<vector<bool>, vector<uint>>::iterator i;
		for (i = mBase2.begin(); i != mBase2.end(); i++)
		{
			vector<uint> vTemp = GraySums(vGrayStart, vGraySize, Base2ToGray(i->first));
			if (i == mBase2.begin())
			{
				vMaxSums = vTemp;
				vMinSums = vTemp;
			}
			else
			{
				for (uint n = 0; n < vGrayStart.size(); n++)
				{
					if (vMaxSums[n] < vTemp[n])
						vMaxSums[n] = vTemp[n];

					if (vMinSums[n] > vTemp[n])
						vMinSums[n] = vTemp[n];
				}
			}
		}
	}
	return vMaxSums;
}

vector<uint> GrayCode::GrayMapMaxSums(vector<uint>& vMinSums, vector<uint> vGrayStart, vector<uint> vGraySize, map<vector<bool>, vector<uint>> mGray)
{
	vector<uint> vMaxSums(vGrayStart.size(), 0);
	vMinSums.assign(vGrayStart.size(), 0);

	if (vGrayStart.size() == vGraySize.size())
	{
		map<vector<bool>, vector<uint>>::iterator i;
		for (i = mGray.begin(); i != mGray.end(); i++)
		{
			vector<uint> vTemp = GraySums(vGrayStart, vGraySize, i->first);
			if (i == mGray.begin())
			{
				vMaxSums = vTemp;
				vMinSums = vTemp;
			}
			else
			{
				for (uint n = 0; n < vGrayStart.size(); n++)
				{
					if (vMaxSums[n] < vTemp[n])
						vMaxSums[n] = vTemp[n];

					if (vMinSums[n] > vTemp[n])
						vMinSums[n] = vTemp[n];
				}
			}
		}
	}
	return vMaxSums;
}

vector<bool> GrayCode::IncrementBase2(vector<bool> vBase2)
{
	vector<bool> vError(vBase2.size(), false);
	if (vBase2.size() > 1)
	{
		for (uint n = 0; n < vBase2.size(); n++)
		{
			uint nPos = (uint)(vBase2.size() - 1 - n);

			if (vBase2[nPos] == false)
			{
				vBase2[nPos] = true;
				return vBase2;
			}
			else
			{
				vBase2[nPos] = false;
			}
		}
	}
	return vError;
}

vector<bool> GrayCode::DecrementBase2(vector<bool> vBase2)
{
	vector<bool> vError(vBase2.size());
	
	bool bAllZero = true;
	for (bool b : vBase2)	// Check if the input is all zeros
	{
		if (b) 
		{
			bAllZero = false;
			break;
		}
	}
	if (bAllZero)
	{
		return vError; // Return error vector if input is all zeros
	}
	
	for (size_t i = vBase2.size(); i-- > 0;)	// Process from LSB to MSB
	{
		if (vBase2[i])
		{
			vBase2[i] = false; // Flip rightmost 1 to 0
			return vBase2;
		}
		else 
		{
			vBase2[i] = true; // Flip 0 to 1
		}
	}
	return vBase2; // Fallback, though loop should return earlier
}


uint GrayCode::Base2ToBase10(vector<bool> vBase2)	// this is for examples only
{
	uint nBase10 = 0;
	uint nPowerOfTwo = 1;
	if (vBase2.size() < 32)
	{
		reverse(vBase2.begin(), vBase2.end());
		for (uint n = 0; n < vBase2.size(); n++)
		{
			if (vBase2[n])
			{
				nBase10 += nPowerOfTwo;
			}
			nPowerOfTwo *= 2;
		}
	}
	return nBase10;
}

uint GrayCode::ClassCount(uint nDefault, vector<uint> v)
{
	uint nCount = 0;
	for (uint n = 0; n < v.size(); n++)
	{
		if (v[n] != nDefault)
			nCount++;
	}
	return nCount;
}

uint GrayCode::ClassCount(bool bPrintSumsAndIndexes, uint nDefault, vector<uint> v)
{
	uint nCount = 0;
	uint nStart = 0;

	if(bPrintSumsAndIndexes)
		nStart = 22;

	for (uint n = nStart; n < v.size(); n++)
	{
		if (v[n] != nDefault)
			nCount++;
	}
	return nCount;
}

uint GrayCode::ClassCount(bool bPrintSumsAndIndexes, uint nDefault, uint nSize, vector<uint> v)
{
	uint nCount = 0;
	uint nStart = 0;
	uint nStop = nStart + nSize;

	if (bPrintSumsAndIndexes)
	{
		//nStart = 22;
		nStart = (nSize * 2) + 2;
		nStop = nStart + nSize;
	}

	for (uint n = nStart; n < nStop; n++)
	{
		if (v[n] != nDefault)
			nCount++;
	}
	return nCount;
}

bool GrayCode::InsertIntoCoordinates(vector<bool>& vCoordinates, uint nNthDimension, uint nDimensions, vector<bool> v)
{	// (x0, x1,...xn) ->  (x0,y0,z0,x1,y1,z1...xn,yn,zn)				// (x0, x1,...xn, y0, y1,...yn, z0, z1,...zn) ->  (x0,y0,z0,x1,y1,z1...xn,yn,zn)
	if (vCoordinates.size() >= v.size() * nDimensions)
	{
		for (uint nBit = 0; nBit < v.size(); nBit++)
		{
			uint nPos = (nBit * nDimensions) + nNthDimension;
			vCoordinates[nPos] = v[nBit];
		}
		return true;
	}
	else
		cout << "\n\n***error*** GrayCode::InsertIntoCoordinates: Coordinates Size != Bits * Dimensions " << vCoordinates.size() << " != " << v.size() << " * " << nDimensions << "\n\n";

	return false;
}

vector<bool> GrayCode::ExtractFromCoordinates(uint nNthDimension, uint nBitsPerDimension, uint nDimensions, vector<bool> vCoordinates)
{	//  (x0,y0,z0,x1,y1,z1...xn,yn,zn) -> (x0, x1,...xn)			//  (x0,y0,z0,x1,y1,z1...xn,yn,zn) -> (x0, x1,...xn, y0, y1,...yn, z0, z1,...zn)

	vector<bool> v(nBitsPerDimension, false);
	if (vCoordinates.size() == nBitsPerDimension * nDimensions)
	{
		for (uint nBit = 0; nBit < nBitsPerDimension; nBit++)
		{
			uint nPos = (nBit * nDimensions) + nNthDimension;
			v[nBit] = vCoordinates[nPos];
		}
	}
	else
		cout << "\nerror***ExtractFromCoordinates: Coordinates Size, Bits, Dimensions " << vCoordinates.size() << " != " << nBitsPerDimension << " * " << nDimensions << "\n";

	return v;
}

bool GrayCode::FlipsAndRotations(vector<bool> v, uint& nFlips, uint& nRotations)
{
	nFlips = 0;
	nRotations = 0;

	if (v.size() < 2)
		return false;

	uint nZeroCount = 0;
	reverse(v.begin(), v.end());
	for (uint n = 0; n < v.size() - 1; n++)
	{
		if (v[n])
		{
			nFlips = nZeroCount + 1;
			break;
		}
		nZeroCount++;
	}

	nRotations = (uint)v.size() - nFlips - 1;

	return true;
}

vector<bool> GrayCode::GrayToCoordinates2D(uint nBitsPerDimension, uint nDimensions, vector<bool> v)
{
	// 00	10	->	rotate right
	// 11	01	->	flip

	if (nDimensions == 2 && v.size() >= 4)
	{
		for (uint a = (uint)v.size() - 4; a >= 0; a -= 2)				// decreasing
		{
			if ((!v[a] && !v[a + 1]) || (v[a] && !v[a + 1]))			// 00	10		// switch or rotate
			{
				for (uint b = a + 2; b < v.size(); b += 2)
				{
					bool t = v[b];
					v[b] = v[b + 1];
					v[b + 1] = t;
				}
			}
			else if ((v[a] && v[a + 1]) || (!v[a] && v[a + 1]))			// 11	01		// flip
			{
				uint b = a + 2;
				v[b].flip();
				v[b + 1].flip();
			}

			if (a == 0)
			{
				break;
			}
		}
	}
	return v;
}

vector<bool> GrayCode::CoordinatesToGray2D(uint nBitsPerDimension, uint nDimensions, vector<bool> v)
{
	// 00	10		// switch
	// 11	01		// flip

	if (nDimensions == 2 && v.size() >= 4)
	{
		for (uint a = 0; a + 2 < v.size(); a += 2)						// left to right
		{
			if ((!v[a] && !v[a + 1]) || (v[a] && !v[a + 1]))			// 00	10		// switch
			{
				for (uint b = a + 2; b < v.size(); b += 2)
				{
					bool t = v[b];
					v[b] = v[b + 1];
					v[b + 1] = t;
				}
			}
			else if ((v[a] && v[a + 1]) || (!v[a] && v[a + 1]))			// 01	11		// flip
			{
				uint b = a + 2;
				v[b].flip();
				v[b + 1].flip();
			}
		}
	}
	return v;
}

vector<bool> GrayCode::GrayCodeToGrayCoordinates(uint nBitsPerDimension, uint nDimensions, vector<bool> v)
{
	uint nFlips = 0;
	uint nRotations = 0;
	vector<bool> vError(v.size(), false);

	if (v.size() != nBitsPerDimension * nDimensions)
	{
		cout << "\n\n***error*** GrayCode::GrayCodeToGrayCoordinates: Size != Bits * Dimensions " << v.size() << " != " << nBitsPerDimension << " * " << nDimensions << "\n\n";
		return vError;
	}
	if (nDimensions == 1)
	{
		return v;
	}
	if (nDimensions == 2)
	{
		return GrayToCoordinates2D(nBitsPerDimension, nDimensions, v);
	}

	uint nStart = (uint)v.size() - nDimensions;
	for (uint nBit = 1; nBit < nBitsPerDimension; nBit++)
	{
		nStart -= nDimensions;

		vector<bool> vInput;
		vInput.assign(v.begin() + nStart, v.begin() + nStart + nDimensions);
		FlipsAndRotations(vInput, nFlips, nRotations);

		if (nFlips > 0)
		{
			v[nStart + nDimensions].flip();
			v[nStart + nDimensions + nFlips].flip();
		}
		if (nRotations > 0)
		{
			uint nInputs = nBitsPerDimension - 1;
			uint nStartCount = (uint)(nStart / nDimensions);
			if (nInputs <= nStartCount)
			{
				return vError;
			}
			uint nMaxRotations = nInputs - nStartCount;

			uint nLength = 0;
			for (uint r = 0; r < nMaxRotations; r++)
			{
				rotate(v.rbegin() + nLength, v.rbegin() + nLength + nRotations, v.rbegin() + nLength + nDimensions);
				nLength += nDimensions;
			}
		}
	}
	return v;
}

vector<bool> GrayCode::GrayCoordinatesToGrayCode(uint nBitsPerDimension, uint nDimensions, vector<bool> v)
{

	uint nFlips = 0;
	uint nRotations = 0;
	vector<bool> vError(v.size(), false);

	if (v.size() != nBitsPerDimension * nDimensions)
	{
		cout << "\n\n***error*** GrayCodeND::GrayCoordinatesToGrayCode: Size != Bits * Dimensions " << v.size() << " != " << nBitsPerDimension << " * " << nDimensions << "\n\n";
		return vError;
	}
	if (nDimensions == 1)
	{
		return v;
	}
	if (nDimensions == 2)
	{
		return CoordinatesToGray2D(nBitsPerDimension, nDimensions, v);
	}

	uint nStart = 0;
	for (uint nBit = 1; nBit < nBitsPerDimension; nBit++)
	{
		vector<bool> vInput;
		vInput.assign(v.begin() + nStart, v.begin() + nStart + nDimensions);
		FlipsAndRotations(vInput, nFlips, nRotations);

		if (nRotations > 0)
		{
			uint nInputs = nBitsPerDimension - 1;
			uint nStartCount = (uint)(nStart / nDimensions);
			if (nInputs <= nStartCount)
			{
				return vError;
			}
			uint nMaxRotations = nInputs - nStartCount;

			uint nLength = nDimensions + (nStartCount * nDimensions);
			for (uint r = 0; r < nMaxRotations; r++)
			{
				rotate(v.begin() + nLength, v.begin() + nLength + nRotations, v.begin() + nLength + nDimensions);
				nLength += nDimensions;
			}
		}
		if (nFlips > 0)
		{
			v[nStart + nDimensions].flip();
			v[nStart + nDimensions + nFlips].flip();
		}
		nStart += nDimensions;
	}
	//s = ss.str();
	return v;
}


vector<uint> GrayCode::GrayCoordinatesToBase10Coordinates(uint nBitsPerDimension, uint nDimensions, vector<bool> vGrayCoordinates)
{
	vector<uint> vBase10(nDimensions, 0);
	for (uint n = 0; n < nDimensions; n++)
	{
		vector<bool> vGray = ExtractFromCoordinates(n, nBitsPerDimension, nDimensions, vGrayCoordinates);
		vector<bool> vBase2 = GrayToBase2(vGray);
		vBase10[n] = Base2ToBase10(vBase2);
	}
	return vBase10;
}

vector<bool> GrayCode::IncrementBase2SameGraySumSlowly(bool& bOK, vector<bool> vBase2)	// step by step for debugging
{
	bOK = false;

	uint nBits = (uint)vBase2.size();
	vector<bool> vZero(nBits, false);
	vector<bool> vStop(nBits, true);

	uint nInitialSum = Base2Sum(vBase2);

	if(GraySum(vBase2) == vBase2.size())
		return vZero;

	vector<bool> vStart = IncrementBase2(vBase2);
	for (vector<bool> v = vStart; v <= vStop; v = IncrementBase2(v))
	{
		uint nSum = Base2Sum(v);
		if (nSum == nInitialSum)
		{
			bOK = true;
			return v;
		}

		if (vBase2 == vStop)
			break;
	}
	return vZero;
}

vector<bool> GrayCode::DecrementBase2SameGraySumSlowly(bool& bOK, vector<bool> vBase2)		// step by step for debugging
{
	bOK = false;

	uint nBits = (uint)vBase2.size();
	vector<bool> vZero(nBits, false);
	vector<bool> vStop(nBits, true);

	uint nInitialSum = Base2Sum(vBase2);
	if(nInitialSum == 0)
		return vZero;

	for (vector<bool> v = DecrementBase2(vBase2); v >= vZero; v = DecrementBase2(v))
	{
		uint nSum = Base2Sum(v);
		if (nSum == nInitialSum)
		{
			bOK = true;
			return v;
		}

		if (v == vZero)
			break;
	}
	return vZero;
}

vector<uint> GrayCode::GetCounts(uint nCountsSize, vector<bool> v)	// v is gray or base2 which ever works best	// counts are reversed - right to left
{	// this is counting consecutive 0's and 1's for the increments below
	reverse(v.begin(), v.end());
	vector<uint> vCounts(nCountsSize, 0);

	bool bPrevious = false;
	uint nPos = 0;
	for (uint n = 0; n < v.size(); n++)
	{
		if (n == 0)
		{
			if (v[n])
			{
				nPos++;
				if (nPos == nCountsSize)
				{
					break;
				}
				bPrevious = true;
			}
			else
			{
				bPrevious = false;
			}
			vCounts[nPos]++;
		}
		else
		{
			if (v[n] != bPrevious)
			{
				nPos++;
				if (nPos == nCountsSize)
				{
					break;
				}
				bPrevious = v[n];

			}
			vCounts[nPos]++;
		}
	}
	return vCounts;
}

vector<uint> GrayCode::GrayIntervalCounts(bool& bInitial, vector<bool> vGray)
{
	bInitial = false;
	bool bOne = false;
	uint nTempCount = 0;
	vector<uint> vIntervalCounts;
	for (uint n = 0; n < vGray.size(); n++)
	{
		if (n == 0)
		{
			nTempCount = 1;
			if (vGray[0])
			{
				bOne = true;
				bInitial = true;
			}
			//else
			//{
			//	bOne = false;		// already the case
			//	bInitial = false;	// already the case
			//}
		}
		else if (bOne && vGray[n])
		{
			nTempCount++;
		}
		else if (bOne && !vGray[n])
		{
			bOne = false;
			vIntervalCounts.push_back(nTempCount);
			nTempCount = 1;
		}
		else if (!bOne && vGray[n])
		{
			bOne = true;
			vIntervalCounts.push_back(nTempCount);
			nTempCount = 1;
		}
		else if (!bOne && !vGray[n])
		{
			nTempCount++;
		}
	}
	vIntervalCounts.push_back(nTempCount);
	return vIntervalCounts;
}

map<vector<uint>, vector<uint>> GrayCode::GrayIntervalCounts(map<vector<bool>, vector<uint>> mGray)
{
	map<vector<uint>, vector<uint>> mIntervalCounts;
	map<vector<bool>, vector<uint>>::iterator i;
	for (i = mGray.begin(); i != mGray.end(); i++)
	{
		bool bInitial = false;
		vector<uint> vIntervalCounts = GrayIntervalCounts(bInitial, i->first);
		mIntervalCounts.insert(make_pair(vIntervalCounts, i->second));
	}
	return mIntervalCounts;
}

vector<uint> GrayCode::GenerateGrayStart(vector<uint> vIntervalCounts)
{
	uint nTotal = 0;
	vector<uint> vGrayStart(vIntervalCounts.size(), 0);
	for (uint n = 0; n < vIntervalCounts.size(); n++)
	{
		vGrayStart[n] = nTotal;
		nTotal += vIntervalCounts[n];
	}
	return vGrayStart;
}

vector<bool> GrayCode::IncrementBase2SameGraySum(bool& bOK, vector<bool> vBase2)
{
	uint nReturn = 0;
	uint nCountsSize = 6;		// ok, does not need to be larger
	vector<uint> vCountsBase2;
	vector<uint> vCountsGray;
	return IncrementBase2SameGraySum(bOK, nReturn, nCountsSize, vCountsBase2, vCountsGray, vBase2);
}

vector<bool> GrayCode::IncrementBase2SameGraySum(bool& bOK, uint& nReturn, uint nCountsSize, vector<uint>& vBase2Counts, vector<uint>& vGrayCounts, vector<bool> vBase2)
{
	bOK = false;
	bool bReturnBase2 = false;
	nReturn = 0;
	vector<bool> vGray = Base2ToGray(vBase2);
	vector<bool> vError(vBase2.size(), false);

	if (vBase2.size() < 2 || vBase2.size() < nCountsSize)
	{
		return IncrementBase2SameGraySumSlowly(bOK, vBase2);
	}

	vBase2Counts = GetCounts(nCountsSize, vBase2);	// reversed
	vGrayCounts = GetCounts(nCountsSize, vGray);	// reversed

	vector<bool> vIncrementBase2 = vBase2;
	reverse(vIncrementBase2.begin(), vIncrementBase2.end());

	vector<bool> vIncrementGray = vGray;
	reverse(vIncrementGray.begin(), vIncrementGray.end());

	if (GraySum(vGray) == 0 || GraySum(vGray) == vBase2.size() || GraySum(vBase2) == vBase2.size())						//	0 0 0 ...
	{
		bOK = false;
		bReturnBase2 = true;
		nReturn = 0;
	}
	else if (vGrayCounts[0] == 0 && vGrayCounts[1] + vGrayCounts[2] == vBase2.size() - 1 && vGrayCounts[4] == 0)		//	 0	vBase2.size()-1	0	(vGrayCounts)
	{
		bOK = false;
		bReturnBase2 = true;
		nReturn = 0;	//
	}
	else if (vBase2Counts[0] == 0 && vBase2Counts[1] > 0 && vBase2Counts[2] > 1)											// 0	x	y (vBase2Counts)
	{
		vIncrementBase2[vBase2Counts[1]].flip();

		bOK = true;
		bReturnBase2 = true;
		nReturn = 1010;	// ok
	}
	else if (vBase2Counts[0] == 0 && vBase2Counts[1] == 1 && vBase2Counts[2] == 1 && vBase2Counts[3] > 0 && vBase2Counts[4] > 1)	// 0	1	1	x	y (vBase2Counts)
	{
		vIncrementGray[1].flip();
		vIncrementGray[vBase2Counts[3] + 2].flip();			// (vIncrementGray[vBase2Counts])

		bOK = true;
		bReturnBase2 = false;
		nReturn = 1020;	// ok
	}
	else if (vBase2Counts[0] == 0 && vBase2Counts[1] > 1 && vBase2Counts[2] == 1 && vBase2Counts[3] > 0)								// 0	x	1	y	(vBase2Counts)
	{
		vIncrementGray[0].flip();
		vIncrementGray[vBase2Counts[1]].flip();		// (vIncrementGray[vBase2Counts])

		bOK = true;
		bReturnBase2 = false;
		nReturn = 1030;	// ok
	}
	else if (vBase2Counts[0] == 0 && vBase2Counts[1] == 1 && vGrayCounts[1] > 1 && vGrayCounts[1] % 2 == 1)					// 0	1 (vBase2Counts)	x	%2=1 (vGrayCounts)
	{
		vIncrementBase2[vGrayCounts[1] - 1].flip();
		vIncrementBase2[vGrayCounts[1]].flip();

		bOK = true;
		bReturnBase2 = true;
		nReturn = 1040;	// ok = 4	***
	}
	else if (vBase2Counts[0] == 0 && vBase2Counts[1] == 1 && vBase2Counts[2] == 1 && vBase2Counts[3] > 1 && vBase2Counts[4] == 1 && vBase2Counts[5] > 0)					// 0	1	1	x	1	y	(vBase2Counts)
	{
		vIncrementGray[2].flip();
		vIncrementGray[vBase2Counts[3] + 2].flip();		// (vIncrementGray[vBase2Counts])

		bOK = true;
		bReturnBase2 = false;
		nReturn = 1050;	// ok = 7
	}
	else if (vBase2Counts[0] == 0 && vBase2Counts[1] == 1 && vBase2Counts[2] == 1 && vBase2Counts[3] > 1 && vBase2Counts[4] == 1)		// 0	1	1	x	1	(vBase2Counts)
	{
		vIncrementGray[1].flip();
		vIncrementGray[vGrayCounts[1] + vGrayCounts[2] + vGrayCounts[3]].flip();

		bOK = true;
		nReturn = 1051;	// ok = 1	***
	}
	else if (vBase2Counts[0] == 0 && vBase2Counts[1] == 1 && vGrayCounts[1] > 1 && vGrayCounts[2] == 1 && vGrayCounts[3] == 1)					// 0	1 (vBase2Counts)	x	1	1 (vGrayCounts)
	{
		vIncrementGray[vGrayCounts[1] - 1].flip();
		vIncrementGray[vGrayCounts[1] + 2].flip();		// (vIncrementGray[vGrayCounts])

		bOK = true;
		bReturnBase2 = false;
		nReturn = 1060;	// ok = 3	***
	}
	else if (vBase2Counts[0] == 0 && vBase2Counts[1] == 1 && vGrayCounts[1] > 3 && vGrayCounts[2] > 1 && vGrayCounts[3] == 1)	// 0	1 (vBase2Counts) >3	 >1	 z	(vGrayCounts)
	{
		vIncrementGray[vGrayCounts[1] - 1].flip();
		vIncrementGray[vGrayCounts[1] + vGrayCounts[2] + 1].flip();		// (vIncrementGray[vGrayCounts])

		bOK = true;
		bReturnBase2 = false;
		nReturn = 1070;	// ok = 1
	}
	else if (vBase2Counts[0] == 0 && vBase2Counts[1] == 1 && vGrayCounts[1] > 1 && vGrayCounts[2] == 1)					// 0	1 (vBase2Counts)	x	1	(vGrayCounts)
	{
		vIncrementGray[vGrayCounts[1]].flip();
		vIncrementGray[vGrayCounts[1] + 2].flip();											// (vIncrementGray[vGrayCounts])

		bOK = true;
		bReturnBase2 = false;
		nReturn = 1080;	// ok = 2	***
	}
	else if (vBase2Counts[0] == 0 && vBase2Counts[1] == 1 && vGrayCounts[1] > 2 && vGrayCounts[2] > 1 && vGrayCounts[3] > 1)					// 0	1(vBase2Counts)	0	>2	>0	> 1 (vGrayCounts)
	{
		vIncrementGray[vGrayCounts[1]].flip();
		vIncrementGray[vGrayCounts[1] + vGrayCounts[2] + 1].flip();

		bOK = true;
		bReturnBase2 = false;
		nReturn = 1090;	// ok = 1	***
	}
	else if (vBase2Counts[0] == 0 && vBase2Counts[1] > 1 && vBase2Counts[2] == 1 && vBase2Counts[3] == 0)					//	0	x	1	0	(vBase2Counts)
	{
		vIncrementGray[vGrayCounts[0]].flip();
		vIncrementGray[vGrayCounts[0] + 1].flip();					// (vIncrementGray[vGrayCounts])

		bOK = true;
		bReturnBase2 = false;
		nReturn = 1100;	// ok - 1	***
	}
	else if (vBase2Counts[0] == 1 && vGrayCounts[1] > 1 && vGrayCounts[1] % 2 == 0)								// 1(vBase2Counts)	x	y (vGrayCounts)
	{
		vIncrementGray[vGrayCounts[1] - 2].flip();		// (vIncrementGray[vGrayCounts])
		vIncrementGray[vGrayCounts[1]].flip();

		bOK = true;
		bReturnBase2 = false;
		nReturn = 2010;	// ok
	}
	else if (vBase2Counts[0] == 1 && vGrayCounts[1] > 1 && vGrayCounts[3] > 1)								// 1(vBase2Counts) x	y (vGrayCounts)
	{
		vIncrementGray[vGrayCounts[1]].flip();
		vIncrementGray[vGrayCounts[1] + vGrayCounts[2] + 1].flip();	// (vIncrementGray[vGrayCounts])

		bOK = true;
		bReturnBase2 = false;
		nReturn = 2011;	// ok 
	}
	else if (vBase2Counts[0] == 1 && vGrayCounts[1] > 1 && vGrayCounts[2] > 0)								// 1(vBase2Counts) x	y (vGrayCounts)
	{
		vIncrementGray[vGrayCounts[1] - 1].flip();
		vIncrementGray[vGrayCounts[1] + vGrayCounts[2] + 1].flip();			// (vIncrementGray[vGrayCounts])

		bOK = true;
		bReturnBase2 = false;
		nReturn = 2012;	// ok = 4
	}
	else if (vBase2Counts[0] == 1 && vBase2Counts[1] > 1 && vBase2Counts[2] == 1 && vBase2Counts[3] > 0)	// 1	x	1	y		// vBase2Counts
	{
		vIncrementGray[1].flip();
		vIncrementGray[vBase2Counts[1] + 1].flip();		// (vIncrementGray[vBase2Counts])

		bOK = true;
		bReturnBase2 = false;
		nReturn = 2013;	// ok = 15
	}
	else if (vBase2Counts[0] == 1 && vBase2Counts[1] > 1 && vBase2Counts[2] > 0)								// 1	x	y		// vBase2Counts
	{
		vIncrementGray[0].flip();
		vIncrementGray[vBase2Counts[0] + vBase2Counts[1]].flip();

		bOK = true;
		bReturnBase2 = false;
		nReturn = 2014;	// ok = 16
	}
	else if (vBase2Counts[0] > 0 && vBase2Counts[1] == 1 && vBase2Counts[2] > 1)											// x	1	y (vBase2Counts)
	{
		vIncrementBase2[vBase2Counts[0] - 1].flip();		// (vIncrementBase2[vBase2Counts])

		bOK = true;
		bReturnBase2 = true;
		nReturn = 2020;	// ok
	}
	else if (vBase2Counts[0] == 1 && vBase2Counts[1] > 1 && vBase2Counts[2] > 1)							// 1	x	y (vBase2Counts)
	{
		vIncrementGray[0].flip();
		vIncrementGray[vBase2Counts[1] + 1].flip();			// (vIncrementGray[vBase2Counts])

		bOK = true;
		bReturnBase2 = false;
		nReturn = 2030;	// ok
	}
	else if (vBase2Counts[0] > 1 && vBase2Counts[1] > 0)								// x	1	y	(vBase2Counts)
	{
		vIncrementBase2[vBase2Counts[0] - 1].flip();		// (vIncrementBase2[vBase2Counts])

		bOK = true;
		bReturnBase2 = true;
		nReturn = 2040;	// ok = 26
	}

	reverse(vIncrementGray.begin(), vIncrementGray.end());

	if (bOK && nReturn > 0)
	{
		if (bReturnBase2)
		{
			reverse(vIncrementBase2.begin(), vIncrementBase2.end());
			return vIncrementBase2;
		}
		else
		{
			return GrayToBase2(vIncrementGray);
		}
	}
	bOK = false;
	return vError;
}

vector<bool> GrayCode::IncrementBase2SameGraySum(uint nBitsPerSegmentGray, vector<uint> vPrefixSegmentsBase10, bool& bOK, uint& nReturn, vector<bool> vBase2)
{
	bOK = false;
	nReturn = 0;
	vector<uint> vCountsBase2;
	vector<uint> vCountsGray;

	uint nSegments = (uint)vPrefixSegmentsBase10.size();
	if (nSegments * nBitsPerSegmentGray != (uint)vBase2.size())
		return vBase2;


	vector<bool> vGrayIncrement;
	vector<bool> vGray = Base2ToGray(vBase2);

	uint nStart = 0;
	for (uint n = 0; n < nSegments; n++)
	{
		vector<bool> vGrayTemp;
		vGrayTemp.assign(vGray.begin() + nStart, vGray.begin() + nStart + nBitsPerSegmentGray);
		vector<bool> vBase2Temp = GrayToBase2(vGrayTemp);

		vector<bool> vBase2TempIncrement = IncrementBase2SameGraySum(bOK, vBase2Temp);
		if (!bOK)
			return vBase2;

		vector<bool> vGrayTempIncrement = Base2ToGray(vBase2TempIncrement);
		vGrayIncrement.insert(vGrayIncrement.end(), vGrayTempIncrement.begin(), vGrayTempIncrement.end());
	}
	vector<bool> vBase2Increment = GrayToBase2(vGrayIncrement);

	return vBase2Increment;
}

vector<bool> GrayCode::IncrementBase2IncrementGraySum(bool& bOK, vector<bool> vBase2)	// increment Base2 (minimized), increment Gray Sum by one
{
	bOK = false;
	if (GraySum(vBase2) == 0 || GraySum(vBase2) == vBase2.size())	// cannot increment all 0's or all 1's
		return vBase2;

	vector<bool> vIncrement = vBase2;	// v is Base2 not Gray, this takes v as Base2 which has a gray sum, increments the Base2 such that the gray sum of the Base2 is incremented and the Base2 increase is minimized
	for (uint n = 0; n < vBase2.size(); n++)
	{
		vector<bool> vNext = IncrementBase2(vIncrement);

		if (vNext <= vIncrement)								// cannot increment
		{
			return vBase2;
		}

		if (Base2Sum(vNext) == Base2Sum(vBase2) + 1)		// both done - ok
		{
			bOK = true;
			return vNext;
		}

		bool bOK2 = false;
		uint nReturn = 0;
		uint nCountsSize = 6;
		vector<uint> vCountsBase2;
		vector<uint> vCountsGray;
		vIncrement = IncrementBase2SameGraySum(bOK2, nReturn, nCountsSize, vCountsBase2, vCountsGray, vIncrement);

		if (!bOK2)												// cannot increment
		{
			return vBase2;
		}
	}
	return vBase2;
}

vector<bool> GrayCode::IncrementBase2IncrementGraySum(bool& bOK, vector<uint> vGrayStart, vector<uint> vGraySize, vector<uint> vTargetSums, vector<bool> vBase2)
{
	bOK = true;
	vector<bool> vReturnGray(vBase2.size(), false);
	vector<bool> vReturnBase2 = vBase2;
	if (vGrayStart.size() == vGraySize.size() &&vGrayStart.size() == vTargetSums.size())
	{
		vector<bool> vGray = Base2ToGray(vBase2);
		for (uint n = 0; n < vGrayStart.size(); n++)
		{
			vector<bool> vTempGray;
			if (vGrayStart[n] + vGraySize[n] <= vGray.size())
			{
				vTempGray.assign(vGray.begin() + vGrayStart[n], vGray.begin() + vGrayStart[n] + vGraySize[n]);

				vector<bool> vTempBase2 = GrayToBase2(vTempGray);

				uint nReturn = 0;
				vTempBase2 = IncrementBase2IncrementGraySumToTarget(nReturn, vTargetSums[n], vTempBase2);

				for (uint a = 0; a < vGraySize[n]; a++)
				{
					uint nPos = vGrayStart[n] + a;
					vReturnBase2[nPos] = vTempBase2[nPos];
				}
			}
		}
	}
	return vReturnBase2;
}

vector<bool> GrayCode::IncrementBase2IncrementGraySumToTarget(uint& nReturn, uint nGraySumTarget, vector<bool> vBase2)	// or Decrement - change the name
{
	nReturn = 2;
	if (Base2Sum(vBase2) < nGraySumTarget)
	{
		uint nStop = nGraySumTarget - Base2Sum(vBase2);
		for (uint n = 0; n < nStop; n++)
		{
			bool bOK = false;
			vBase2 = IncrementBase2IncrementGraySum(bOK, vBase2);

			if (!bOK)
			{
				nReturn = 1;
				break;
			}
			if (Base2Sum(vBase2) == nGraySumTarget)
			{
				nReturn = 0;
				break;
			}
		}
	}
	else if (Base2Sum(vBase2) > nGraySumTarget)
	{
		uint nStop = Base2Sum(vBase2) - nGraySumTarget;
		for (uint n = 0; n < nStop; n++)
		{
			bool bOK = false;
			vBase2 = DecrementBase2DecrementSum(bOK, vBase2);

			if (!bOK)
			{
				nReturn = 1;
				break;
			}
			if (Base2Sum(vBase2) == nGraySumTarget)
			{
				nReturn = 0;
				break;
			}
		}
	}
	return vBase2;
}

vector<bool> GrayCode::DecrementBase2DecrementSum(bool& bOK, vector<bool> vBase2)	// decrement bool (minimized), decrement gray zero sim by one	// see SimZero.xls
{
	bOK = false;

	if (Base2Sum(vBase2) < 2)	// cannot decrement
		return vBase2;

	vector<bool> vDecrement = vBase2;	// vBase2 not gray, this takes v as bool which has a gray sim, decrements the base2 such that the gray sum of the bool is decremented and the bool decrease is minimized
	for (uint n = 0; n < vBase2.size(); n++)
	{
		vector<bool> vNext = DecrementBase2(vDecrement);
		if (vNext == vDecrement)
		{
			bOK = false;
			return vBase2;
		}

		if (Base2Sum(vNext) + 1 == Base2Sum(vBase2))
		{
			bOK = true;
			return vNext;
		}

		vDecrement = DecrementBase2(vDecrement);
		if (!bOK)
		{
			return vBase2;
		}
		else
		{
			bOK = false;
		}
	}
	return vBase2;
}

vector<bool> GrayCode::DecrementBase2SameGraySum(bool& bOK, vector<bool> vBase2)
{
	uint nReturn = 0;
	uint nCountsSize = 6;
	vector<uint> vBase2Counts;
	vector<uint> vGrayCounts;

	return DecrementBase2SameGraySum(bOK, nReturn, nCountsSize, vBase2Counts, vGrayCounts, vBase2);
}

vector<bool> GrayCode::DecrementBase2SameGraySum(bool& bOK, uint& nReturn, uint nCountsSize, vector<uint>& vBase2Counts, vector<uint>& vGrayCounts, vector<bool> vBase2)
{
	bOK = false;
	bool bReturnBase2 = false;
	nReturn = 0;
	vector<bool> vGray = Base2ToGray(vBase2);
	vector<bool> vZeros(vBase2.size(), false);

	if (vBase2.size() < 2 || vBase2.size() < nCountsSize)
	{
		return DecrementBase2SameGraySumSlowly(bOK, vBase2);
	}

	vBase2Counts = GetCounts(nCountsSize, vBase2);	// reversed
	vGrayCounts = GetCounts(nCountsSize, vGray);	// reversed

	vector<bool> vDecrementBase2 = vBase2;
	reverse(vDecrementBase2.begin(), vDecrementBase2.end());

	vector<bool> vDecrementGray = vGray;
	reverse(vDecrementGray.begin(), vDecrementGray.end());

	//if (GraySum(vGray) == 0 || GraySum(vGray) == vBase2.size() || GraySum(vBase2) == vBase2.size())						//	0 0 0 ...
	if (GraySum(vBase2) == 0)						//	0 0 0 ...
	{
		bOK = false;
		bReturnBase2 = true;
		nReturn = 0;
	}
	else if (vGrayCounts[0] == 0 && vGrayCounts[1] > 0 && vGrayCounts[2] > 0 && vGrayCounts[3] == 0 && vGrayCounts[4] == 0)		//	 0 x y 0 0 ...	(vGrayCounts)
	{
		bOK = false;
		bReturnBase2 = true;
		nReturn = 1000;	//
	}
	//else if (vBase2Counts[0] == 0 && vBase2Counts[1] > 0 && vBase2Counts[2] > 1)											// 0	x	y (vBase2Counts)
	else if (vBase2Counts[0] == 0 && vBase2Counts[1] > 0 && vBase2Counts[2] > 0 && vBase2Counts[3] == 0)					// 0	x	y	0	(vBase2Counts)
	{
		//vDecrementBase2[vBase2Counts[1]].flip();
		vDecrementBase2[vBase2Counts[1] - 1].flip();

		bOK = true;
		bReturnBase2 = true;
		nReturn = 1010;	// ok

		//	3	1			 || 000000000011		000000000010		0 2 10 0 0 0	1 1 10 0 0 0
		//	3	1	1		 || 000000000001		000000000001		0 1 11 0 0 0	0 1 11 0 0 0
		//	3	1	1	1010 || 000000000001		000000000001		0 1 11 0 0 0	0 1 11 0 0 0 || 4 + 0 = 4	ok

		//	7	1			 || 000000000111		000000000100		0 3 9 0 0 0		2 1 9 0 0 0
		//	7	1	1		 || 000000000011		000000000010		0 2 10 0 0 0	1 1 10 0 0 0
		//	7	1	1	1010 || 000000000011		000000000010		0 2 10 0 0 0	1 1 10 0 0 0 || 8 + 0 = 8	ok
	}
	else if (vBase2Counts[0] == 0 && vBase2Counts[1] == 1 && vBase2Counts[2] > 1 && vBase2Counts[3] == 1)					// 0	1	x	1	(vBase2Counts)
	{
		//vDecrementBase2[vBase2Counts[1] + vBase2Counts[2]].flip();
		//vDecrementBase2[vBase2Counts[2]].flip();
		vDecrementGray[vGrayCounts[2] + 2].flip();
		vDecrementGray[1].flip();

		bOK = true;
		bReturnBase2 = false;
		nReturn = 1011;

		//	9	3	 			||	000000001001	2 3		000000001101	1 3		0 1 2 1 8 0		0 1 1 2 8 0
		//	9	3	1			||	000000000101			000000000111			0 1 1 1 9 0		0 3 9 0 0 0
		//	9	3	1	1011	||	000000000101			000000000111			0 1 1 1 9 0		0 3 9 0 0 0	||	10 + 0 = 10	ok

		//	17	3	 			||	000000010001	2 3 4	000000011001	1 4		0 1 3 1 7 0		0 1 2 2 7 0
		//	17	3	1			||	000000001101			000000001011			0 1 1 2 8 0		0 2 1 1 8 0
		//	17	3	1	1011	||	000000001101			000000001011			0 1 1 2 8 0		0 2 1 1 8 0	||	18 + 0 = 18	ok

		//	41	5	 			||	000000101001	2 3		000000111101	1 3		0 1 2 1 1 1		0 1 1 4 6 0
		//	41	5	1			||	000000100101			000000110111			0 1 1 1 2 1		0 3 1 2 6 0
		//	41	5	1	1011	||	000000100101			000000110111			0 1 1 1 2 1		0 3 1 2 6 0	||	42 + 0 = 42	ok

		//	90	6	 			||	000001011010	2 3		000001110111	1 3		1 1 1 2 1 1		0 3 1 3 5 0
		//	90	6	1			||	000001010110			000001111101			1 2 1 1 1 1		0 1 1 5 5 0
		//	90	6	1	1020	||	000001101010			000001011111			1 1 1 1 1 2		0 5 1 1 5 0	||	90 + 1 = 91	error

	}
	else if (vBase2Counts[0] == 0 && vBase2Counts[1] == 1 && vBase2Counts[2] > 1 && vBase2Counts[3] > 1)					// 0	1	x	y	(vBase2Counts)
	{
		vDecrementGray[0].flip();
		vDecrementGray[vBase2Counts[2] + 1].flip();		// note vDecrementGray[vBase2Counts] here

		bOK = true;
		bReturnBase2 = false;
		nReturn = 1012;

		//	25	3	 			||	000000011001	1 2 3	000000010101	0 3		0 1 2 2 7 0		0 1 1 1 1 1
		//	25	3	1			||	000000010111			000000011100			0 3 1 1 7 0		2 3 7 0 0 0
		//	25	3	1	1012	||	000000010111			000000011100			0 3 1 1 7 0		2 3 7 0 0 0	||	26 + 0 = 26	ok

		//	49	3	 			||	000000110001	1 2 3 4	000000101001	0 4		0 1 3 2 6 0		0 1 2 1 1 1
		//	49	3	1			||	000000101111			000000111000			0 4 1 1 6 0		3 3 6 0 0 0
		//	49	3	1	1012	||	000000101111			000000111000			0 4 1 1 6 0		3 3 6 0 0 0	||	50 + 0 = 50	ok
	}
	else if (vBase2Counts[0] == 0 && vBase2Counts[1] > 1 && vBase2Counts[2] == 1)					// 0	x	1	(vBase2Counts)
	{
		vDecrementBase2[vBase2Counts[1] - 1].flip();

		bOK = true;
		bReturnBase2 = true;
		nReturn = 1013;

		//	11	3	 			||	000000001011		000000001110		0 2 1 1 8 0		1 3 8 0 0 0
		//	11	3	1			||	000000001001		000000001101		0 1 2 1 8 0		0 1 1 2 8 0
		//	11	3	1	1012	||	000000001001		000000001101		0 1 2 1 8 0		0 1 1 2 8 0	||	12 + 0 = 12	ok

		//	23	3	 			||	000000010111		000000011100		0 3 1 1 7 0		2 3 7 0 0 0
		//	23	3	1			||	000000010011		000000011010		0 2 2 1 7 0		1 1 1 2 7 0
		//	23	3	1	1012	||	000000010011		000000011010		0 2 2 1 7 0		1 1 1 2 7 0	||	24 + 0 = 24	ok

	}
	else if (vBase2Counts[0] == 0 && vGrayCounts[0] == 0 && vGrayCounts[1] > 1 && vGrayCounts[1] % 2 == 1 && vGrayCounts[2] == 1 && vGrayCounts[3] == 2)								// 0,0	x	1	2	 (vGrayCounts)
	{
		vDecrementGray[vGrayCounts[1]].flip();			// (vDecrementGray[vBase2Counts])
		vDecrementGray[vGrayCounts[1] + 2].flip();			// (vDecrementGray[vBase2Counts])

		bOK = true;
		bReturnBase2 = false;
		nReturn = 1014;	// ok

		//	37	5	 			||	000000100101	4 5		000000110111	3 5		0 1 1 1 2 1		0 3 1 2 6 0
		//	37	5	1			||	000000010101			000000011111			0 1 1 1 1 1		0 5 7 0 0 0
		//	37	5	1	1014	||	000000010101			000000011111			0 1 1 1 1 1		0 5 7 0 0 0	||	38 + 0 = 38	ok
	}
	else if (vBase2Counts[0] == 0 && vGrayCounts[0] == 0 && vGrayCounts[1] > 1 && vGrayCounts[1] % 2 == 0 && vGrayCounts[2] == 1 && vGrayCounts[3] == 2)								// 0,0	x	1	2	 (vGrayCounts)
	{
		vDecrementGray[vGrayCounts[1]].flip();			// (vDecrementGray[vBase2Counts])
		vDecrementGray[vGrayCounts[1] - 2].flip();			// (vDecrementGray[vBase2Counts])

		bOK = true;
		bReturnBase2 = false;
		nReturn = 10144;	// ok

		//	437	7	 			||	000110110101	3 4		000101101111	2 4		0 1 1 1 1 2		0 4 1 2 1 1
		//	437	7	1			||	000110101101			000101111011			0 1 1 2 1 1		0 2 1 4 1 1
		//	437	7	1	1014	||	000111010101			000100111111			0 1 1 1 1 1		0 6 2 1 3 0	||	437 + 1 = 438	error
		}
		//else if (vBase2Counts[0] == 1 && vGrayCounts[0] == 0 && vGrayCounts[1] > 2 && vGrayCounts[2] == 1 && vGrayCounts[3] > 2)								// 1,0	x	1	y	 (vGrayCounts)
	else if (vBase2Counts[0] == 1 && vGrayCounts[0] == 0 && vGrayCounts[1]  > 2 && vGrayCounts[1] % 2 == 1 && vGrayCounts[2] == 1 && vGrayCounts[3] > 2)								// 1,0	x	1	y	 (vGrayCounts)
	{
		vDecrementGray[vGrayCounts[1] - 2].flip();
		vDecrementGray[vGrayCounts[1]].flip();

		bOK = true;
		bReturnBase2 = false;
		nReturn = 1015;	// ok

		//	90	6	 			||	000001011010	2 3		000001110111	1 3		1 1 1 2 1 1		0 3 1 3 5 0
		//	90	6	1			||	000001010110			000001111101			1 2 1 1 1 1		0 1 1 5 5 0
		//	90	6	1	1015	||	000001010110			000001111101			1 2 1 1 1 1		0 1 1 5 5 0	||	91 + 0 = 91	ok
	}
	else if (vBase2Counts[0] == 1 && vGrayCounts[0] == 0 && vGrayCounts[1] > 2 && vGrayCounts[1] % 2 == 0 && vGrayCounts[2] == 1 && vGrayCounts[3] > 2)								// 1,0	x	1	y	 (vGrayCounts)
	{
		vDecrementGray[vGrayCounts[1]].flip();
		vDecrementGray[vGrayCounts[1] + 2].flip();

		bOK = true;
		bReturnBase2 = false;
		nReturn = 1016;	// ok

		//	330	8	 			||	000101001010	5 6		000111101111	4 6		1 1 1 1 2 1		0 4 1 4 3 0
		//	330	8	1			||	000100101010			000110111111			1 1 1 1 1 1		0 6 1 2 3 0
		//	330	8	1	1016	||	000100101010			000110111111			1 1 1 1 1 1		0 6 1 2 3 0	||	331 + 0 = 331	ok
	}
	else if (vBase2Counts[0] == 1 && vGrayCounts[0] == 0 && vGrayCounts[1] > 2 && vGrayCounts[1] % 2 == 0 && vGrayCounts[2] == 1 && vGrayCounts[3] == 2)								// 1,0	3	1	x	 (vGrayCounts)
	{
		vDecrementGray[vGrayCounts[1]].flip();
		vDecrementGray[vGrayCounts[1] + 2].flip();

		bOK = true;
		bReturnBase2 = false;
		nReturn = 1017;	// ok

		//	74	6	 			||	000001001010	5 6		000001101111	4 6		1 1 1 1 2 1		0 4 1 2 5 0
		//	74	6	1			||	000000101010			000000111111			1 1 1 1 1 1		0 6 6 0 0 0
		//	74	6	1	1017	||	000000101010			000000111111			1 1 1 1 1 1		0 6 6 0 0 0	||	75 + 0 = 75	ok
	}
	else if (vBase2Counts[0] == 1 && vGrayCounts[0] == 0 && vGrayCounts[1] > 2 && vGrayCounts[1] % 2 == 1 && vGrayCounts[2] == 1 && vGrayCounts[3] == 2)								// 1,0	3	1	x	 (vGrayCounts)
	{
		vDecrementGray[vGrayCounts[1]].flip();
		vDecrementGray[vGrayCounts[1] - 2].flip();

		bOK = true;
		bReturnBase2 = false;
		nReturn = 10177;	// ok

		//	874	8	 			||	001101101010	4 5		001011011111	3 5		1 1 1 1 1 2		0 5 1 2 1 1
		//	874	8	1			||	001101011010			001011110111			1 1 1 2 1 1		0 3 1 4 1 1
		//	874	8	1	1017	||	001110101010			001001111111			1 1 1 1 1 1		0 7 2 1 2 0	||	874 + 1 = 875	error
	}
	else if (vBase2Counts[0] == 1 && vGrayCounts[0] == 0 && vGrayCounts[1] > 2 && vGrayCounts[2] == 1 && vGrayCounts[3] == 2)								// 1,0	2	1	x	 (vGrayCounts)
	{
		vDecrementGray[vGrayCounts[1]].flip();
		vDecrementGray[vGrayCounts[1] - 2].flip();

		bOK = true;
		bReturnBase2 = false;
		nReturn = 1018;	// ok

		//	218	6	 			||	000011011010	2 3		000010110111	1 3		1 1 1 2 1 2		0 3 1 2 1 1
		//	218	6	1			||	000011010110			000010111101			1 2 1 1 1 2		0 1 1 4 1 1
		//	218	6	1	1018	||	000011010110			000010111101			1 2 1 1 1 2		0 1 1 4 1 1	||	219 + 0 = 219	ok
	}
	else if (vBase2Counts[0] == 0 && vGrayCounts[0] == 0 && vGrayCounts[1] > 2 && vGrayCounts[1] % 2 == 0 && vGrayCounts[2] == 1 && vGrayCounts[3] > 1)								// 0,0	4	1	y	 (vGrayCounts)
	{
		vDecrementGray[vGrayCounts[1]].flip();
		vDecrementGray[vGrayCounts[1] - 2].flip();

		bOK = true;
		bReturnBase2 = false;
		nReturn = 1019;

		//	181	7	 			||	000010110101	3 4		000011101111	2 4		0 1 1 1 1 2		0 4 1 3 4 0
		//	181	7	1			||	000010101101			000011111011			0 1 1 2 1 1		0 2 1 5 4 0
		//	181	7	1	1018	||	000010101101			000011111011			0 1 1 2 1 1		0 2 1 5 4 0	||	182 + 0 = 182	ok
	}
	else if (vBase2Counts[0] == 0 && vGrayCounts[0] == 0 && vGrayCounts[1] > 2 && vGrayCounts[1] % 2 == 1 && vGrayCounts[2] == 1 && vGrayCounts[3] > 1)								// 0,0	4	1	y	 (vGrayCounts)
	{
		vDecrementGray[vGrayCounts[1]].flip();
		vDecrementGray[vGrayCounts[1] + 2].flip();

		bOK = true;
		bReturnBase2 = false;
		nReturn = 10199;

		//	661	9	 			||	001010010101	6 7		001111011111	5 7		0 1 1 1 1 1		0 5 1 4 2 0
		//	661	9	1			||	001001010101			001101111111			0 1 1 1 1 1		0 7 1 2 2 0
		//	661	9	1	1019	||	001010100101			001111110111			0 1 1 1 2 1		0 3 1 6 2 0	||	661 + 1 = 662	error
	}
	else if (vBase2Counts[0] == 0 && vGrayCounts[0] == 0 && vGrayCounts[1] > 2 && vGrayCounts[2] == 1 && vGrayCounts[3] > 1)								// 0,0	3	1	y	 (vGrayCounts)
	{
		//vDecrementBase2[1].flip();						// (vDecrementBase2[vBase2Counts])
		//vDecrementBase2[2].flip();			
		vDecrementGray[vGrayCounts[1]].flip();			// (vDecrementGray[vBase2Counts])
		vDecrementGray[vGrayCounts[1] + 2].flip();			// (vDecrementGray[vBase2Counts])

		bOK = true;
		bReturnBase2 = false;
		nReturn = 1020;	// ok	*** same as 1014? - close

		//	165	7	 			||	000010100101	4 5		000011110111	3 5		0 1 1 1 2 1		0 3 1 4 4 0
		//	165	7	1			||	000010010101			000011011111			0 1 1 1 1 1		0 5 1 2 4 0
		//	165	7	1	1019	||	000010010101			000011011111			0 1 1 1 1 1		0 5 1 2 4 0	||	166 + 0 = 166	ok
	}
	else if (vBase2Counts[0] == 0 && vBase2Counts[1] == 1 && vBase2Counts[2] == 1 && vBase2Counts[3] > 1 && vBase2Counts[4] > 1)	// 0	1	1	x	y (vBase2Counts)
	{
		vDecrementBase2[1].flip();						// (vDecrementBase2[vBase2Counts])
		vDecrementBase2[2].flip();			
		//vDecrementGray[vGrayCounts[1] - 2].flip();			// (vDecrementGray[vBase2Counts])
		//vDecrementGray[vGrayCounts[1] - 0].flip();			// (vDecrementGray[vBase2Counts])

		bOK = true;
		bReturnBase2 = true;
		nReturn = 1021;	// ok

		//	13	3	 			||	000000001101	1 2		000000001011	0 2		0 1 1 2 8 0		0 2 1 1 8 0
		//	13	3	1			||	000000001011			000000001110			0 2 1 1 8 0		1 3 8 0 0 0
		//	13	3	1	1021	||	000000001011			000000001110			0 2 1 1 8 0		1 3 8 0 0 0	||	14 + 0 = 14	ok
	}
	else if (vBase2Counts[0] == 1 && vGrayCounts[0] == 0 && vGrayCounts[1] > 1 && vGrayCounts[1] % 2 == 0 && vGrayCounts[2] == 2 && vGrayCounts[3] == 2)								// 1,0	x	2	2	y (vGrayCounts)
	{
		vDecrementGray[vGrayCounts[1]].flip();
		vDecrementGray[vGrayCounts[1] + 3].flip();

		bOK = true;
		bReturnBase2 = false;
		nReturn = 1022;	// ok	return 2010

		//	34	4	 			||	000000100010	3 4 5	000000110011	2 5		1 1 3 1 6 0		0 2 2 2 6 0
		//	34	4	1			||	000000011010			000000010111			1 1 1 2 7 0		0 3 1 1 7 0
		//	34	4	1	1022	||	000000011010			000000010111			1 1 1 2 7 0		0 3 1 1 7 0	||	35 + 0 = 35	ok

		}
	else if (vBase2Counts[0] == 1 && vGrayCounts[0] == 0 && vGrayCounts[1] > 1 && vGrayCounts[1] % 2 == 1 && vGrayCounts[2] == 2 && vGrayCounts[3] == 2)								// 1,0	x	2	2	y (vGrayCounts)
	{
		vDecrementGray[vGrayCounts[1]].flip();
		vDecrementGray[vGrayCounts[1] - 2].flip();

		bOK = true;
		bReturnBase2 = false;
		nReturn = 10222;	// ok	return 2010

		//	442	6	 			||	000110111010	2 3		000101100111	1 3		1 1 1 3 1 2		0 3 2 2 1 1
		//	442	6	1			||	000110110110			000101101101			1 2 1 2 1 2		0 1 1 2 1 2
		//	442	6	1	1022	||	000111001010			000100101111			1 1 1 1 2 3		0 4 1 1 2 1	||	442 + 1 = 443	error
	}
	//else if (vGrayCounts[0] == 0 && vGrayCounts[1] == 2 && vGrayCounts[2] == 1 && vGrayCounts[3] > 2)								// 0	x	1	y	 (vGrayCounts)
	else if (vBase2Counts[0] == 0 && vBase2Counts[1] == 1 && vBase2Counts[2] == 1 && vBase2Counts[3] > 1)								// 0	1	1	x	(vBase2Counts)
	{
		vDecrementGray[0].flip();						// (vDecrementGray[])
		vDecrementGray[vGrayCounts[1]].flip();			// (vDecrementGray[])

		bOK = true;
		bReturnBase2 = false;
		nReturn = 1023;	// ok

		//	45	5	 			||	000000101101	1 2		000000111011	0 2		0 1 1 2 1 1		0 2 1 3 6 0
		//	45	5	1			||	000000101011			000000111110			0 2 1 1 1 1		1 5 6 0 0 0
		//	45	5	1	1023	||	000000101011			000000111110			0 2 1 1 1 1		1 5 6 0 0 0	||	46 + 0 = 46	ok

		//	82	6	 			||	000001010010	3 4		000001111011	2 4		1 1 2 1 1 1		0 2 1 4 5 0
		//	82	6	1			||	000001001010			000001101111			1 1 1 1 2 1		0 4 1 2 5 0
		//	82	6	1	2010	||	000001001010			000001101111			1 1 1 1 2 1		0 4 1 2 5 0	||	83 + 0 = 83	ok

	}
	else if (vBase2Counts[0] == 0 && vBase2Counts[1] > 1 && vBase2Counts[2] == 1 && vBase2Counts[3] > 0)								// 0	x	1	y	(vBase2Counts)
	{
		vDecrementGray[0].flip();
		vDecrementGray[vBase2Counts[1]].flip();		// (vIncrementGray[vBase2Counts])

		bOK = true;
		bReturnBase2 = false;
		nReturn = 1030;	// ok
	}
	else if (vGrayCounts[0] == 0 && vGrayCounts[1] > 1 && vGrayCounts[2] == 1 && vGrayCounts[3] == 1 && vGrayCounts[3] > 1)					// 0	x	1	1  (vGrayCounts)
	{
		vDecrementGray[vGrayCounts[1] - 1].flip();
		vDecrementGray[vGrayCounts[1] + 2].flip();

		bOK = true;
		bReturnBase2 = false;
		nReturn = 1040;	// ok = 4	***

		//	26	4	 			||	000000011010	2 3		000000010111	1 3		1 1 1 2 7 0		0 3 1 1 7 0
		//	26	4	1			||	000000010110			000000011101			1 2 1 1 7 0		0 1 1 3 7 0
		//	26	4	1	1040	||	000000100010			000000110011			1 1 3 1 6 0		0 2 2 2 6 0	||	26 + 1 = 27	error


		//	101	5	 			||	000001100101	3 4 5	000001010111	2 5		0 1 1 1 2 2		0 3 1 1 1 1
		//	101	5	1			||	000001011101			000001110011			0 1 1 3 1 1		0 2 2 3 5 0
		//	101	7	1	1080	||	000001010101			000001111111			0 1 1 1 1 1		0 7 5 0 0 0	||	101 + 1 = 102	error
	}
	else if (vBase2Counts[0] == 0 && vBase2Counts[1] == 1 && vBase2Counts[2] == 1 && vBase2Counts[3] > 1 && vBase2Counts[4] == 1 && vBase2Counts[5] > 0)					// 0	1	1	x	1	y	(vBase2Counts)
	{
		vDecrementGray[2].flip();
		vDecrementGray[vBase2Counts[3] + 2].flip();		// (vIncrementGray[vBase2Counts])

		bOK = true;
		bReturnBase2 = false;
		nReturn = 1050;	// ok = 7
	}
	else if (vBase2Counts[0] == 0 && vBase2Counts[1] == 1 && vBase2Counts[2] == 1 && vBase2Counts[3] > 1 && vBase2Counts[4] == 1)		// 0	1	1	x	1	(vBase2Counts)
	{
		vDecrementGray[1].flip();
		vDecrementGray[vGrayCounts[1] + vGrayCounts[2] + vGrayCounts[3]].flip();

		bOK = true;
		nReturn = 1051;	// ok = 1	***
	}
	else if (vBase2Counts[0] == 0 && vGrayCounts[0] == 0 && vGrayCounts[1] > 2 && vGrayCounts[1] % 2 == 0 && vGrayCounts[2] == 1 && vGrayCounts[3] == 1 && vGrayCounts[4] > 2)					//	0	x	1	1	y	(vGrayCounts)
	{
		vDecrementGray[vGrayCounts[1]].flip();		// (vDecrementGray[vGrayCounts])
		vDecrementGray[vGrayCounts[1] - 2].flip();		// (vDecrementGray[vGrayCounts])

		bOK = true;
		bReturnBase2 = false;
		nReturn = 1060;

		//	53	5	 			||	000000110101	3 4		000000101111	2 4		0 1 1 1 1 2		0 4 1 1 6 0
		//	53	5	1			||	000000101101			000000111011			0 1 1 2 1 1		0 2 1 3 6 0
		//	53	5	1	1060	||	000000101101			000000111011			0 1 1 2 1 1		0 2 1 3 6 0	||	54 + 0 = 54	ok
	}
	else if (vBase2Counts[0] == 0 && vGrayCounts[0] == 0 && vGrayCounts[1] > 2 && vGrayCounts[1] % 2 == 1 && vGrayCounts[2] == 1 && vGrayCounts[3] == 1 && vGrayCounts[4] > 2)					//	0	x	1	1	y	(vGrayCounts)
	{
		vDecrementGray[vGrayCounts[1] - 1].flip();		// (vDecrementGray[vGrayCounts])
		vDecrementGray[vGrayCounts[1] + 2].flip();		// (vDecrementGray[vGrayCounts])

		bOK = true;
		bReturnBase2 = false;
		nReturn = 1061;

		//	485	5	 			||	000111100101	3 4 5	000100010111	2 5		0 1 1 1 2 4		0 3 1 1 3 1
		//	485	5	1			||	000111011101			000100110011			0 1 1 3 1 3		0 2 2 2 2 1
		//	485	5	1	1060	||	000111101001			000100011101			0 1 2 1 1 4		0 1 1 3 3 1	||	485 + 1 = 486	error
	}
	else if (vBase2Counts[0] == 0 && vGrayCounts[0] == 0 && vGrayCounts[1] > 2 && vGrayCounts[1] % 2 == 0 && vGrayCounts[2] == 2 && vGrayCounts[3] == 1 && vGrayCounts[4] > 2)		// 0	x	2	1	y(vGrayCounts)
	{
		vDecrementGray[vGrayCounts[1] - 2].flip();
		vDecrementGray[vGrayCounts[1] - 0].flip();		// (vDecrementGray[vGrayCounts])

		bOK = true;
		bReturnBase2 = false;
		nReturn = 1070;	// ok = 1

		//	117	5	 			||	000001110101	3 4		000001001111	2 4		0 1 1 1 1 3		0 4 2 1 5 0
		//	117	5	1			||	000001101101			000001011011			0 1 1 2 1 2		0 2 1 2 1 1
		//	117	5	1	1070	||	000001101101			000001011011			0 1 1 2 1 2		0 2 1 2 1 1	||	118 + 0 = 118	ok
	}
	else if (vBase2Counts[0] == 0 && vGrayCounts[0] == 0 && vGrayCounts[1] > 2 && vGrayCounts[1] % 2 == 1 && vGrayCounts[2] == 2 && vGrayCounts[3] == 1 && vGrayCounts[4] > 2)		// 0	x	2	1	y(vGrayCounts)
	{
		vDecrementGray[vGrayCounts[1] - 1].flip();		// (vDecrementGray[vGrayCounts])
		vDecrementGray[vGrayCounts[1] + 3].flip();

		bOK = true;
		bReturnBase2 = false;
		nReturn = 10700;	// ok = 1

		//	965	5	 			||	001111000101	3 4 5 6	001000100111	2 6		0 1 1 1 3 4		0 3 2 1 3 1
		//	965	5	1			||	001110111101			001001100011			0 1 1 4 1 3		0 2 3 2 2 1
		//	965	5	1	1070	||	001111001001			001000101101			0 1 2 1 2 4		0 1 1 2 1 1	||	965 + 1 = 966	error
	}
	else if (vBase2Counts[0] == 0 && vGrayCounts[0] == 0 && vGrayCounts[1] == 3 && vGrayCounts[2] == 1 && vGrayCounts[3] == 1 && vGrayCounts[4] > 0)					// 0,0	3	1	1	y	(vGrayCounts)
	{
		vDecrementGray[vGrayCounts[1] - 1].flip();
		vDecrementGray[vGrayCounts[1] + 2].flip();

		bOK = true;
		bReturnBase2 = false;
		nReturn = 1080;	// ok = 2	***

		//	101	5	 			||	000001100101	3 4 5	000001010111	2 5		0 1 1 1 2 2		0 3 1 1 1 1
		//	101	5	1			||	000001011101			000001110011			0 1 1 3 1 1		0 2 2 3 5 0
		//	101	5	1	1080	||	000001011101			000001110011			0 1 1 3 1 1		0 2 2 3 5 0	||	102 + 0 = 102	ok

		//	229	5	 			||	000011100101	3 4 5	000010010111	2 5		0 1 1 1 2 3		0 3 1 1 2 1
		//	229	5	1			||	000011011101			000010110011			0 1 1 3 1 2		0 2 2 2 1 1
		//	229	5	1	1080	||	000011011101			000010110011			0 1 1 3 1 2		0 2 2 2 1 1	||	230 + 0 = 230	ok

	}
	else if (vBase2Counts[0] == 0 && vGrayCounts[0] == 0 && vGrayCounts[1] > 2 && vGrayCounts[1] % 2 == 0 && vGrayCounts[2] == 1 && vGrayCounts[3] == 1 && vGrayCounts[4] > 0)					// 0,0	4	1	1	y	(vGrayCounts)
	{
		vDecrementGray[vGrayCounts[1] - 2].flip();
		vDecrementGray[vGrayCounts[1] + 0].flip();

		bOK = true;
		bReturnBase2 = false;
		nReturn = 1081;	// ok = 2	***

		//	309	7	 			||	000100110101	3 4		000110101111	2 4		0 1 1 1 1 2		0 4 1 1 1 2
		//	309	7	1			||	000100101101			000110111011			0 1 1 2 1 1		0 2 1 3 1 2
		//	309	7	1	1081	||	000100101101			000110111011			0 1 1 2 1 1		0 2 1 3 1 2	||	310 + 0 = 310	ok
	}
	else if (vBase2Counts[0] == 0 && vGrayCounts[0] == 0 && vGrayCounts[1] > 2 && vGrayCounts[1] % 2 == 1 && vGrayCounts[2] == 1 && vGrayCounts[3] == 1 && vGrayCounts[4] > 0)					// 0,0	5	1	1	y	(vGrayCounts)
	{
		vDecrementGray[vGrayCounts[1] - 1].flip();
		vDecrementGray[vGrayCounts[1] + 2].flip();

		bOK = true;
		bReturnBase2 = false;
		nReturn = 1081;	// ok = 2	***

		//	405	7	 			||	000110010101	5 6 7	000101011111	4 7		0 1 1 1 1 1		0 5 1 1 1 1
		//	405	7	1			||	000101110101			000111001111			0 1 1 1 1 3		0 4 2 3 3 0
		//	405	7	1	1081	||	000110100101			000101110111			0 1 1 1 2 1		0 3 1 3 1 1	||	405 + 1 = 406	error
	}
	//else if (vBase2Counts[0] == 0 && vBase2Counts[1] == 1 && vGrayCounts[1] > 2 && vGrayCounts[2] > 1 && vGrayCounts[3] > 1)					// 0	1(vBase2Counts)	0	>2	>0	> 1 (vGrayCounts)	155
	else if (vBase2Counts[0] == 0 && vGrayCounts[0] == 0 && vGrayCounts[1] > 2 && vGrayCounts[1] % 2 == 1 && vGrayCounts[2] > 1 && vGrayCounts[3] > 1)					// 0	
	{
		vDecrementGray[vGrayCounts[1]].flip();
		vDecrementGray[vGrayCounts[1] + vGrayCounts[2] + 1].flip();

		bOK = true;
		bReturnBase2 = false;
		nReturn = 1090;	// ok = 1	***

		//	325	7	 			||	000101000101	4 5 6	000111100111	3 6		0 1 1 1 3 1		0 3 2 4 3 0
		//	325	7	1			||	000100110101			000110101111			0 1 1 1 1 2		0 4 1 1 1 2
		//	325	7	1	1090	||	000100110101			000110101111			0 1 1 1 1 2		0 4 1 1 1 2	||	326 + 0 = 326	ok
	}
	else if (vBase2Counts[0] == 0 && vGrayCounts[0] == 0 && vGrayCounts[1] > 2 && vGrayCounts[1] % 2 == 0 && vGrayCounts[2] > 1 && vGrayCounts[3] > 1)					// 0	
	{
		vDecrementGray[vGrayCounts[1]].flip();
		vDecrementGray[vGrayCounts[1] - 2].flip();

		bOK = true;
		bReturnBase2 = false;
		nReturn = 1090;	// ok = 1	***

		//	373	7	 			||	000101110101	3 4		000111001111	2 4		0 1 1 1 1 3		0 4 2 3 3 0
		//	373	7	1			||	000101101101			000111011011			0 1 1 2 1 2		0 2 1 2 1 3
		//	373	7	1	1090	||	000110010101			000101011111			0 1 1 1 1 1		0 5 1 1 1 1	||	373 + 1 = 374	error
	}
	else if (vBase2Counts[0] == 0 && vBase2Counts[1] > 1 && vBase2Counts[2] == 1 && vBase2Counts[3] == 0)					//	0	x	1	0	(vBase2Counts)
	{
		vDecrementGray[vGrayCounts[0]].flip();
		vDecrementGray[vGrayCounts[0] + 1].flip();					// (vDecrementGray[vGrayCounts])

		bOK = true;
		bReturnBase2 = false;
		nReturn = 1100;	// ok - 1	***
	}
	else if (vBase2Counts[0] == 0 && vGrayCounts[0] > 0 && vBase2Counts[1] > 0 && vBase2Counts[2] > 0 && vBase2Counts[3] == 1)					//	0	x	y	1	(vBase2Counts)
	//else if (vGrayCounts[0] > 0 && vGrayCounts[1] > 0 && vGrayCounts[2] > 0 && vGrayCounts[3] > 1)					//	0	x	y	1	(vGrayCounts)
	{
		vDecrementBase2[vBase2Counts[1] - 1].flip();
		//vDecrementGray[vGrayCounts[0] - 1].flip();
		//vDecrementGray[vGrayCounts[0] - 0].flip();

		bOK = true;
		bReturnBase2 = true;
		//bReturnBase2 = false;
		nReturn = 1110;

		//	19	3	 			||	000000010011	1		000000011010	0 1		0 2 2 1 7 0		1 1 1 2 7 0
		//	19	3	1			||	000000010001			000000011001			0 1 3 1 7 0		0 1 2 2 7 0
		//	19	3	1	1110	||	000000010001			000000011001			0 1 3 1 7 0		0 1 2 2 7 0	||	20 + 0 = 20	ok

		//	39	3	 			||	000000100111	2		000000110100	1 2		0 3 2 1 6 0		2 1 1 2 6 0
		//	39	3	1			||	000000100011			000000110010			0 2 3 1 6 0		1 1 2 2 6 0
		//	39	3	1	1110	||	000000100011			000000110010			0 2 3 1 6 0		1 1 2 2 6 0	||	40 + 0 = 40	ok
	}
	else if (vBase2Counts[0] == 0 && vBase2Counts[1] == 1 && vBase2Counts[2] == 1 && vBase2Counts[3] > 1)					//	0	1	1	x	(vBase2Counts)
	{
		vDecrementBase2[1].flip();
		vDecrementBase2[2].flip();

		bOK = true;
		bReturnBase2 = true;
		nReturn = 1111;

		//	29	3	 			||	000000011101		000000010011		0 1 1 3 7 0		0 2 2 1 7 0
		//	29	3	1			||	000000011011		000000010110		0 2 1 2 7 0		1 2 1 1 7 0
		//	29	3	1	1111	||	000000011011		000000010110		0 2 1 2 7 0		1 2 1 1 7 0	||	30 + 0 = 30	ok
	}
	else if (vBase2Counts[0] == 0 && vBase2Counts[1] > 1 && vBase2Counts[2] > 1 && vBase2Counts[3] > 1)					//	0	2	2	x	(vBase2Counts)
	{
		vDecrementBase2[vBase2Counts[1] - 1].flip();

		bOK = true;
		bReturnBase2 = true;
		nReturn = 1112;

		//	51	3	 			||	000000110011	1		000000101010	0 1		0 2 2 2 6 0		1 1 1 1 1 1
		//	51	3	1			||	000000110001			000000101001			0 1 3 2 6 0		0 1 2 1 1 1
		//	51	3	1	1112	||	000000110001			000000101001			0 1 3 2 6 0		0 1 2 1 1 1	||	52 + 0 = 52	ok

		//	103	3	 			||	000001100111	2		000001010100	1 2		0 3 2 2 5 0		2 1 1 1 1 1
		//	103	3	1			||	000001100011			000001010010			0 2 3 2 5 0		1 1 2 1 1 1
		//	103	5	1	1112	||	000001100101			000001010111			0 1 1 1 2 2		0 3 1 1 1 1	||	103 + 1 = 104	error
	}
	else if (vBase2Counts[0] == 1 && vBase2Counts[1] == 1 && vBase2Counts[2] > 1 && vBase2Counts[3] == 1)								// 1	1	x	(vBase2Counts)	
	{
		vDecrementGray[vGrayCounts[1] + vGrayCounts[2] + 1].flip();		// (vDecrementGray[vGrayCounts])
		vDecrementGray[vGrayCounts[1]].flip();

		bOK = true;
		bReturnBase2 = false;
		nReturn = 2010;	// ok

		//	18	4			 || 000000010010		000000011011		1 1 2 1 7 0		0 2 1 2 7 0
		//	18	4	1		 || 000000001010		000000001111		1 1 1 1 8 0		0 4 8 0 0 0
		//	18	4	1	2010 || 000000001010		000000001111		1 1 1 1 8 0		0 4 8 0 0 0 || 19 + 0 = 19	ok

		//	34	4			 || 000000100010		000000110011		1 1 3 1 6 0		0 2 2 2 6 0
		//	34	4	1		 || 000000011010		000000010111		1 1 1 2 7 0		0 3 1 1 7 0
		//	34	4	1	2010 || 000000011010		000000010111		1 1 1 2 7 0		0 3 1 1 7 0 || 29 + 6 = 35	ok
	}
	else if (vBase2Counts[0] == 1 && vBase2Counts[1] == 1 && vBase2Counts[2] > 1 && vBase2Counts[3] > 1)								// 1	1	x	(vBase2Counts)	
	{
		vDecrementGray[1].flip();
		//vDecrementGray[vGrayCounts[1] + 2].flip();		// (vDecrementGray[vGrayCounts])
		vDecrementGray[vBase2Counts[2] + 2].flip();		// (vDecrementGray[vGrayCounts])

		bOK = true;
		bReturnBase2 = false;
		nReturn = 2011;	// ok

		//	50	4	 			||	000000110010	2 3 4	000000101011	1 4		1 1 2 2 6 0		0 2 1 1 1 1
		//	50	4	1			||	000000101110			000000111001			1 3 1 1 6 0		0 1 2 3 6 0
		//	50	4	1	2011	||	000000101110			000000111001			1 3 1 1 6 0		0 1 2 3 6 0	||	51 + 0 = 51	ok

		//	98	4	 			||	000001100010	2 3 4 5	000001010011	1 5		1 1 3 2 5 0		0 2 2 1 1 1
		//	98	4	1			||	000001011110			000001110001			1 4 1 1 5 0		0 1 3 3 5 0
		//	98	2	1	2011	||	000001111110			000001000001			1 6 5 0 0 0		0 1 5 1 5 0	||	98 + 1 = 99	error

		//	114	4	 			||	000001110010	2 3 4	000001001011	1 4		1 1 2 3 5 0		0 2 1 1 2 1
		//	114	4	1			||	000001101110			000001011001			1 3 1 2 5 0		0 1 2 2 1 1
		//	114	4	1	2011	||	000001101110			000001011001			1 3 1 2 5 0		0 1 2 2 1 1	||	115 + 0 = 115	ok

	}
	else if (vBase2Counts[0] == 1 && vGrayCounts[0] == 0 && vGrayCounts[1] > 2 && vGrayCounts[1] % 2 == 1 && vGrayCounts[2] == 2 && vGrayCounts[3] > 2)			// 0	x	2	y	 (vGrayCounts)
	{
		vDecrementGray[vGrayCounts[1] - 2].flip();
		vDecrementGray[vGrayCounts[1]].flip();

		bOK = true;
		bReturnBase2 = false;
		nReturn = 2012;	// ok 

		//	186	6	 			||	000010111010	2 3		000011100111	1 3		1 1 1 3 1 1		0 3 2 3 4 0
		//	186	6	1			||	000010110110			000011101101			1 2 1 2 1 1		0 1 1 2 1 3
		//	186	6	1	2012	||	000011001010			000010101111			1 1 1 1 2 2		0 4 1 1 1 1	||	186 + 1 = 187	error
	}
	else if (vBase2Counts[0] == 1 && vGrayCounts[0] == 0 && vGrayCounts[1] > 2 && vGrayCounts[1] % 2 == 0 && vGrayCounts[2] == 2 && vGrayCounts[3] > 2)			// 0	x	2	y	 (vGrayCounts)
	{
		vDecrementGray[vGrayCounts[1]].flip();
		vDecrementGray[vGrayCounts[1] + 3].flip();

		bOK = true;
		bReturnBase2 = false;
		nReturn = 20122;	// ok 

		//	650	8	 			||	001010001010	5 6 7	001111001111	4 7		1 1 1 1 3 1		0 4 2 4 2 0
		//	650	8	1			||	001001101010			001101011111			1 1 1 1 1 2		0 5 1 1 1 2
		//	650	8	1	2012	||	001010010110			001111011101			1 2 1 1 2 1		0 1 1 3 1 4	||	650 + 1 = 651	error
	}
	else if (vBase2Counts[0] == 1 && vBase2Counts[3] > 1 && vGrayCounts[0] == 0 && vGrayCounts[1] > 2 && vGrayCounts[2] > 0)								// 0	x	y	(vGrayCounts)
	{
		vDecrementGray[1].flip();
		vDecrementGray[vGrayCounts[1]].flip();			// (vDecrementGray[vGrayCounts])

		bOK = true;
		bReturnBase2 = false;
		nReturn = 2013;	// ok = 4

		//	122	4	 			||	000001111010	2 3		000001000111	1 3		1 1 1 4 5 0		0 3 3 1 5 0
		//	122	4	1			||	000001110110			000001001101			1 2 1 3 5 0		0 1 1 2 2 1
		//	122	4	1	2013	||	000001110110			000001001101			1 2 1 3 5 0		0 1 1 2 2 1	||	123 + 0 = 123	ok

		//	154	6	 			||	000010011010	2 3		000011010111	1 3		1 1 1 2 2 1		0 3 1 1 1 2
		//	154	6	1			||	000010010110			000011011101			1 2 1 1 2 1		0 1 1 3 1 2
		//	154	6	1	2013	||	000010010110			000011011101			1 2 1 1 2 1		0 1 1 3 1 2	||	155 + 0 = 155	ok

		//	202	6	 			||	000011001010	4 5 6	000010101111	3 6		1 1 1 1 2 2		0 4 1 1 1 1
		//	202	6	1			||	000010111010			000011100111			1 1 1 3 1 1		0 3 2 3 4 0
		//	202	6	1	2013	||	000011010110			000010111101			1 2 1 1 1 2		0 1 1 4 1 1	||	202 + 1 = 203	error
	}
	else if (vBase2Counts[0] == 1 && vBase2Counts[1] > 1 && vBase2Counts[2] == 1 && vBase2Counts[3] > 0)	// 1	x	1	y		// vBase2Counts
	{
		vDecrementBase2[1].flip();

		bOK = true;
		bReturnBase2 = true;
		nReturn = 2014;	// ok = 15

	}
	else if (vBase2Counts[0] == 1 && vBase2Counts[1] > 1 && vBase2Counts[2] > 0)								// 1	x	y		// vBase2Counts
	{
		//vDecrementGray[0].flip();
		//vDecrementGray[vBase2Counts[0] + vBase2Counts[1]].flip();

		vDecrementBase2[vBase2Counts[0]].flip();						// (vDecrementBase2[vBase2Counts])

		bOK = true;
		//bReturnBase2 = false;
		bReturnBase2 = true;
		nReturn = 2015;	// ok = 16
	}
	else if (vBase2Counts[0] == 0 && vGrayCounts[0] == 0 && vGrayCounts[1] > 2 && vGrayCounts[1] % 2 == 1 && vGrayCounts[2] == 2 && vGrayCounts[3] > 0)								// 0	x	2	y	(vGrayCounts)
	{
		vDecrementGray[vGrayCounts[1] - 1].flip();
		vDecrementGray[vGrayCounts[1] + vGrayCounts[2] + 1].flip();	

		bOK = true;
		bReturnBase2 = false;
		nReturn = 2016;	// ok = 4

		//	197	5	 			||	000011000101	3 4 5 6	000010100111	2 6		0 1 1 1 3 2		0 3 2 1 1 1
		//	197	5	1			||	000010111101			000011100011			0 1 1 4 1 1		0 2 3 3 4 0
		//	197	5	1	2016	||	000010111101			000011100011			0 1 1 4 1 1		0 2 3 3 4 0	||	198 + 0 = 198	ok

	}
	else if (vBase2Counts[0] == 0 && vGrayCounts[0] == 0 && vGrayCounts[1] > 2 && vGrayCounts[1] % 2 == 0 && vGrayCounts[2] == 2 && vGrayCounts[3] > 0)								// 0	x	2	y	(vGrayCounts)
	{
		vDecrementGray[vGrayCounts[1] - 2].flip();
		vDecrementGray[vGrayCounts[1]].flip();			// (vDecrementGray[vGrayCounts])

		bOK = true;
		bReturnBase2 = false;
		nReturn = 20166;	// ok = 4

		//	629	7	 			||	001001110101	3 4		001101001111	2 4		0 1 1 1 1 3		0 4 2 1 1 2
		//	629	7	1			||	001001101101			001101011011			0 1 1 2 1 2		0 2 1 2 1 1
		//	629	7	1	2016	||	001010000101			001111000111			0 1 1 1 4 1		0 3 3 4 2 0	||	629 + 1 = 630	error
	}
	//else if (vBase2Counts[0] == 0 && vGrayCounts[0] == 0 && vGrayCounts[1] > 2 && vGrayCounts[2] > 2 && vGrayCounts[3] > 0)								// 0	x	y	1	(vGrayCounts)
	else if (vBase2Counts[0] == 0 && vGrayCounts[0] == 0 && vGrayCounts[1] > 2 && vGrayCounts[1] % 2 == 0 && vGrayCounts[2] > 2 && vGrayCounts[3] > 0)								// 0	x	y	1	(vGrayCounts)
	{
		vDecrementGray[vGrayCounts[1] - 2].flip();
		vDecrementGray[vGrayCounts[1]].flip();			// (vDecrementGray[vGrayCounts])

		bOK = true;
		bReturnBase2 = false;
		nReturn = 2017;	// ok = 4

		//	245	5	 			||	000011110101	3 4		000010001111	2 4		0 1 1 1 1 4		0 4 3 1 4 0
		//	245	5	1			||	000011101101			000010011011			0 1 1 2 1 3		0 2 1 2 2 1
		//	245	5	1	2017	||	000011101101			000010011011			0 1 1 2 1 3		0 2 1 2 2 1	||	246 + 0 = 246	ok
	}
	else if (vBase2Counts[0] == 0 && vGrayCounts[0] == 0 && vGrayCounts[1] > 2 && vGrayCounts[1] % 2 == 1 && vGrayCounts[2] > 2 && vGrayCounts[3] > 0)								// 0	x	y	1	(vGrayCounts)
	{
		vDecrementGray[vGrayCounts[1] - 1].flip();
		vDecrementGray[vGrayCounts[1] + vGrayCounts[2] + vGrayCounts[3]].flip();			// (vDecrementGray[vGrayCounts])

		bOK = true;
		bReturnBase2 = false;
		nReturn = 2017;	// ok = 4

		//	389	5	 			||	000110000101	3 4 5 6 7		000101000111	2 7		0 1 1 1 4 2		0 3 3 1 1 1
		//	389	5	1			||	000101111101			000111000011			0 1 1 5 1 1		0 2 4 3 3 0
		//	389	5	1	2017	||	000101111101			000111000011			0 1 1 5 1 1		0 2 4 3 3 0	||	390 + 0 = 390	ok
	}
	else if (vBase2Counts[0] == 1 && vGrayCounts[0] == 0 && vGrayCounts[1] > 2 && vGrayCounts[1] % 2 == 1 && vGrayCounts[2] == 1 && vGrayCounts[3] == 1)								// 1,0	x	1	1	(vGrayCounts)
	{
		vDecrementGray[vGrayCounts[1] - 2].flip();
		vDecrementGray[vGrayCounts[1]].flip();			// (vDecrementGray[vGrayCounts])

		bOK = true;
		bReturnBase2 = false;
		nReturn = 2019;	// ok = 4

		//	106	6	 			||	000001101010	4 5		000001011111	3 5		1 1 1 1 1 2		0 5 1 1 5 0
		//	106	6	1			||	000001011010			000001110111			1 1 1 2 1 1		0 3 1 3 5 0
		//	106	6	1	2019	||	000010001010			000011001111			1 1 1 1 3 1		0 4 2 2 4 0	||	106 + 1 = 107	error
	}
	else if (vBase2Counts[0] == 1 && vGrayCounts[0] == 0 && vGrayCounts[1] > 2 && vGrayCounts[1] % 2 == 0 && vGrayCounts[2] == 1 && vGrayCounts[3] == 1)								// 1,0	x	1	1	(vGrayCounts)
	{
		vDecrementGray[vGrayCounts[1] - 1].flip();
		vDecrementGray[vGrayCounts[1] + 2].flip();			// (vDecrementGray[vGrayCounts])

		bOK = true;
		bReturnBase2 = false;
		nReturn = 20199;	// ok = 4

		//	202	6	 			||	000011001010	4 5 6	000010101111	3 6		1 1 1 1 2 2		0 4 1 1 1 1
		//	202	6	1			||	000010111010			000011100111			1 1 1 3 1 1		0 3 2 3 4 0
		//	202	6	1	2019	||	000010111010			000011100111			1 1 1 3 1 1		0 3 2 3 4 0	||	202 + 1 = 203	ok
	}
	else if (vBase2Counts[0] == 1 && vGrayCounts[0] == 0 && vGrayCounts[1] > 2 && vGrayCounts[1] % 2 == 0 && vGrayCounts[2] > 1 && vGrayCounts[3] > 1)								// 1,0	x	y	2	(vGrayCounts)	178
	{
		vDecrementGray[vGrayCounts[1]].flip();
		vDecrementGray[vGrayCounts[1] + vGrayCounts[2] + 1].flip();			// (vDecrementGray[vGrayCounts])

		bOK = true;
		bReturnBase2 = false;
		nReturn = 2020;	// ok = 4

		//	266	6	 			||	000100001010	5 6 7 8	000110001111	4 8		1 1 1 1 4 1		0 4 3 2 3 0
		//	266	6	1			||	000011101010			000010011111			1 1 1 1 1 3		0 5 2 1 4 0
		//	266	6	1	2020	||	000011101010			000010011111			1 1 1 1 1 3		0 5 2 1 4 0	||	267 + 0 = 267	ok
	}
	else if (vBase2Counts[0] == 1 && vGrayCounts[0] == 0 && vGrayCounts[1] > 2 && vGrayCounts[1] % 2 == 1 && vGrayCounts[2] > 1 && vGrayCounts[3] > 1)								// 1,0	x	y	2	(vGrayCounts)	178
	{
		vDecrementGray[vGrayCounts[1]].flip();
		vDecrementGray[vGrayCounts[1] - 2].flip();			// (vDecrementGray[vGrayCounts])

		bOK = true;
		bReturnBase2 = false;
		nReturn = 20200;	// ok = 4

		//	1514	8	 		||	010111101010	4 5		011100011111	3 5		1 1 1 1 1 4		0 5 3 3 1 0
		//	1514	8	1		||	010111011010			011100110111			1 1 1 2 1 3		0 3 1 2 2 3
		//	1514	8	1	2020||	011000101010			010100111111			1 1 1 1 1 1		0 6 2 1 1 1	||	1514 + 1 = 1515	error
	}
	else if (vBase2Counts[0] == 1 && vGrayCounts[0] == 0 && vGrayCounts[1] > 1 && vGrayCounts[1] % 2 == 0 && vGrayCounts[2] > 1)								// 1,0	x	y	(vGrayCounts)	178
	{
		vDecrementGray[vGrayCounts[1] - 1].flip();
		vDecrementGray[vGrayCounts[1] + vGrayCounts[2] + 1].flip();			// (vDecrementGray[vGrayCounts])

		bOK = true;
		bReturnBase2 = false;
		nReturn = 2021;	// ok = 4

		//	394	6	 			||	000110001010	4 5 6 7	000101001111	3 7		1 1 1 1 3 2		0 4 2 1 1 1
		//	394	6	1			||	000101111010			000111000111			1 1 1 4 1 1		0 3 3 3 3 0
		//	394	8	1	2020	||	000101101010			000111011111			1 1 1 1 1 2		0 5 1 3 3 0	||	394 + 1 = 395	error
	}
	else if (vBase2Counts[0] == 1 && vGrayCounts[0] == 0 && vGrayCounts[1] > 1 && vGrayCounts[1] % 2 == 1 && vGrayCounts[2] > 1)								// 1,0	x	y	(vGrayCounts)	178
	{
		vDecrementGray[vGrayCounts[1] - 2].flip();
		vDecrementGray[vGrayCounts[1]].flip();			// (vDecrementGray[vGrayCounts])

		bOK = true;
		bReturnBase2 = false;
		nReturn = 20211;	// ok = 4

		//	490	6	 			||	000111101010	4 5		000100011111	3 5		1 1 1 1 1 4		0 5 3 1 3 0
		//	490	6	1			||	000111011010			000100110111			1 1 1 2 1 3		0 3 1 2 2 1
		//	490	6	1	2021	||	001000001010			001100001111			1 1 1 1 5 1		0 4 4 2 2 0	||	490 + 1 = 491	error
	}
	else if (vBase2Counts[0] > 1 && vBase2Counts[1] == 1 && vBase2Counts[2] > 0)											// x	1	y (vBase2Counts)		//	2 1 9 0 0 0
	{
		//vDecrementGray[0].flip();
		//vDecrementGray[vGrayCounts[0] + vGrayCounts[1] - 1].flip();
		vDecrementGray[0].flip();
		vDecrementGray[vBase2Counts[0]].flip();

		bOK = true;
		//bReturnBase2 = true;
		bReturnBase2 = false;
		nReturn = 2022;	// ok

		//	4	2	 			||	000000000100	1 2		000000000110	0 2		2 1 9 0 0 0		1 2 9 0 0 0
		//	4	2	1			||	000000000010			000000000011			1 1 10 0 0 0	0 2 10 0 0 0
		//	4	2	1	2020	||	000000000010			000000000011			1 1 10 0 0 0	0 2 10 0 0 0	||	5 + 0 = 5	ok

		//	8	2	 			||	000000001000	1 2 3	000000001100	0 3		3 1 8 0 0 0		2 2 8 0 0 0
		//	8	2	1			||	000000000110			000000000101			1 2 9 0 0 0		0 1 1 1 9 0
		//	8	2	1	2020	||	000000000110			000000000101			1 2 9 0 0 0		0 1 1 1 9 0		||	9 + 0 = 9	ok

		//	104	4	 			||	000001101000	1 2 3	000001011100	0 3		3 1 1 2 5 0		2 3 1 1 5 0
		//	104	4	1			||	000001100110			000001010101			1 2 2 2 5 0		0 1 1 1 1 1
		//	104	0	0	0		||	000000000000			000000000000			12 0 0 0 0 0	12 0 0 0 0 0	||	104 + 1 = 105	error

	}
	else if (vBase2Counts[0] == 1 && vBase2Counts[1] > 1 && vBase2Counts[2] > 1)							// 1	x	y (vBase2Counts)
	{
		vDecrementGray[0].flip();
		vDecrementGray[vBase2Counts[1] + 1].flip();			// (vDecrementGray[vBase2Counts])

		bOK = true;
		bReturnBase2 = false;
		nReturn = 2030;	// ok
	}
	else if (vBase2Counts[0] > 1 && vBase2Counts[1] > 1)								// x	y	(vBase2Counts)
	{
		vDecrementBase2[vBase2Counts[0]].flip();		// (vDecrementBase2[vBase2Counts])

		bOK = true;
		bReturnBase2 = true;
		nReturn = 2040;	// ok = 26

		//	12	2	 			||	000000001100		000000001010		2 2 8 0 0 0		1 1 1 1 8 0
		//	12	2	1			||	000000001000		000000001100		3 1 8 0 0 0		2 2 8 0 0 0
		//	12	2	1	2040	||	000000001000		000000001100		3 1 8 0 0 0		2 2 8 0 0 0	||	13 + 0 = 13	ok
		}
	//else if (vBase2Counts[0] > 1 && vBase2Counts[1] == 1 && vBase2Counts[2] == 1)										// x	1	1	(vBase2Counts)
	else if (vGrayCounts[0]  > 0 && vGrayCounts[1] > 1 && vGrayCounts[2] > 1)											// x	1	1	(vBase2Counts)
	{
		//vDecrementBase2[vGrayCounts[0]].flip();		// (vDecrementBase2[vGrayCounts])
		//vDecrementBase2[vGrayCounts[1]].flip();		// (vDecrementBase2[vGrayCounts])
		vDecrementGray[0].flip();					// (vDecrementGray[vGrayCounts])
		vDecrementGray[vGrayCounts[0] + 1].flip();		// (vDecrementGray[vGrayCounts])

		bOK = true;
		bReturnBase2 = false;
		nReturn = 2041;	// ok = 26

		//	20	4	 			||	000000010100		000000011110		2 1 1 1 7 0		1 4 7 0 0 0
		//	20	4	1			||	000000010010		000000011011		1 1 2 1 7 0		0 2 1 2 7 0
		//	20	4	1	2041	||	000000010010		000000011011		1 1 2 1 7 0		0 2 1 2 7 0	||	21 + 0 = 21	ok

		//	40	4	 			||	000000101000		000000111100		3 1 1 1 6 0		2 4 6 0 0 0
		//	40	4	1			||	000000100110		000000110101		1 2 2 1 6 0		0 1 1 1 1 2
		//	40	4	1	2041	||	000000100110		000000110101		1 2 2 1 6 0		0 1 1 1 1 2	||	41 + 0 = 41	ok
	}
	else if (vBase2Counts[0]  == 2 && vBase2Counts[1] == 1 && vBase2Counts[2] == 1 && vBase2Counts[3] == 2)											// x	1	1	y	(vBase2Counts)
	{
		vDecrementBase2[vBase2Counts[0]].flip();		// (vDecrementBase2[vBase2Counts])
		vDecrementBase2[vBase2Counts[1]].flip();		// (vDecrementBase2[vBase2Counts])

		bOK = true;
		bReturnBase2 = true;
		nReturn = 2042;	// ok = 

		//	52	4	 			||	000000110100		000000101110		2 1 1 2 6 0		1 3 1 1 6 0
		//	52	4	1			||	000000110010		000000101011		1 1 2 2 6 0		0 2 1 1 1 1
		//	52	4	1	2042	||	000000110010		000000101011		1 1 2 2 6 0		0 2 1 1 1 1	||	53 + 0 = 53	ok
	}
	else if (vBase2Counts[0]  ==  vGrayCounts[0] + 1 && vBase2Counts[1] + 1 == vGrayCounts[1])	
	{
		vDecrementGray[0].flip();
		vDecrementGray[vGrayCounts[0] + 1].flip();
		
		bOK = true;
		bReturnBase2 = false;
		nReturn = 3000;
	}
	else if (vBase2Counts[0] == 0 && vGrayCounts[0] == 0 && vGrayCounts[1] > 2 && vGrayCounts[1] + vBase2Counts[2] + vGrayCounts[3] == vDecrementGray.size())
	{
		vDecrementGray[vGrayCounts[1] - 2].flip();
		vDecrementGray[vGrayCounts[1]].flip();
		
		bOK = true;
		bReturnBase2 = false;
		nReturn = 4000;

		//	3413	11	 			||	110101010101	9 10	101111111111	8 10	0 1 1 1 1 1		0 10 1 1 0 0
		//	3413	11	1			||	101101010101			111011111111			0 1 1 1 1 1		0 8 1 3 0 0
		//	3413	0	0	0		||	000000000000			000000000000			12 0 0 0 0 0	12 0 0 0 0 0	||	3413 + 1 = 3414	error
	}
	else if (vBase2Counts[0] == 1 && vGrayCounts[0] == 0 && vBase2Counts[1] + 1 == vDecrementBase2.size())
	{
		vDecrementBase2[1].flip();
		
		bOK = true;
		bReturnBase2 = true;
		nReturn = 5000;

		//	4094	2	 			||	111111111110	1		100000000001	0 1		1 11 0 0 0 0		0 1 10 1 0 0
		//	4094	2	1			||	111111111100			100000000010			2 10 0 0 0 0		1 1 9 1 0 0
		//	4094	0	0	0		||	000000000000			000000000000			12 0 0 0 0 0		12 0 0 0 0 0	||	4094 + 1 = 4095	error
	}
	else if (vBase2Counts[0] == 0 && vBase2Counts[1] == vDecrementBase2.size())
	{
		vDecrementBase2[vBase2Counts[1] - 1].flip();
		
		bOK = true;
		bReturnBase2 = true;
		nReturn = 6000;

		//	4095	1	 			||	111111111111	11		100000000000	10 11	0 12 0 0 0 0		11 1 0 0 0 0
		//	4095	1	1			||	011111111111			010000000000			0 11 1 0 0 0		10 1 1 0 0 0
		//	4095	0	0	0		||	000000000000			000000000000			12 0 0 0 0 0		12 0 0 0 0 0	||	4095 + 1 = 4096	error
		}

	//reverse(vDecrementGray.begin(), vDecrementGray.end());

	if (bOK && nReturn > 0)
	{
		if (bReturnBase2)
		{
			reverse(vDecrementBase2.begin(), vDecrementBase2.end());
			return vDecrementBase2;
		}
		else
		{
			reverse(vDecrementGray.begin(), vDecrementGray.end());
			return GrayToBase2(vDecrementGray);
		}
	}
	return vZeros;
}

vector<bool> GrayCode::ConfigureBase2ToSameSums(bool& bOK, vector<uint> vTargetSumsLower, vector<uint> vTargetSumsUpper, vector<uint> vGrayStart, vector<uint> vGraySize, vector<bool> vBase2)
{
	IO cIO = IO();
	Intervals cI = Intervals();

	bOK = true;
	vector<bool> vError(vBase2.size(), false);

	uint nTotalGraySum = SumVector(vGraySize);

	if (nTotalGraySum != vBase2.size())
	{
		cout << "\nTotalGraySize != vBase2.size()***Intervals::ConfigureBase2ToSameSums***\n";		// arrange for overlapping intervals - later
		bOK = false;
		return vError;
	}

	if (vGrayStart.size() == vGraySize.size() && vGrayStart.size() == vTargetSumsLower.size() && vGrayStart.size() == vTargetSumsUpper.size())
	{
		vector<bool> vGrayFinal;
		vector<bool> vGray = Base2ToGray(vBase2);

		for (uint n = 0; n < vGrayStart.size(); n++)
		{
			uint nPos = vGrayStart[n];
			uint nSize = vGraySize[n];

			if (nPos + nSize <= (uint)vGray.size())
			{
				vector<bool> vGraySegment;
				vGraySegment.assign(vGray.begin() + nPos, vGray.begin() + nPos + nSize);

				vector<bool> vTempSegment = vGraySegment;

				bool bOKTemp = false;
				vGraySegment = cI.BoundedGraySum(bOKTemp, vTargetSumsLower[n], vTargetSumsUpper[n], vGraySegment);

				if (bOKTemp)
				{
					vGrayFinal.insert(vGrayFinal.end(), vGraySegment.begin(), vGraySegment.end());
				}
				else
				{
					bOK = false;
					uint nSpace0 = 0;
					cout << "***Error: GrayCode::ConfigureBase2ToSameSums ***\n";
					cout << "TempSegment = " << cIO.DumpVector(nSpace0, vTempSegment) << "\t";
					cout << "Segment = " << cIO.DumpVector(nSpace0, vGraySegment) << "\t";
					cout << "Pos = " << nPos << "\tSize = " << nSize << "\tPos + Size = " << nPos + nSize << "\t";
					cout << "Lower = " << vTargetSumsLower[n] << "\t" << "Upper = " << vTargetSumsUpper[n] << "\t";
					cout << "n = " << n << "\n\n";
					return vError;
				}
			}
		}
		return GrayToBase2(vGrayFinal);
	}
	else
	{
		cout << "\nvGrayStart.size() == vGraySize.size() && vGrayStart.size() == vTargetSumsLower.size() && vGrayStart.size() == vTargetSumsUpper.size()***Intervals::ConfigureBase2ToSameSums***\n";		// arrange for overlapping intervals - later
		bOK = false;
		return vError;
	}
	return vError;
}

map<vector<bool>, vector<uint>> GrayCode::ConfigureMapToSameSums(vector<uint> vTargetSumsLower, vector<uint> vTargetSumsUpper, vector<uint> vGrayStart, vector<uint> vGraySize, map<vector<bool>, vector<uint>> m)
{
	//cout << "\n\n";

	map<vector<bool>, vector<uint>> mSameSums;
	map<vector<bool>, vector<uint> >::iterator i;
	uint nCount = 0;
	for (i = m.begin(); i != m.end(); i++)
	{
		bool bAllOK = true;
		vector<bool> vBase2 = i->first;
		vector<uint> vIndexClass = i->second;

		//cout << vIndexClass[0] << " ";
		//cout << "\nMap Count = " << nCount << " of " << m.size() << "\n";

		bool bOK = false;
		vBase2 = ConfigureBase2ToSameSums(bOK, vTargetSumsLower, vTargetSumsUpper, vGrayStart, vGraySize, vBase2);

		//cout << bOK;

		if (bOK)
		{
			mSameSums.insert(make_pair(vBase2, vIndexClass));
		}
		nCount++;
		if (nCount % 100 == 0)
			cout << nCount << " ";
	}
	cout << "\n";
	return mSameSums;
}

vector<bool> GrayCode::MaxIterativePointBase2(vector<bool> v1, vector<bool> v2)
{
	vector<bool> vMaxIterativeBase2(v1.size(), false);

	if (v1 < v2 && v1.size() == v2.size())
	{
		bool bAlternate = false;	
		bool bPrevious  = false;	// this alternates
		bool bEqualLeft = true;		// all equal up to here

		for (uint n = 0; n < v1.size(); n++) 
		{
			if (bEqualLeft && v1[n] == v2[n])
			{
				vMaxIterativeBase2[n] = v1[n];
			}
			else if (bEqualLeft && !v1[n] && v2[n])	//  this should be the first occurrence of this
			{
				bEqualLeft = false;
			}
			else if (!bEqualLeft && !bAlternate && v1[n])
			{
				vMaxIterativeBase2[n] = true;
			}
			else if (!bEqualLeft && !bAlternate && !v1[n])
			{
				bPrevious = true;
				bAlternate = true;
				vMaxIterativeBase2[n] = true;
			}
			else if (bAlternate && bPrevious)
			{
				bPrevious = false;
				vMaxIterativeBase2[n] = false;
			}
			else if (bAlternate && !bPrevious)
			{
				bPrevious = true;
				vMaxIterativeBase2[n] = true;
			}
		}
	}
	return vMaxIterativeBase2;
}

bool GrayCode::IncrementBitCountsGray(vector<bool> vGray, vector<uint>& vBitCounts)
{
	if (vGray.size() != vBitCounts.size()) return false;

	for (uint n = 0; n < vGray.size(); n++)
	{
		if (vGray[n])
			vBitCounts[n]++;
	}
	return true;
}

vector<uint> GrayCode::GetBitCounts(uint nBits, map<vector<bool>, vector<uint> > mGray)
{	// only counting bits in gray format
	vector<uint> vBitCounts(nBits, 0);

	map<vector<bool>, vector<uint> > ::iterator i;
	for (i = mGray.begin(); i != mGray.end(); i++)
		IncrementBitCountsGray(i->first, vBitCounts);

	return vBitCounts;
}

map<uint, vector<uint>> GrayCode::BitCountOrder(vector<uint> vBitCounts)
{
	vector<uint> vCount(1, 0);
	map<uint, vector<uint>> m;
	pair< map< uint, vector<uint> > ::iterator, bool > pr;
	for (uint n = 0; n < vBitCounts.size(); n++)
	{
		vector<uint> vCount(1, n);
		pr = m.insert(make_pair(vBitCounts[n], vCount));
		if (!pr.second)
			pr.first->second.push_back(n);
	}
	return m;
}

vector<uint> GrayCode::GetFinalBitCountOrder(map<uint, vector<uint>> m)
{
	vector<uint> vFinalBitCountOrder;

	map<uint, vector<uint> >::iterator i;
	for (i = m.begin(); i != m.end(); i++)
	{
		vFinalBitCountOrder.insert(vFinalBitCountOrder.end(), i->second.begin(), i->second.end());
	}

	return vFinalBitCountOrder;
}

vector<bool> GrayCode::ReOrderGray(vector<uint> vOrder, vector<bool> v)
{
	vector<bool> vReOrder = v;
	for (uint n = 0; n < vOrder.size(); n++)
	{
		uint nPos = vOrder[n];
		if (nPos < v.size())
		{
			vReOrder[n] = v[nPos];
		}
	}
	return vReOrder;
}

map<vector<bool>, vector<uint>> GrayCode::ReOrderGray(vector<uint> vOrder, map<vector<bool>, vector<uint>> m)
{
	map< vector<bool>, vector<uint> >mReOrder;

	map< vector<bool>, vector<uint> >::iterator i;
	for (i = m.begin(); i != m.end(); i++)
	{
		vector<bool> vGray = i->first;
		vector<bool> vGrayReOrdered = ReOrderGray(vOrder, vGray);
		mReOrder.insert(make_pair(vGrayReOrdered, i->second));
	}
	return mReOrder;
}

map<uint, vector<uint>> GrayCode::HilbertCurve(uint nDimensions, uint nBitsPerDimension)
{
	map<uint, vector<uint>> mHilbert;
	uint nTotalBits = nDimensions * nBitsPerDimension;

	vector<bool> vStart(nTotalBits, false);
	vector<bool> vStop(nTotalBits, true);

	for (vector<bool> vBase2 = vStart; vBase2 <= vStop; vBase2 = IncrementBase2(vBase2))
	{
		uint nBase10 = Base2ToBase10(vBase2);
		vector<bool> vGray = Base2ToGray(vBase2);
		vector<bool> vGrayCoordinates = GrayCodeToGrayCoordinates(nBitsPerDimension, nDimensions, vGray);
		vector<uint> vBase10 = GrayCoordinatesToBase10Coordinates(nBitsPerDimension, nDimensions, vGrayCoordinates);

		mHilbert.insert(make_pair(nBase10, vBase10));

		if (vBase2 == vStop)
			break;
	}
	return mHilbert;
}

uint GrayCode::FindKey(uint nIndex, uint nClass, map<uint, vector<uint>> m)
{
	map<uint, vector<uint>>::iterator i;
	for (i = m.begin(); i != m.end(); i++)
	{
		vector<uint> vIndexClass = i->second;
		if (vIndexClass.size() > 1)
		{
			if (vIndexClass[0] == nIndex && vIndexClass[1] == nClass)
				return i->first;
		}
	}
	return uint();
}

vector<bool> GrayCode::FindKey(uint nIndex, uint nClass, map<vector<bool>, vector<uint>> m)
{
	map<vector<bool>, vector<uint>>::iterator i;
	for (i = m.begin(); i != m.end(); i++)
	{
		vector<uint> vIndexClass = i->second;
		if (vIndexClass.size() > 1)
		{
			if (vIndexClass[0] == nIndex && vIndexClass[1] == nClass)
				return i->first;
		}
	}
	return vector<bool>();
}

vector<bool> GrayCode::FindKeyFromIndex(uint nIndexPosition, uint nClassPosition, uint nIndex, uint& nClass, map<vector<bool>, vector<uint>> m)
{
	map<vector<bool>, vector<uint>>::iterator i;
	for (i = m.begin(); i != m.end(); i++)
	{
		vector<uint> vIndexClass = i->second;
		if (vIndexClass.size() > nIndexPosition && vIndexClass.size() > nClassPosition)
		{
			if (vIndexClass[nIndexPosition] == nIndex)
			{
				nClass = vIndexClass[nClassPosition];
				return i->first;
			}
		}
	}
	return vector<bool>();
}

vector<bool> GrayCode::Vector28x28To32x32(vector<bool> v28x28)
{
	vector<bool> v32x32(32 * 32, false);

	if (v28x28.size() == 28 * 28)
	{
		uint nPos = 32 + 32 + 2;
		for (uint n = 0; n < 28 * 28; n++)
		{
			v32x32[nPos] = v28x28[n];

			if ((n + 1) % 28 == 0)
			{
				nPos += 4;
			}
			nPos++;
		}
	}
	return v32x32;
}

map<vector<bool>, vector<uint>> GrayCode::Map28x28To32x32(map<vector<bool>, vector<uint>> m28x28)
{
	map<vector<bool>, vector<uint>> m32x32;
	map<vector<bool>, vector<uint>>::iterator i;
	for (i = m28x28.begin(); i != m28x28.end(); i++)
	{
		vector<bool> v28x28 = i->first;
		vector<bool> v32x32 = Vector28x28To32x32(v28x28);
		m32x32.insert(make_pair(v32x32, i->second));
	}
	return m32x32;
}

vector<bool> GrayCode::Gray32x32ToHilbert(vector<bool> vGray32x32)
{
	uint nHilbertDimensions = 2;
	uint nHilbertBitsPerDimension = 5;
	map<uint, vector<uint>> mHilbert = HilbertCurve(nHilbertDimensions, nHilbertBitsPerDimension);
	vector<bool> vGrayHilbert(32 * 32, false);

	for (uint y = 0; y < 32; y++)
	{
		for (uint x = 0; x < 32; x++)
		{
			uint nPosXY = x + (y * 32);
			uint nPosHilbert = FindKey(x, y, mHilbert);

			vGrayHilbert[nPosHilbert] = vGray32x32[nPosXY];
		}
	}
	return vGrayHilbert;
}

map<vector<bool>, vector<uint>> GrayCode::GetFocusSubSet(uint nFocusClass, uint nClassPosition, map<vector<bool>, vector<uint>> m)
{
	map<vector<bool>, vector<uint> > mSubSet;

	map<vector<bool>, vector<uint> >::iterator i;
	for (i = m.begin(); i != m.end(); i++)
	{
		if (i->second[nClassPosition] == nFocusClass && nClassPosition < i->second.size())
			mSubSet.insert(make_pair(i->first, i->second));
	}
	return mSubSet;
}

map<vector<bool>, vector<uint>> GrayCode::GetNotFocusSubSet(uint nFocusClass, uint nClassPosition, map<vector<bool>, vector<uint>> m)
{
	map<vector<bool>, vector<uint> > mSubSet;

	map<vector<bool>, vector<uint> >::iterator i;
	for (i = m.begin(); i != m.end(); i++)
	{
		if (i->second[nClassPosition] != nFocusClass && nClassPosition < i->second.size())
			mSubSet.insert(make_pair(i->first, i->second));
	}
	return mSubSet;
}

map<vector<bool>, vector<uint>> GrayCode::BinaryClassOutput(uint nFocusClass, uint nClassPosition, map<vector<bool>, vector<uint>> m)
{
	map<vector<bool>, vector<uint>>::iterator i;
	map<vector<bool>, vector<uint>> mBinaryClass;
	for (i = m.begin(); i != m.end(); i++)
	{
		if (nClassPosition < i->second.size())
		{
			if (i->second[nClassPosition] == nFocusClass)
			{
				i->second[nClassPosition] = 1;
			}
			else
			{
				i->second[nClassPosition] = 0;
			}
		}

		mBinaryClass.insert(make_pair(i->first, i->second));
	}
	return mBinaryClass;
}

map<vector<bool>, vector<uint>> GrayCode::BinaryIndexOutput(uint nFocusIndex, uint nIndexPosition, uint nClassPosition, map<vector<bool>, vector<uint>> m)
{
	map<vector<bool>, vector<uint>>::iterator i;
	map<vector<bool>, vector<uint>> mBinaryClass;
	for (i = m.begin(); i != m.end(); i++)
	{
		if (nIndexPosition < i->second.size() && nClassPosition < i->second.size())
		{
			if (i->second[nIndexPosition] == nFocusIndex)
			{
				i->second[nClassPosition] = 1;
			}
			else
			{
				i->second[nClassPosition] = 0;
			}
		}
		mBinaryClass.insert(make_pair(i->first, i->second));
	}
	return mBinaryClass;
}
