namespace Gma.QrCodeNet.Encoding.Masking.Scoring
{
	/// <summary>
	/// ISO/IEC 18004:2000 Chapter 8.8.2 Page 52
	/// </summary>
	internal class Penalty3 : Penalty
	{
		/// <summary>
		/// Calculate penalty value for Third rule.
		/// </summary>
		internal override int PenaltyCalculate(BitMatrix matrix) => PenaltyCalculation(matrix, true) + PenaltyCalculation(matrix, false);

		private int PenaltyCalculation(BitMatrix matrix, bool isHorizontal)
		{
			int i = 0;
			int j = 1;
			int penalty = 0;
			int width = matrix.Width;
			bool bit;
			while (i < width)
			{
				while (j < width - 5)
				{
					bit = isHorizontal
						? matrix[j + 4, i]
						: matrix[i, j + 4];
					if (!bit)
					{
						bit = isHorizontal
							? matrix[j, i]
							: matrix[i, j];
						if (!bit)
						{
							penalty += PatternCheck(matrix, i, j, isHorizontal);
							j += 4;
						}
						else
						{
							j += 4;
						}
					}
					else
					{
						for (int num = 4; num > 0; num--)
						{
							bit = isHorizontal
								? matrix[j + num, i]
								: matrix[i, j + num];
							if (!bit)
							{
								j += num;
								break;
							}
							if (num == 1)
							{
								j += 5;
							}
						}
					}
				}
				j = 0;
				i++;
			}
			return penalty;
		}

		private int PatternCheck(BitMatrix matrix, int i, int j, bool isHorizontal)
		{
			bool bit;
			for (int num = 3; num >= 1; num--)
			{
				bit = isHorizontal
					? matrix[j + num, i]
					: matrix[i, j + num];
				if (!bit)
				{
					return 0;
				}
			}

			// Check for left side and right side x ( xoxxxox ).
			if ((j - 1) < 0 || (j + 1) >= matrix.Width)
			{
				return 0;
			}

			bit = isHorizontal
				? matrix[j + 5, i]
				: matrix[i, j + 5];
			if (!bit)
			{
				return 0;
			}

			bit = isHorizontal
				? matrix[j - 1, i]
				: matrix[i, j - 1];
			if (!bit)
			{
				return 0;
			}

			if ((j - 5) >= 0)
			{
				for (int num = -2; num >= -5; num--)
				{
					bit = isHorizontal
						? matrix[j + num, i]
						: matrix[i, j + num];
					if (bit)
					{
						break;
					}

					if (num == -5)
					{
						return 40;
					}
				}
			}

			if ((j + 9) < matrix.Width)
			{
				for (int num = 6; num <= 9; num++)
				{
					bit = isHorizontal
						? matrix[j + num, i]
						: matrix[i, j + num];
					if (bit)
					{
						return 0;
					}
				}
				return 40;
			}
			else
			{
				return 0;
			}
		}
	}
}
