PixelNeighbors::PixelNeighbors(int width, int height, const Mask& mask, Mask::Value maskValidNeighborValue, int x, int y)
		: m_hasTop(y > 0 && mask.GetValue(x, y - 1) == maskValidNeighborValue)
		, m_hasBottom(y < height - 1 && mask.GetValue(x, y + 1) == maskValidNeighborValue)
		, m_hasLeft(x > 0 && mask.GetValue(x - 1, y) == maskValidNeighborValue)
		, m_hasRight(x < width - 1 && mask.GetValue(x + 1, y) == maskValidNeighborValue)
	{
		CacheNum();
	}
	void AAndBVars::Evaluate(const ImageFloat& inputImage, const Mask& mask, const UnknownVars& unknownVars, int x, int y, PixelFloat& inOutPixel, const unsigned int variableId)
	{
		wxASSERT(x >= 0);
		wxASSERT(y >= 0);
		wxASSERT(x < inputImage.GetWidth());
		wxASSERT(y < inputImage.GetHeight());
		if (mask.GetValue(x, y) == Mask::UNKNOWN)
		{
			// Unknown pixel
			for (int component = 0; component < LfnIc::PixelFloat::NUM_CHANNELS; ++component)
			{
				m_a.insert(variableId + unknownVars.GetNum() * component, unknownVars.GetIndex(x,y) + unknownVars.GetNum() * component) = 1.0f;
			}
		}
		else
		{
			// Known pixel
			inOutPixel -= inputImage.GetPixel(x, y);
		}
	}
	UnknownVars::UnknownVars(int width, int height, const Mask& mask)
		: m_width(width)
		, m_height(height)
	{
		wxASSERT(m_width <= USHRT_MAX);
		wxASSERT(m_height <= USHRT_MAX);

		int i = 0;
		for (int y = 0; y < height; ++y)
		{
			for (int x = 0; x < width; ++x)
			{
				if (mask.GetValue(x, y) == Mask::UNKNOWN)
				{
					m_xyToUnknownIndexMap[GetKeyFromXy(x, y)] = i++;
				}
			}
		}

		m_u.resize(GetNum() * LfnIc::PixelFloat::NUM_CHANNELS, 1);
	}
	AAndBVars::AAndBVars(const ImageFloat& inputImage, const Mask& mask, const BVarInitializer& bVarInitializer, const UnknownVars& unknownVars)
	{
		// The A matrix is 3N * 3N where N is the number of masked pixels
		m_a.resize(unknownVars.GetNum() * LfnIc::PixelFloat::NUM_CHANNELS, unknownVars.GetNum() * LfnIc::PixelFloat::NUM_CHANNELS);

		// The 'b' values
		m_b.resize(unknownVars.GetNum() * LfnIc::PixelFloat::NUM_CHANNELS, 1);

		const int width = inputImage.GetWidth();
		const int height = inputImage.GetHeight();

		for (int y = 0; y < height; ++y)
		{
			for (int x = 0; x < width; ++x)
			{
				if (mask.GetValue(x, y) == Mask::UNKNOWN)
				{
					const PixelNeighbors neighbors(width, height, x, y);

					PixelFloat pixel;
					bVarInitializer.GetInitialValue(x, y, pixel);

					const int unknownIndex = unknownVars.GetIndex(x, y);

					Evaluate(neighbors.HasTop(), inputImage, mask, unknownVars, x, y - 1, pixel, unknownIndex);
					Evaluate(neighbors.HasLeft(), inputImage, mask, unknownVars, x - 1, y, pixel, unknownIndex);
					Evaluate(neighbors.HasRight(), inputImage, mask, unknownVars, x + 1, y, pixel, unknownIndex);
					Evaluate(neighbors.HasBottom(), inputImage, mask, unknownVars, x, y + 1, pixel, unknownIndex);

					// This is the center pixel, so the corresponding entry should be on the diagonal
					for (int component = 0; component < LfnIc::PixelFloat::NUM_CHANNELS; ++component)
					{
						m_a.insert(unknownIndex + unknownVars.GetNum() * component, unknownIndex + unknownVars.GetNum() * component) = -neighbors.GetNum();
						m_b(unknownIndex + unknownVars.GetNum() * component) = pixel.channel[component];
					}

				}
			}
		}
	}
	void WriteOutput(
		const UnknownVars& unknownVars,
		const Mask& mask,
		ImageFloat& inputOutputImage,
		int translateSolutionX,
		int translateSolutionY)
	{
		const int srcWidth = unknownVars.GetWidth();
		const int srcHeight = unknownVars.GetHeight();
		const int outputWidth = inputOutputImage.GetWidth();
		const int outputHeight = inputOutputImage.GetHeight();
		const int numUnknownVars = unknownVars.GetNum();

		// Convert solution vector back to image
		for (int y = 0; y < outputHeight; ++y)
		{
			for (int x = 0; x < outputWidth; ++x)
			{
				const int srcX = x - translateSolutionX;
				const int srcY = y - translateSolutionY;
				if (srcX >= 0 && srcY >= 0 && srcX < srcWidth && srcY < srcHeight)
				{
					if (mask.GetValue(srcX, srcY) == Mask::UNKNOWN)
					{
						const int i = unknownVars.GetIndex(srcX, srcY);
						PixelFloat p;
						for (int component = 0; component < PixelFloat::NUM_CHANNELS; ++component)
						{
							p.channel[component] = unknownVars.GetFloatClamped0To1(i + numUnknownVars * component);
						}
						inputOutputImage.SetPixel(x, y, p);
					}
				}
			}
		}
	}
	void Cloner::UpdateLaplacian(
		const ImageFloat& sourceImage,
		const Mask& mask,
		int sourceOffsetX,
		int sourceOffsetY)
	{
		const int sourceWidth = sourceImage.GetWidth();
		const int sourceHeight = sourceImage.GetHeight();
		const int sourceImageTranslatedWidth = m_sourceImageTranslated.GetWidth();
		const int sourceImageTranslatedHeight = m_sourceImageTranslated.GetHeight();

		wxASSERT(sourceImageTranslatedWidth == m_laplacian.GetWidth());
		wxASSERT(sourceImageTranslatedHeight == m_laplacian.GetHeight());

		// Reset m_laplacianMask to all Mask::KNOWN.
		{
			for (int y = m_sourceImageTranslatedRect.y, ny = y + m_sourceImageTranslatedRect.height; y < ny; ++y)
			{
				for (int x = m_sourceImageTranslatedRect.x, nx = x + m_sourceImageTranslatedRect.width; x < nx; ++x)
				{
					m_laplacianMask.SetValue(x, y, Mask::KNOWN);
				}
			}

#if _DEBUG
			for (int y = 0; y < sourceImageTranslatedHeight; ++y)
			{
				for (int x = 0; x < sourceImageTranslatedWidth; ++x)
				{
					wxASSERT(m_laplacianMask.GetValue(x, y) == Mask::KNOWN);
				}
			}
#endif
		}

		// Set m_sourceImageTranslatedRect
		{
			m_sourceImageTranslatedRect = wxRect(sourceOffsetX, sourceOffsetY, sourceWidth, sourceHeight);
			m_sourceImageTranslatedRect.Intersect(wxRect(0, 0, sourceImageTranslatedWidth, sourceImageTranslatedHeight));
		}

		// Copy the source into m_sourceImageTranslated at the source offset,
		// and translate the source mask into m_laplacianMask.
		for (int y = 0; y < sourceImageTranslatedHeight; ++y)
		{
			for (int x = 0; x < sourceImageTranslatedWidth; ++x)
			{
				const int translatedX = x - sourceOffsetX;
				const int translatedY = y - sourceOffsetY;
				if (translatedX >= 0 && translatedY >= 0 && translatedX < sourceWidth && translatedY < sourceHeight)
				{
					const int sourceIndex = LfnTech::GetRowMajorIndex(sourceWidth, translatedX, translatedY);
					const int translatedIndex = LfnTech::GetRowMajorIndex(sourceImageTranslatedWidth, x, y);
					m_sourceImageTranslated.GetData()[translatedIndex] = sourceImage.GetData()[sourceIndex];
					m_laplacianMask.SetValue(x, y, mask.GetValue(translatedX, translatedY));
				}
			}
		}

		// Compute the laplacian from the translated source image.
		for (int y = 0; y < sourceImageTranslatedHeight; ++y)
		{
			for (int x = 0; x < sourceImageTranslatedWidth; ++x)
			{
				// Only interested in computing the laplacian of the unknown
				// pixels from the translated source.
				const PixelNeighbors neighbors(sourceImageTranslatedWidth, sourceImageTranslatedHeight, m_laplacianMask, Mask::UNKNOWN, x, y);

				if (m_laplacianMask.GetValue(x, y) == Mask::UNKNOWN || neighbors.GetNum() > 0)
				{
					PixelFloat rgb = m_sourceImageTranslated.GetPixel(x, y);
					rgb *= float(-neighbors.GetNum());

					if (neighbors.HasLeft())
					{
						rgb += m_sourceImageTranslated.GetPixel(x - 1, y);
					}
					if (neighbors.HasRight())
					{
						rgb += m_sourceImageTranslated.GetPixel(x + 1, y);
					}
					if (neighbors.HasTop())
					{
						rgb += m_sourceImageTranslated.GetPixel(x, y - 1);
					}
					if (neighbors.HasBottom())
					{
						rgb += m_sourceImageTranslated.GetPixel(x, y + 1);
					}

					m_laplacian.SetPixel(x, y, rgb);
				}
			}
		}
	}