internal static void FillMatrix(int[,] matrix, MatrixCell startupCell)
        {
            var currentCell = startupCell;
            var dirIndex = 0;

            while (IsCellPassable(matrix, currentCell))
            {
                matrix[currentCell.X, currentCell.Y] = currentCell.Value;

                while (!IsNextCellPassable(matrix, currentCell, dirIndex) &&
                       CanCellMoveSomewhere(matrix, currentCell, dirIndex))
                {
                    dirIndex = (dirIndex + 1) % DirX.Length;
                }

                currentCell.X += DirX[dirIndex];
                currentCell.Y += DirY[dirIndex];
                currentCell.Value++;
            }

            var nextStartupCell = FindFirstAvailableCell(matrix);
            if (nextStartupCell == null)
            {
                return;
            }

            nextStartupCell.Value = currentCell.Value;
            FillMatrix(matrix, nextStartupCell);
        }
        List<MatrixCell> _Items;			// list of MatrixCell

		public MatrixCells(ReportDefn r, ReportLink p, XmlNode xNode) : base(r, p)
		{
			MatrixCell m;
            _Items = new List<MatrixCell>();
			// Loop thru all the child nodes
			foreach(XmlNode xNodeLoop in xNode.ChildNodes)
			{
				if (xNodeLoop.NodeType != XmlNodeType.Element)
					continue;
				switch (xNodeLoop.Name)
				{
					case "MatrixCell":
						m = new MatrixCell(r, this, xNodeLoop);
						break;
					default:	
						m=null;		// don't know what this is
						// don't know this element - log it
						OwnerReport.rl.LogError(4, "Unknown MatrixCells element '" + xNodeLoop.Name + "' ignored.");
						break;
				}
				if (m != null)
					_Items.Add(m);
			}
			if (_Items.Count == 0)
				OwnerReport.rl.LogError(8, "For MatrixCells at least one MatrixCell is required.");
			else
                _Items.TrimExcess();
		}
        private static bool IsCellPassable(int[,] matrix, MatrixCell currentCell)
        {
            var isCellPassable = currentCell.X >= 0 && currentCell.X < matrix.GetLongLength(0) &&
                                 currentCell.Y >= 0 && currentCell.Y < matrix.GetLongLength(1) &&
                                 matrix[currentCell.X, currentCell.Y] == 0;

            return isCellPassable;
        }
        private static bool IsNextCellPassable(int[,] matrix, MatrixCell currentCell, int dirIndex)
        {
            var nextCell = new MatrixCell
            {
                X = currentCell.X + DirX[dirIndex],
                Y = currentCell.Y + DirY[dirIndex]
            };

            return IsCellPassable(matrix, nextCell);
        }
        private static bool CanCellMoveSomewhere(int[,] matrix, MatrixCell currentCell, int dirIndex)
        {
            for (var i = 0; i < DirX.Length; i++)
            {
                dirIndex = (dirIndex + 1) % DirX.Length;

                if (IsNextCellPassable(matrix, currentCell, dirIndex))
                {
                    return true;
                }
            }

            return false;
        }
        internal static MatrixCell FindFirstAvailableCell(int[,] matrix)
        {
            for (var row = 0; row < matrix.GetLength(0); row++)
            {
                for (var col = 0; col < matrix.GetLength(0); col++)
                {
                    if (matrix[row, col] == 0)
                    {
                        var firstEmptyCell = new MatrixCell(row, col);
                        return firstEmptyCell;
                    }
                }
            }

            return null;
        }
        /// <summary>
        /// Sets the bits in the region starting at location and having 
        /// given width and height
        /// </summary>
        /// <param name="location">Top Left of the the Region</param>
        /// <param name="width">Width of the Region</param>
        /// <param name="height">Height of the Region</param>
        internal void SetRegion(MatrixCell location, int width, int height)
        {
            if (BitOrientation == Orientation.Horizontal)
            {
                // Optimization: If the region is only 1 bit wide and high
                if ((width == 1) && (height == 1))
                {
                    this[location.Row, location.Col] = true;
                    return;
                }

                for (var row = 0; row < height; row++)
                {
                    for (var col = 0; col < width; col++)
                    {
                        this[location.Row + row, location.Col + col] = true;
                    }
                }
            }
            // Interchange Row & Column and width & height if the BitOrientation is Vertical
            else
            {
                // Optimization: If the region is only 1 bit wide and high
                if ((width == 1) && (height == 1))
                {
                    this[location.Col, location.Row] = true;
                    return;
                }

                for (var row = 0; row < width; row++)
                {
                    for (var col = 0; col < height; col++)
                    {
                        this[location.Col + row, location.Row + col] = true;
                    }
                }
            }
        }
        /// <summary>
        /// Finds the next empty region of given width and height starting
        /// from the startIndex row
        /// </summary>
        /// <param name="startIndex">The row to start the search from</param>
        /// <param name="width">Width of the Region</param>
        /// <param name="height">Height of the Region</param>
        /// <returns></returns>
        internal MatrixCell FindRegion(long startIndex, int width, int height)
        {
            // Swap width and height if the BitOrientation is Vertical
            if ((BitOrientation == Orientation.Vertical) && (width != height))
            {
                var temp = width;
                width = height;
                height = temp;
            }

            var invalidCell = new MatrixCell(-1, -1);

            if (startIndex < 0 || startIndex >= _rowsInternal)
                throw new ArgumentOutOfRangeException(nameof(startIndex));

            if (startIndex + (height - 1) >= _rowsInternal)
                throw new ArgumentOutOfRangeException(nameof(width), $"Cannot fit item having height of {height} rows in {_rowsInternal - startIndex} rows!");

            if ((width < 1) || (width > 60))
                throw new ArgumentOutOfRangeException(nameof(width), $"Length of the item must be in the range 1 - {MaxBitsPerItem}!");

            if (width > _columnsInternal)
                throw new ArgumentOutOfRangeException(nameof(width), $"Length cannot be greater than number of columns in the BitMatrix!");

            // Optimization: If both width and height are 1 then use a faster 
            // loop to find the next empty bit
            if ((width == 1) && (height == 1))
            {
                for (var row = startIndex; row < _rowsInternal; row++)
                {
                    for (var col = 0; col < _columnsInternal; col++)
                    {
                        if (!this[row, col])
                        {
                            // Swap the row and col values if the BitOrientation is Vertical
                            return (BitOrientation == Orientation.Horizontal) ? new MatrixCell(row, col) : new MatrixCell(col, row);
                        }
                    }
                }

                // If the code has reached here it means that it did not find any unset
                // bit in the entire _data. Simply return from here.
                return invalidCell;
            }

            var mask = (((UInt64)1) << width) - 1;
            for (var row = startIndex; row < _rowsInternal; row++)
            {
                // Quickcheck: If the row is empty then no need to check individual bits in the row
                if (!RowHasData(row))
                {
                    // Current column has no bits set. Check the bits in the next (height - 1)
                    // rows starting at the same column position (0) to check if they are unset
                    if (!AnyBitsSetInRegion(row, 0, width, height))
                    {
                        // Swap the row and col values if the BitOrientation is Vertical
                        return (BitOrientation == Orientation.Horizontal) ? new MatrixCell(row, 0) : new MatrixCell(0, row);
                    }
                }

                // Row is not empty and has some set bits.  Check if there are
                // 'width' continuous unset bits in the column.
                // 1. Check the first 'width' bits
                var rowData = (UInt64)0;
                var col = 0;
                for (; col < width; col++)
                {
                    rowData <<= 1;
                    rowData |= this[row, col] ? (UInt64)1 : (UInt64)0;
                }
                if ((rowData & mask) == 0)
                {
                    // Current column has 'width' unset bits starting from 0 position.
                    // Check the bits in the next (height - 1) rows starting at the same
                    // column position (0) to check if they are unset
                    if (!AnyBitsSetInRegion(row, 0, width, height))
                    {
                        // Swap the row and col values if the BitOrientation is Vertical
                        return (BitOrientation == Orientation.Horizontal) ? new MatrixCell(row, 0) : new MatrixCell(0, row);
                    }
                }

                // Shift the rowData by 1 bit and clear the (width + 1)th most significant bit.
                // This way a set of 'width' continuous bits is matched against the mask 
                // to check if all the bits are zero.
                var colBegin = 0;
                while (col < _columnsInternal)
                {
                    rowData <<= 1;
                    rowData &= mask;
                    rowData |= this[row, col++] ? (UInt64)1 : (UInt64)0;
                    colBegin++;

                    if ((rowData & mask) != 0)
                        continue;

                    // Current column has 'width' unset bits starting from colBegin position.
                    // Check the bits in the next (height - 1) rows starting at the same
                    // column position (colBegin) to check if they are unset
                    if (AnyBitsSetInRegion(row, colBegin, width, height))
                        continue;

                    // Swap the row and col values if the BitOrientation is Vertical
                    return (BitOrientation == Orientation.Horizontal) ? new MatrixCell(row, colBegin) : new MatrixCell(colBegin, row);
                }
            }

            return invalidCell;
        }