namespace Gma.QrCodeNet.Encoding.EncodingRegion;

/// <summary>
/// Embed version information for version larger than or equal to 7.
/// </summary>
/// <remarks>ISO/IEC 18004:2000 Chapter 8.10 Page 54</remarks>
internal static class VersionInformation
{
    private const int VIRectangleHeight = 3;
    private const int VIRectangleWidth = 6;

    private const int LengthDataBits = 6;
    private const int LengthECBits = 12;
    private const int VersionBCHPoly = 0x1f25;

    /// <summary>
    /// Embed version information to Matrix
    /// Only for version greater than or equal to 7
    /// </summary>
    internal static void EmbedVersionInformation(this TriStateMatrix tsMatrix, int version)
    {
        if (version < 7)
        {
            return;
        }

        BitList versionInfo = VersionInfoBitList(version);

        int matrixWidth = tsMatrix.Width;

        // 1 cell between version info and position stencil
        int shiftLength = QRCodeConstantVariable.PositionStencilWidth + VIRectangleHeight + 1;

        // Reverse order input
        int viIndex = LengthDataBits + LengthECBits - 1;

        for (int viWidth = 0; viWidth < VIRectangleWidth; viWidth++)
        {
            for (int viHeight = 0; viHeight < VIRectangleHeight; viHeight++)
            {
                bool bit = versionInfo[viIndex];
                viIndex--;

                // Bottom left
                tsMatrix[viWidth, (matrixWidth - shiftLength + viHeight), MatrixStatus.NoMask] = bit;

                // Top right
                tsMatrix[(matrixWidth - shiftLength + viHeight), viWidth, MatrixStatus.NoMask] = bit;
            }
        }
    }

    private static BitList VersionInfoBitList(int version)
    {
        BitList result = new()
        {
            { version, LengthDataBits },
            { BCHCalculator.CalculateBCH(version, VersionBCHPoly), LengthECBits }
        };

        if (result.Count != (LengthECBits + LengthDataBits))
        {
            throw new Exception("Version Info creation error. Result is not 18 bits");
        }

        return result;
    }
}