private static void AddLineToPreparedTextWithPageCheck(PreparedPagedText ppt, String line, Int32 availableHeight, ref Int32 currentAvailableHeight)
 {
     ppt.AddLineToPage(ppt.CurrentPageNumber, line);
     currentAvailableHeight -= ppt.LineHeight;
     if (currentAvailableHeight < ppt.LineHeight)
     {
         currentAvailableHeight = availableHeight;
         ppt.CurrentPageNumber++;
     }
 }
        /// <summary>
        /// Returns a PreparedPagedText structure that explains how to draw a long piece of text into a rectangular area.
        /// </summary>
        public static PreparedPagedText PrepareTextForDisplayInBox(String textChunk, Graphics g, Font f, Int32 targetBoxWidthPostScale, Int32 targetBoxHeightPostScale, Int32 edgeBuffer)
        {
            PreparedPagedText ppt = new PreparedPagedText();

            // First, we must discount any space that is for an edge buffer.
            Int32 availableWidth         = targetBoxWidthPostScale - edgeBuffer;
            Int32 availableHeight        = targetBoxHeightPostScale - edgeBuffer;
            Int32 currentAvailableHeight = availableHeight;

            // The text chunk is FIRST divided by any new line characters.
            String[] remainingTextChunks = textChunk.Split(new String[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
            // We treat these chunks individually.
            foreach (String textElement in remainingTextChunks)
            {
                Boolean finished      = false;
                String  remainingText = textElement;
                while (!finished)
                {
                    SizeF measuredString = g.MeasureString(remainingText, f);
                    ppt.LineHeight = (Int32)measuredString.Height;
                    if (ppt.LineHeight > currentAvailableHeight)
                    {
                        // We will never have enough line height, so end, now.
                        finished = true;
                    }
                    else
                    {
                        // If the width of the remaining text is less than the desired textbox width, we're done;
                        // there's nothing more to split.  The while loop ALWAYS ends here; if the text is bigger,
                        // then we KNOW there will be another line.  Eventually, the last line will be less than the available width.
                        if (measuredString.Width < availableWidth)
                        {
                            AddLineToPreparedTextWithPageCheck(ppt, remainingText, availableHeight, ref currentAvailableHeight);
                            finished = true;
                        }
                        else
                        {
                            // If the remaining text is too long for this line, keep building up a new line, one word at a time,
                            // until it goes over the target width.  When it does, remove the last added word, and add that line.
                            // Then, build up the remaining text.
                            String[] wordArray = remainingText.Split(' ');
                            if (wordArray.Length == 1)
                            {
                                // If after splitting, we have only ONE entry, we will never be able to finish.  We will never be able to fit this line in the provided box.  So bail out.
                                // Otherwise we'd get stuck in an infinite loop.
                                finished = true;
                            }
                            else
                            {
                                remainingText = "";                                        // Empty the raw text string.  Anything that goes here will be more text to process.
                                String        textLine              = "";                  // The line of text that will be safe to add
                                StringBuilder sbTextLineTemp        = new StringBuilder(); // Text plus the extra word
                                Boolean       buildingRemainingText = false;
                                StringBuilder sbRemainingText       = new StringBuilder();

                                for (Int32 currentWordIndex = 0; currentWordIndex < wordArray.Length; currentWordIndex++)
                                {
                                    if (buildingRemainingText) /* i.e., we're preparing the remaining text for the next go around of this process. */
                                    {
                                        sbRemainingText.Append(wordArray[currentWordIndex]);
                                        if (currentWordIndex < wordArray.Length - 1)
                                        {
                                            sbRemainingText.Append(" ");
                                        }
                                    }
                                    else
                                    {
                                        sbTextLineTemp.Append(wordArray[currentWordIndex]);
                                        if (currentWordIndex + 1 < wordArray.Length)
                                        {
                                            sbTextLineTemp.Append(" ");
                                        }
                                        measuredString = g.MeasureString(sbTextLineTemp.ToString(), f);
                                        if (measuredString.Width >= availableWidth) /* We've gone overboard; we don't want the last word we added. */
                                        {
                                            AddLineToPreparedTextWithPageCheck(ppt, textLine, availableHeight, ref currentAvailableHeight);
                                            sbRemainingText.Append(wordArray[currentWordIndex]);
                                            if (currentWordIndex < wordArray.Length - 1)
                                            {
                                                sbRemainingText.Append(" ");
                                            }
                                            buildingRemainingText = true;
                                        }
                                        else
                                        {
                                            textLine = sbTextLineTemp.ToString();
                                        }
                                    }
                                }

                                remainingText = sbRemainingText.ToString();
                            }
                        }
                    }
                }
            }

            ppt.CurrentPageNumber = 0;

            return(ppt);
        }
        /// <summary>
        /// Given some text we want to draw (which may not already be set into a PreparedPagedText object),
        /// draw it to the screen at the given logical position.
        /// </summary>
        public static void DrawPreparedText(BaseGameModel model, Position logicalPosition, String fullText, Graphics g, Font font,
                                            Boolean drawBorder, Pen penBorder, Int32 edgeBuffer, ref PreparedPagedText prepText)
        {
            Position displayPos = model.Camera.MapLogicalToDisplay(logicalPosition, true);

            if (drawBorder)
            {
                Drawing2D.DrawRectBorder(g, penBorder, displayPos);
            }
            if (prepText == null)
            {
                prepText = DrawText.PrepareTextForDisplayInBox(fullText, g,
                                                               font, (Int32)displayPos.Width, (Int32)displayPos.Height, (Int32)(edgeBuffer * model.Camera.CurrentScale));
            }

            List <String> preparedOutputText = prepText.GetCurrentPageText();
            Int32         currentLineY       = 0;

            for (Int32 currentLine = 0; currentLine < preparedOutputText.Count; currentLine++)
            {
                String   textToDraw     = preparedOutputText[currentLine];
                Position displayTextPos = model.Camera.TopLeftAlignTextWithinRect(logicalPosition, textToDraw, font, g, ignoreCameraPosition: true);
                g.DrawString(textToDraw, font, Brushes.White, (Single)displayTextPos.UpperLeftX, (Single)displayTextPos.UpperLeftY + currentLineY);
                currentLineY += prepText.LineHeight;
            }
        }