/// <summary> <p>This is called when a horizontal scan finds a possible alignment pattern. It will
        /// cross check with a vertical scan, and if successful, will see if this pattern had been
        /// found on a previous horizontal scan. If so, we consider it confirmed and conclude we have
        /// found the alignment pattern.</p>
        ///
        /// </summary>
        /// <param name="stateCount">reading state module counts from horizontal scan
        /// </param>
        /// <param name="i">row where alignment pattern may be found
        /// </param>
        /// <param name="j">end of possible alignment pattern in row
        /// </param>
        /// <returns> {@link AlignmentPattern} if we have found the same pattern twice, or null if not
        /// </returns>
        private AlignmentPattern handlePossibleCenter(int[] stateCount, int i, int j)
        {
            int   stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2];
            float?centerJ         = centerFromEnd(stateCount, j);

            if (centerJ == null)
            {
                return(null);
            }
            float?centerI = crossCheckVertical(i, (int)centerJ, 2 * stateCount[1], stateCountTotal);

            if (centerI != null)
            {
                float estimatedModuleSize = (stateCount[0] + stateCount[1] + stateCount[2]) / 3.0f;
                foreach (var center in possibleCenters)
                {
                    // Look for about the same center and module size:
                    if (center.aboutEquals(estimatedModuleSize, centerI.Value, centerJ.Value))
                    {
                        return(center.combineEstimate(centerI.Value, centerJ.Value, estimatedModuleSize));
                    }
                }
                // Hadn't found this before; save it
                var point = new AlignmentPattern(centerJ.Value, centerI.Value, estimatedModuleSize);
                possibleCenters.Add(point);
                if (resultPointCallback != null)
                {
                    resultPointCallback(point);
                }
            }
            return(null);
        }
        /// <summary> <p>This method attempts to find the bottom-right alignment pattern in the image. It is a bit messy since
        /// it's pretty performance-critical and so is written to be fast foremost.</p>
        ///
        /// </summary>
        /// <returns> {@link AlignmentPattern} if found
        /// </returns>
        internal AlignmentPattern find()
        {
            int startX  = this.startX;
            int height  = this.height;
            int maxJ    = startX + width;
            int middleI = startY + (height >> 1);

            // We are looking for black/white/black modules in 1:1:1 ratio;
            // this tracks the number of black/white/black modules seen so far
            int[] stateCount = new int[3];
            for (int iGen = 0; iGen < height; iGen++)
            {
                // Search from middle outwards
                int i = middleI + ((iGen & 0x01) == 0 ? ((iGen + 1) >> 1) : -((iGen + 1) >> 1));
                stateCount[0] = 0;
                stateCount[1] = 0;
                stateCount[2] = 0;
                int j = startX;
                // Burn off leading white pixels before anything else; if we start in the middle of
                // a white run, it doesn't make sense to count its length, since we don't know if the
                // white run continued to the left of the start point
                while (j < maxJ && !image[j, i])
                {
                    j++;
                }
                int currentState = 0;
                while (j < maxJ)
                {
                    if (image[j, i])
                    {
                        // Black pixel
                        if (currentState == 1)
                        {
                            // Counting black pixels
                            stateCount[1]++;
                        }
                        else
                        {
                            // Counting white pixels
                            if (currentState == 2)
                            {
                                // A winner?
                                if (foundPatternCross(stateCount))
                                {
                                    // Yes
                                    AlignmentPattern confirmed = handlePossibleCenter(stateCount, i, j);
                                    if (confirmed != null)
                                    {
                                        return(confirmed);
                                    }
                                }
                                stateCount[0] = stateCount[2];
                                stateCount[1] = 1;
                                stateCount[2] = 0;
                                currentState  = 1;
                            }
                            else
                            {
                                stateCount[++currentState]++;
                            }
                        }
                    }
                    else
                    {
                        // White pixel
                        if (currentState == 1)
                        {
                            // Counting black pixels
                            currentState++;
                        }
                        stateCount[currentState]++;
                    }
                    j++;
                }
                if (foundPatternCross(stateCount))
                {
                    AlignmentPattern confirmed = handlePossibleCenter(stateCount, i, maxJ);
                    if (confirmed != null)
                    {
                        return(confirmed);
                    }
                }
            }

            // Hmm, nothing we saw was observed and confirmed twice. If we had
            // any guess at all, return it.
            if (possibleCenters.Count != 0)
            {
                return(possibleCenters[0]);
            }

            return(null);
        }