private void showPredictions(WorldDate date,
                                     List <GarbagePrediction> predictions, string mode)
        {
            bool          today = date == Utilities.Now();
            List <string> pages = new List <string> ();

            // Show a special message for all cans being empty.
            if (predictions.Count == 0)
            {
                pages.Add(Helper.Translation.Get($"garbage.none.{mode}", new
                {
                    date = date.Localize(),
                }));
            }
            else
            {
                // Build the list of predictions.
                List <string> lines = new List <string>
                {
                    Helper.Translation.Get($"garbage.header.{(today ? "today" : "later")}", new
                    {
                        date = date.Localize(),
                    })
                };

                // Randomize the order of predictions for variety.
                Random rng = new Random((int)Game1.uniqueIDForThisGame +
                                        date.TotalDays);

                foreach (GarbagePrediction prediction in
                         predictions.OrderBy((GarbagePrediction a) => rng.Next()))
                {
                    string can = prediction.can.ToString().Replace("SVE_", "");
                    lines.Add(Helper.Translation.Get($"garbage.prediction.{can}", new
                    {
                        itemName = (prediction.loot is Hat)
                                                        ? Helper.Translation.Get("garbage.item.hat")
                                                        : (prediction.loot.ParentSheetIndex == 217)
                                                                ? Helper.Translation.Get("garbage.item.dishOfTheDay")
                                                                : prediction.loot.DisplayName,
                    }));
                }
                if (Constants.TargetPlatform != GamePlatform.Android)
                {
                    lines.Add("");                      // padding for occasional display issues
                }
                pages.Add(string.Join("^", lines));
            }

            // If checking more cans could alter the results, add an
            // appropriate closing.
            if (Garbage.IsProgressDependent)
            {
                pages.Add(Helper.Translation.Get("garbage.closing.progress"));
            }

            // Show the predictions.
            showDialogues(pages);
            Game1.afterDialogues = extinguish;
        }
        private void onDateChosen(WorldDate date)
        {
            // Gather the appropriate predictions.
            List <Mining.Prediction> predictions = Mining.ListFloorsForDate(date);

            bool          today = date == Utilities.Now();
            List <string> pages = new List <string> ();

            // Build the list of predictions.
            List <string> lines = new List <string>
            {
                Helper.Translation.Get($"mining.header.{(today ? "today" : "later")}", new
                {
                    date = date.Localize(),
                })
            };

            string joiner = CultureInfo.CurrentCulture.TextInfo.ListSeparator + " ";

            foreach (Mining.FloorType type in predictions
                     .Select((p) => p.type).Distinct().ToList())
            {
                List <int> floors = predictions
                                    .Where((p) => p.type == type)
                                    .Select((p) => p.floor)
                                    .ToList();
                string floorsText;
                if (floors.Count == 1)
                {
                    floorsText = Helper.Translation.Get("mining.floor",
                                                        new { num = floors[0] });
                }
                else
                {
                    int lastNum = floors[floors.Count - 1];
                    floors.RemoveAt(floors.Count - 1);
                    floorsText = unbreak(Helper.Translation.Get("mining.floors",
                                                                new { nums = string.Join(joiner, floors), lastNum = lastNum }));
                }

                lines.Add(Helper.Translation.Get($"mining.prediction.{type}",
                                                 new { floors = floorsText }));
            }
            if (predictions.Count == 0)
            {
                lines.Add(Helper.Translation.Get("mining.prediction.none"));
            }
            pages.Add(string.Join("^", lines));

            // If going deeper in the mines could alter the results, add an
            // appropriate closing.
            if (Mining.IsProgressDependent)
            {
                pages.Add(Helper.Translation.Get("mining.closing.progress"));
            }

            // Show the predictions.
            showDialogues(pages);
            Game1.afterDialogues = extinguish;
        }
        public override void draw(SpriteBatch b)
        {
            // dialog background
            Game1.drawDialogueBox(xPositionOnScreen, yPositionOnScreen, width,
                                  height, false, true);

            // PromptLabel
            float promptWidth  = Game1.smallFont.MeasureString(promptMessage).X;
            float promptOffset = (promptLabel.bounds.Width - promptWidth) / 2;

            Utility.drawTextWithShadow(b, promptMessage, Game1.smallFont,
                                       new Vector2(promptLabel.bounds.X + promptOffset, promptLabel.bounds.Y),
                                       Game1.textColor);

            // DateLabel
            string dateText   = date.Localize();
            float  dateWidth  = DateFont.MeasureString(dateText).X;
            float  dateOffset = (dateLabel.bounds.Width - dateWidth) / 2;

            Utility.drawTextWithShadow(b, dateText, DateFont,
                                       new Vector2(dateLabel.bounds.X + dateOffset, dateLabel.bounds.Y),
                                       Game1.textColor);

            // Calendar
            calendar.draw(b);

            // WeekLabels
            for (int i = 0; i < weekLabels.Count; ++i)
            {
                ClickableComponent label = weekLabels[i];
                string             text  = (i % 4 + 1).ToString();
                SpriteText.drawStringHorizontallyCenteredAt(b, text,
                                                            label.bounds.X, label.bounds.Y, junimoText: true);
            }

            // DayButtons
            for (int i = 0; i < dayButtons.Count; ++i)
            {
                ClickableTextureComponent button = dayButtons[i];
                Vector2   position   = new Vector2(button.bounds.X, button.bounds.Y);
                Rectangle sourceRect = new Rectangle(button.sourceRect.X +
                                                     ((i == selectedDay) ? 24 : (i == hoverButton) ? 12 : 0),
                                                     button.sourceRect.Y, button.sourceRect.Width,
                                                     button.sourceRect.Height);
                Vector2 origin = new Vector2(button.sourceRect.Width / 2,
                                             button.sourceRect.Height / 2);
                double angle = 2 * Math.PI * (i + 0.5) / 112.0;
                b.Draw(button.texture, position, sourceRect, Color.White,
                       (float)angle, origin, CalendarScale, SpriteEffects.None,
                       0.86f + (float)button.bounds.Y / 20000f);
            }

            // SeasonSprites
            foreach (ClickableTextureComponent sprite in seasonSprites)
            {
                sprite.draw(b);
            }

            // PrevButton, NextButton, ScryButton
            foreach (ClickableTextureComponent button in otherButtons)
            {
                button.draw(b);
            }

            // SeasonDebris
            foreach (WeatherDebris debris in seasonDebris)
            {
                debris.draw(b);
            }

            // DaySparkles
            foreach (TemporaryAnimatedSprite sparkle in daySparkles)
            {
                sparkle.draw(b, true);
            }

            // hover text
            if (hoverText != null)
            {
                drawHoverText(b, hoverText, Game1.smallFont);
            }

            // mouse cursor
            if (!Game1.options.hardwareCursor)
            {
                drawMouse(b);
            }
        }
        private void arrangeInterface()
        {
            int xOff = xPositionOnScreen + borderWidth + spaceToClearSideBorder * 2;
            int yOff = yPositionOnScreen + borderWidth + spaceToClearTopBorder -
                       (Mobile ? 40 : 0);

            promptLabel = new ClickableComponent(
                new Rectangle(xPositionOnScreen, yOff, width, Game1.smallFont.LineSpacing),
                "PromptLabel");
            yOff += Game1.smallFont.LineSpacing + spaceToClearSideBorder;

            dateLabel = new ClickableComponent(
                new Rectangle(xOff, yOff, CalendarSize, DateFont.LineSpacing),
                "DateLabel");
            yOff += DateFont.LineSpacing +
                    spaceToClearSideBorder * (Mobile ? 1 : 2);

            int calendarScaled = (int)(CalendarSize * CalendarScale);

            calendar = new ClickableTextureComponent("Calendar",
                                                     new Rectangle(xOff + (CalendarSize - calendarScaled) / 2, yOff,
                                                                   calendarScaled, calendarScaled),
                                                     null, null, calendarTile, new Rectangle(), CalendarScale, true);
            int xCenter = xOff + CalendarSize / 2;
            int yCenter = yOff + calendarScaled / 2;

            yOff += calendarScaled +
                    spaceToClearSideBorder * (Mobile ? 1 : 2);

            weekLabels = new List <ClickableComponent> ();
            double weekRadius = 164.5 * CalendarScale;

            for (int i = 0; i < 16; ++i)
            {
                double angle = 2 * Math.PI * (i + 0.5) / 16.0;
                int    x     = (int)(xCenter + weekRadius * Math.Sin(angle) +
                                     ((i % 4 == 0) ? 0.0 : 4.0) +
                                     (Mobile ? -4.0 : 0.0));
                int y = (int)(yCenter - weekRadius * Math.Cos(angle) +
                              (Mobile ? -28.0 : -24.0));

                weekLabels.Add(new ClickableComponent(new Rectangle(x, y, 0, 0),
                                                      $"Week{i}"));
            }

            dayButtons = new List <ClickableTextureComponent> ();
            double dayRadius = 220.0 * CalendarScale;

            for (int i = 0; i < 112; ++i)
            {
                WorldDate date = dayToWorldDate(i);

                double angle = 2 * Math.PI * (i + 0.5) / 112.0;
                int    x     = (int)(xCenter + dayRadius * Math.Sin(angle));
                int    y     = (int)(yCenter - dayRadius * Math.Cos(angle));

                dayButtons.Add(new ClickableTextureComponent($"Day{i}",
                                                             new Rectangle(x, y, 12, 52), null, date.Localize(),
                                                             dayButtonTiles, new Rectangle(36 * (i / 28), 0, 12, 52),
                                                             CalendarScale));
            }

            seasonSprites = new List <ClickableTextureComponent> ();
            for (int i = 0; i < 4; ++i)
            {
                Texture2D texture = Helper.Content.Load <Texture2D>
                                        (SeasonData[i].spriteAsset, ContentSource.GameContent);
                Rectangle sb     = SeasonData[i].spriteBounds;
                Rectangle bounds = new Rectangle
                                       ((int)(sb.X + xCenter),   // not scaling
                                       (int)(sb.Y * CalendarScale + yCenter),
                                       (int)(sb.Width * CalendarScale),
                                       (int)(sb.Height * CalendarScale));
                seasonSprites.Add(new ClickableTextureComponent($"SeasonSprite{i}",
                                                                bounds, null, null, texture, SeasonData[i].spriteSource,
                                                                1f)); // not scaling despite reduced bounds
            }

            xOff -= spaceToClearSideBorder;

            prevButton = new ClickableTextureComponent("PrevButton",
                                                       new Rectangle(xOff, yOff, Game1.tileSize, Game1.tileSize), null,
                                                       Helper.Translation.Get("datePicker.prevLabel"), Game1.mouseCursors,
                                                       Game1.getSourceRectForStandardTileSheet(Game1.mouseCursors, 44),
                                                       1f);

            nextButton = new ClickableTextureComponent("NextButton",
                                                       new Rectangle(xOff + Game1.tileSize + spaceToClearSideBorder, yOff,
                                                                     Game1.tileSize, Game1.tileSize), null,
                                                       Helper.Translation.Get("datePicker.nextLabel"), Game1.mouseCursors,
                                                       Game1.getSourceRectForStandardTileSheet(Game1.mouseCursors, 33),
                                                       1f);

            scryButton = new ClickableTextureComponent("ScryButton",
                                                       new Rectangle(xOff + CalendarSize + spaceToClearSideBorder * 2
                                                                     - Game1.tileSize, yOff, Game1.tileSize, Game1.tileSize), null,
                                                       Helper.Translation.Get("datePicker.scryLabel"), Game1.mouseCursors,
                                                       Game1.getSourceRectForStandardTileSheet(Game1.mouseCursors, 46),
                                                       1f);

            otherButtons = new List <ClickableTextureComponent>
            {
                prevButton, nextButton, scryButton
            };
        }