@using SharedLibraryCore.Configuration.Attributes
@using SharedLibraryCore.Configuration;
@model SharedLibraryCore.Configuration.ApplicationConfiguration

@{
    ViewData["Title"] = SharedLibraryCore.Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CONFIGURATION_TITLE"];
    string optionalText = SharedLibraryCore.Utilities.CurrentLocalization.LocalizationIndex["COMMAND_HELP_OPTIONAL"];
    string advancedText = SharedLibraryCore.Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CONFIGURATION_ADVANCED"];
    string addText = SharedLibraryCore.Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CONFIGURATION_ADD"];
    string saveText = SharedLibraryCore.Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CONFIGURATION_SAVE"];
    string noticeText = SharedLibraryCore.Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CONFIGURATION_SAVING_CHANGES"];
    string addServerText = SharedLibraryCore.Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CONFIGURATION_SERVER_ADD"];

    var properties = Model.GetType().GetProperties();

    string[] getLinkedPropertyName(System.Reflection.PropertyInfo info)
    {
        var test = (info.GetCustomAttributes(false)
             .Where(_attr => _attr.GetType() == typeof(ConfigurationLinked))
             .FirstOrDefault() as ConfigurationLinked);

        return test?.LinkedPropertyNames ?? new string[0];
    }

    bool shouldIgnore(System.Reflection.PropertyInfo info) => (info.GetCustomAttributes(false)
             .Where(_attr => _attr.GetType() == typeof(ConfigurationIgnore))
             .FirstOrDefault() as ConfigurationIgnore) != null;

    bool isOptional(System.Reflection.PropertyInfo info) => (info.GetCustomAttributes(false)
             .Where(_attr => _attr.GetType() == typeof(ConfigurationOptional))
             .FirstOrDefault() as ConfigurationOptional) != null;

    bool hasLinkedParent(System.Reflection.PropertyInfo info)
    {
        return Model.GetType().GetProperties().SelectMany(_prop => getLinkedPropertyName(_prop)).Contains(info.Name);
    }
}

<div class="row">
    <div class="col-12 text-white-50 ">
        <h3 class="text-white">@ViewData["Title"]</h3>
        <h5 class="mb-4">@noticeText</h5>
        <form id="configurationForm" asp-controller="Configuration" asp-action="Save" method="post">
            @foreach (var property in properties)
            {
                if (shouldIgnore(property))
                {
                    continue;
                }

                string[] linkedPropertyNames = getLinkedPropertyName(property);

                // bool type
                if (property.PropertyType == typeof(bool))
                {
                    <div class="form-group form-check bg-primary mb-0 pl-3 pr-3 p-2">
                        @Html.Editor(property.Name, linkedPropertyNames.Length > 0 ? new { htmlAttributes = new { @class = "has-related-content mb-0", data_related_content = string.Join(',', linkedPropertyNames.Select(_id => $"#{_id}_content")) } } : null)
                        @Html.Label(property.Name, null, new { @class = "form-check-label ml-1" })
                    </div>
                }

                // array type
                else if (property.PropertyType.IsArray)
                {
                    // special type for server config, I don't like this but for now it's ok
                    @if (property.PropertyType.GetElementType() == typeof(ServerConfiguration))
                    {
                        <div id="@($"{property.Name}_content")" class="pl-3 pr-3 pt-2 pb-3 bg-dark">
                            @for (int i = 0; i < Model.Servers.Length; i++)
                            {
                                @Html.EditorFor(model => model.Servers[i]);
                            }
                            <a asp-controller="Configuration" asp-action="GetNewListItem" asp-route-propertyName="@property.Name" class="btn btn-primary configuration-server-add-new">@addServerText</a>
                        </div>
                    }

                    else if (hasLinkedParent(property))
                    {
                        <div id="@($"{property.Name}_content")" class="@(linkedPropertyNames.Length == 0 ? "hide" : "hide") bg-dark pl-3 pr-3 pb-2">
                            @if (linkedPropertyNames.Length == 0)
                            {
                                @Html.Label(property.Name, null, new { @class = "mt-2 d-block" })
                            }
                            @Html.Editor(property.Name, new { htmlAttributes = new { @class = $"form-group form-control bg-dark text-white-50 {(linkedPropertyNames.Length == 0 ? "mb-3" : "mb-0")}" } })
                            <a asp-controller="Configuration" asp-action="GetNewListItem" asp-route-propertyName="@property.Name" class="btn btn-primary configuration-add-new">@addText</a>
                        </div>
                    }

                    else
                    {
                        @Html.Label(property.Name, null, new { @class = "bg-primary pl-3 pr-3 p-2 mb-0 w-100" })
                        <div id="@($"{property.Name}_content")" class="pl-3 pr-3 pt-2 pb-3 bg-dark">
                            @Html.Editor(property.Name, new { htmlAttributes = new { @class = "form-control bg-dark text-white-50 mt-3 mb-3", placeholder = isOptional(property) ? optionalText : "" } })
                            <a asp-controller="Configuration" asp-action="GetNewListItem" asp-route-propertyName="@property.Name" class="btn btn-primary configuration-add-new">@addText</a>
                        </div>
                    }
                }

                else
                {
                    if (hasLinkedParent(property))
                    {
                        <div id="@($"{property.Name}_content")" class="@(hasLinkedParent(property) ? "hide" : "") bg-dark pl-3 pr-3 pt-2 pb-3">
                            @Html.Label(property.Name, null, new { @class = "mt-1" })
                            @Html.Editor(property.Name, new { htmlAttributes = new { @class = "form-group form-control bg-dark text-white-50 mb-0", placeholder = isOptional(property) ? optionalText : "" } })
                        </div>
                    }

                    else
                    {
                        @Html.Label(property.Name, null, new { @class = "bg-primary pl-3 pr-3 p-2 mb-0 w-100" })
                        <div class="p-3 bg-dark">
                            @Html.Editor(property.Name, new { htmlAttributes = new { @class = "form-group form-control bg-dark text-white-50 mb-0", placeholder = isOptional(property) ? optionalText : "" } })
                        </div>
                    }
                }
            }
            <button class="btn btn-primary btn-block">@saveText</button>
        </form>
    </div>
</div>
@section scripts {
    <environment include="Development">
        <script type="text/javascript" src="~/js/configuration.js"></script>
    </environment>
}