@using Humanizer
@using Newtonsoft.Json
@using StardewModdingAPI.Toolkit.Utilities
@using StardewModdingAPI.Web.Framework
@using StardewModdingAPI.Web.Framework.LogParsing.Models
@model StardewModdingAPI.Web.ViewModels.LogParserModel

@{
    ViewData["Title"] = "SMAPI log parser";
    IDictionary<string, LogModInfo[]> contentPacks = Model.GetContentPacksByMod();
    IDictionary<string, bool> defaultFilters = Enum
        .GetValues(typeof(LogLevel))
        .Cast<LogLevel>()
        .ToDictionary(level => level.ToString().ToLower(), level => level != LogLevel.Trace);
    JsonSerializerSettings noFormatting = new JsonSerializerSettings { Formatting = Formatting.None };
}

@section Head {
    @if (Model.PasteID != null)
    {
        <meta name="robots" content="noindex" />
    }
    <link rel="stylesheet" href="~/Content/css/log-parser.css?r=20191127" />
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.min.js" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/jquery@3.3.1/dist/jquery.min.js" crossorigin="anonymous"></script>
    <script src="~/Content/js/log-parser.js?r=20190515"></script>
    <script>
        $(function() {
            smapi.logParser({
                logStarted: new Date(@Json.Serialize(Model.ParsedLog?.Timestamp)),
                showPopup: @Json.Serialize(Model.ParsedLog == null),
                showMods: @Json.Serialize(Model.ParsedLog?.Mods?.Select(p => Model.GetSlug(p.Name)).Distinct().ToDictionary(slug => slug, slug => true), noFormatting),
                showSections: @Json.Serialize(Enum.GetNames(typeof(LogSection)).ToDictionary(section => section, section => false), noFormatting),
                showLevels: @Json.Serialize(defaultFilters, noFormatting),
                enableFilters: @Json.Serialize(!Model.ShowRaw)
            }, '@this.Url.PlainAction("Index", "LogParser", values: null)');
        });
    </script>
}

@* upload result banner *@
@if (Model.UploadError != null)
{
    <div class="banner error" v-pre>
        <strong>Oops, the server ran into trouble saving that file.</strong><br />
        <small v-pre>Error details: @Model.UploadError</small>
    </div>
}
else if (Model.ParseError != null)
{
    <div class="banner error" v-pre>
        <strong>Oops, couldn't parse that log. (Make sure you upload the log file, not the console text.)</strong><br />
        Share this URL when asking for help: <code>https://@this.Context.Request.Host.ToUriComponent()@this.Url.PlainAction("Index", "LogParser", new { id = Model.PasteID }))</code><br />
        (Or <a href="@this.Url.PlainAction("Index", "LogParser", values: null)">upload a new log</a>.)<br />
        <br />
        <small v-pre>Error details: @Model.ParseError</small>
    </div>
}
else if (Model.ParsedLog?.IsValid == true)
{
    <div class="banner success" v-pre>
        <strong>Share this link to let someone else see the log:</strong> <code>https://@this.Context.Request.Host.ToUriComponent()@this.Url.PlainAction("Index", "LogParser", new { id = Model.PasteID })</code><br />
        (Or <a href="@this.Url.PlainAction("Index", "LogParser", values: null)">upload a new log</a>.)
    </div>
}

@* save warnings *@
@if (Model.UploadWarning != null || Model.Expiry != null)
{
    <div class="save-metadata" v-pre>
        @if (Model.Expiry != null)
        {
            <text>This log will expire in @((DateTime.UtcNow - Model.Expiry.Value).Humanize()). </text>
        }
        <!--@Model.UploadWarning-->
    </div>
}

