namespace Gma.QrCodeNet.Encoding.ReedSolomon;

/// <summary>
/// Description of GeneratorPolynomial.
/// </summary>
internal sealed class GeneratorPolynomial
{
    /// <summary>
    /// After create GeneratorPolynomial. Keep it as long as possible.
    /// Unless QRCode encode is done or no more QRCode need to generate.
    /// </summary>
    internal GeneratorPolynomial(GaloisField256 gfield)
    {
        Gfield = gfield;
        CacheGenerator = new List<Polynomial>(10)
            {
                new Polynomial(Gfield, new int[] { 1 })
            };
    }

    private GaloisField256 Gfield { get; }

    private List<Polynomial> CacheGenerator { get; }

    /// <summary>
    /// Get generator by degree. (Largest degree for that generator)
    /// </summary>
    /// <returns>Generator</returns>
    internal Polynomial GetGenerator(int degree)
    {
        if (degree >= CacheGenerator.Count)
        {
            BuildGenerator(degree);
        }

        return CacheGenerator[degree];
    }

    /// <summary>
    /// Build Generator if we cannot find specific degree of generator from cache
    /// </summary>
    private void BuildGenerator(int degree)
    {
        lock (CacheGenerator)
        {
            int currentCacheLength = CacheGenerator.Count;
            if (degree >= currentCacheLength)
            {
                Polynomial lastGenerator = CacheGenerator[currentCacheLength - 1];

                for (int d = currentCacheLength; d <= degree; d++)
                {
                    Polynomial nextGenerator = lastGenerator.Multiply(new Polynomial(Gfield, new int[] { 1, Gfield.Exponent(d - 1) }));
                    CacheGenerator.Add(nextGenerator);
                    lastGenerator = nextGenerator;
                }
            }
        }
    }
}