@* upload new log *@
@if (Model.ParsedLog == null)
{
    <h2>Where do I find my SMAPI log?</h2>
    <div>What system do you use?</div>
    <ul id="os-list">
        @foreach (Platform platform in new[] { Platform.Android, Platform.Linux, Platform.Mac, Platform.Windows })
        {
            <li>
                <input type="radio" name="os" value="@platform" id="os-@platform" checked="@(Model.DetectedPlatform == platform)" />
                <label for="os-@platform">@platform</label>
            </li>
        }
    </ul>
    <div data-os="@Platform.Android">
        On Android:
        <ol>
            <li>Open a file app (like My Files or MT Manager).</li>
            <li>Find the <code>StardewValley</code> folder on your internal storage.</li>
            <li>Open the <code>ErrorLogs</code> subfolder.</li>
            <li>The log file is <code>SMAPI-crash.txt</code> if it exists, otherwise <code>SMAPI-latest.txt</code>.</li>
        </ol>
    </div>
    <div data-os="@Platform.Linux">
        On Linux:
        <ol>
            <li>Open the Files app.</li>
            <li>Click the options menu (might be labeled <em>Go</em> or <code>⋮</code>).</li>
            <li>Choose <em>Enter Location</em>.</li>
            <li>Enter this exact text: <pre>~/.config/StardewValley/ErrorLogs</pre></li>
            <li>The log file is <code>SMAPI-crash.txt</code> if it exists, otherwise <code>SMAPI-latest.txt</code>.</li>
        </ol>
    </div>
    <div data-os="@Platform.Mac">
        On Mac:
        <ol>
            <li>Open the Finder app.</li>
            <li>Click <em>Go</em> at the top, then <em>Go to Folder</em>.</li>
            <li>Enter this exact text: <pre>~/.config/StardewValley/ErrorLogs</pre></li>
            <li>The log file is <code>SMAPI-crash.txt</code> if it exists, otherwise <code>SMAPI-latest.txt</code>.</li>
        </ol>
    </div>
    <div data-os="@Platform.Windows">
        On Windows:
        <ol>
            <li>Press the <code>Windows</code> and <code>R</code> buttons at the same time.</li>
            <li>In the 'run' box that appears, enter this exact text: <pre>%appdata%\StardewValley\ErrorLogs</pre></li>
            <li>The log file is <code>SMAPI-crash.txt</code> if it exists, otherwise <code>SMAPI-latest.txt</code>.</li>
        </ol>
    </div>

    <h2>How do I share my log?</h2>
    <form action="@this.Url.PlainAction("PostAsync", "LogParser")" method="post">
        <ol>
            <li>
                Drag the file onto this textbox (or paste the text in):<br />
                <textarea id="input" name="input" placeholder="paste log here"></textarea>
            </li>
            <li>
                Click this button:<br />
                <input type="submit" id="submit" value="save & parse log" />
            </li>
            <li>On the new page, copy the URL and send it to the person helping you.</li>
        </ol>
    </form>
}

@* parsed log *@
@if (Model.ParsedLog?.IsValid == true)
{
    <div id="output">
        @if (Model.ParsedLog.Mods.Any(mod => mod.HasUpdate))
        {
            <h2>Suggested fixes</h2>
            <ul id="fix-list">
                <li>
                    Consider updating these mods to fix problems:

                    <table id="updates" class="table">
                        @foreach (LogModInfo mod in Model.ParsedLog.Mods.Where(mod => (mod.HasUpdate && mod.ContentPackFor == null) || (contentPacks != null && contentPacks.TryGetValue(mod.Name, out LogModInfo[] contentPackList) && contentPackList.Any(pack => pack.HasUpdate))))
                        {
                            <tr class="mod-entry">
                                <td>
                                    <strong class=@(!mod.HasUpdate ? "hidden" : "")>@mod.Name</strong>
                                    @if (contentPacks != null && contentPacks.TryGetValue(mod.Name, out LogModInfo[] contentPackList))
                                    {
                                        <div class="content-packs">
                                            @foreach (LogModInfo contentPack in contentPackList.Where(pack => pack.HasUpdate))
                                            {
                                                <text>+ @contentPack.Name</text><br />
                                            }
                                        </div>
                                    }
                                </td>
                                <td>
                                    @if (mod.HasUpdate)
                                    {
                                        <a href="@mod.UpdateLink" target="_blank">
                                            @(mod.Version == null ? @mod.UpdateVersion : $"{mod.Version} → {mod.UpdateVersion}")
                                        </a>
                                    }
                                    else
                                    {
                                        <text>&nbsp;</text>
                                    }

                                    @if (contentPacks != null && contentPacks.TryGetValue(mod.Name, out contentPackList))
                                    {
                                        <div>
                                            @foreach (LogModInfo contentPack in contentPackList.Where(pack => pack.HasUpdate))
                                            {
                                                <a href="@contentPack.UpdateLink" target="_blank">@contentPack.Version → @contentPack.UpdateVersion</a><br />
                                            }
                                        </div>
                                    }
                                </td>
                            </tr>
                        }
                    </table>
                </li>
            </ul>
        }

        <h2>Log info</h2>
        <table id="metadata" class="table">
            <caption>Game info:</caption>
            <tr>
                <th>Stardew Valley:</th>
                <td v-pre>@Model.ParsedLog.GameVersion on @Model.ParsedLog.OperatingSystem</td>
            </tr>
            <tr>
                <th>SMAPI:</th>
                <td v-pre>@Model.ParsedLog.ApiVersion</td>
            </tr>
            <tr>
                <th>Folder:</th>
                <td v-pre>@Model.ParsedLog.GamePath</td>
            </tr>
            <tr>
                <th>Log started:</th>
                <td>@Model.ParsedLog.Timestamp.UtcDateTime.ToString("yyyy-MM-dd HH:mm") UTC ({{localTimeStarted}} your time)</td>
            </tr>
        </table>
        <br />
        <table id="mods" class="@(Model.ShowRaw ? "filters-disabled" : null) table">
            <caption>
                Installed mods:
                @if (!Model.ShowRaw)
                {
                    <span class="notice txt"><i>click any mod to filter</i></span>
                    <span class="notice btn txt" v-on:click="showAllMods" v-bind:class="{ invisible: !anyModsHidden }">show all</span>
                    <span class="notice btn txt" v-on:click="hideAllMods" v-bind:class="{ invisible: !anyModsShown || !anyModsHidden }">hide all</span>
                }
            </caption>
            @foreach (var mod in Model.ParsedLog.Mods.Where(p => p.Loaded && p.ContentPackFor == null))
            {
                <tr v-on:click="toggleMod('@Model.GetSlug(mod.Name)')" class="mod-entry" v-bind:class="{ hidden: !showMods['@Model.GetSlug(mod.Name)'] }">
                    <td><input type="checkbox" v-bind:checked="showMods['@Model.GetSlug(mod.Name)']" v-bind:class="{ invisible: !anyModsHidden }" /></td>
                    <td v-pre>
                        <strong>@mod.Name</strong> @mod.Version
                        @if (contentPacks != null && contentPacks.TryGetValue(mod.Name, out LogModInfo[] contentPackList))
                        {
                            <div class="content-packs">
                                @foreach (var contentPack in contentPackList)
                                {
                                    <text>+ @contentPack.Name @contentPack.Version</text><br />
                                }
                            </div>
                        }
                    </td>
                    <td v-pre>
                        @mod.Author
                        @if (contentPacks != null && contentPacks.TryGetValue(mod.Name, out contentPackList))
                        {
                            <div class="content-packs">
                                @foreach (var contentPack in contentPackList)
                                {
                                    <text>+ @contentPack.Author</text><br />
                                }
                            </div>
                        }
                    </td>
                    @if (mod.Errors == 0)
                    {
                        <td v-pre class="color-green">no errors</td>
                    }
                    else if (mod.Errors == 1)
                    {
                        <td v-pre class="color-red">@mod.Errors error</td>
                    }
                    else
                    {
                        <td v-pre class="color-red">@mod.Errors errors</td>
                    }
                </tr>
            }
        </table>

        @if (!Model.ShowRaw)
        {
            <div id="filters">
                Filter messages:
                <span v-bind:class="{ active: showLevels['trace'] }" v-on:click="toggleLevel('trace')">TRACE</span> |
                <span v-bind:class="{ active: showLevels['debug'] }" v-on:click="toggleLevel('debug')">DEBUG</span> |
                <span v-bind:class="{ active: showLevels['info'] }" v-on:click="toggleLevel('info')">INFO</span> |
                <span v-bind:class="{ active: showLevels['alert'] }" v-on:click="toggleLevel('alert')">ALERT</span> |
                <span v-bind:class="{ active: showLevels['warn'] }" v-on:click="toggleLevel('warn')">WARN</span> |
                <span v-bind:class="{ active: showLevels['error'] }" v-on:click="toggleLevel('error')">ERROR</span>
            </div>

            <table id="log">
                @foreach (var message in Model.ParsedLog.Messages)
                {
                    string levelStr = message.Level.ToString().ToLower();
                    string sectionStartClass = message.IsStartOfSection ? "section-start" : null;
                    string sectionFilter = message.Section != null && !message.IsStartOfSection ? $"&& sectionsAllow('{message.Section}')" : null; // filter the message by section if applicable

                    <tr class="mod @levelStr @sectionStartClass"
                        @if (message.IsStartOfSection)
                        {
                            <text>v-on:click="toggleSection('@message.Section')"</text>
                        }
                        v-show="filtersAllow('@Model.GetSlug(message.Mod)', '@levelStr') @sectionFilter">
                        <td v-pre>@message.Time</td>
                        <td v-pre>@message.Level.ToString().ToUpper()</td>
                        <td v-pre data-title="@message.Mod">@message.Mod</td>
                        <td>
                            <span v-pre class="log-message-text">@message.Text</span>
                            @if (message.IsStartOfSection)
                            {
                                <span class="section-toggle-message">
                                    <template v-if="sectionsAllow('@message.Section')">This section is shown. Click here to hide it.</template>
                                    <template v-else>This section is hidden. Click here to show it.</template>
                                </span>
                            }
                        </td>
                    </tr>
                    if (message.Repeated > 0)
                    {
                        <tr class="@levelStr mod mod-repeat" v-show="filtersAllow('@Model.GetSlug(message.Mod)', '@levelStr') @sectionFilter">
                            <td colspan="3"></td>
                            <td v-pre><i>repeats [@message.Repeated] times.</i></td>
                        </tr>
                    }
                }
            </table>

            <small><a href="@this.Url.PlainAction("Index", "LogParser", new { id = Model.PasteID, raw = true })">view raw log</a></small>
        }
        else
        {
            <pre v-pre>@Model.ParsedLog.RawText</pre>
            <small><a href="@this.Url.PlainAction("Index", "LogParser", new { id = Model.PasteID })">view parsed log</a></small>
        }
    </div>
}
else if (Model.ParsedLog?.IsValid == false)
{
    <h3>Raw log</h3>
    <pre v-pre>@Model.ParsedLog.RawText</pre>
}