using DevExpress.Utils;
using DevExpress.Web;
using DevExpress.Web.ASPxThemes;
using DevExpress.Web.Mvc;
using DevExpress.XtraPrinting;
using DevExpress.XtraScheduler;
using GreenTree.Nachtragsmanagement.Core.Authentication;
using GreenTree.Nachtragsmanagement.Core.Domain.Deviation;
using GreenTree.Nachtragsmanagement.Core.Domain.User;
using GreenTree.Nachtragsmanagement.Services.Appendix;
using GreenTree.Nachtragsmanagement.Services.Configuration;
using GreenTree.Nachtragsmanagement.Services.Deviation;
using GreenTree.Nachtragsmanagement.Services.Logging;
using GreenTree.Nachtragsmanagement.Services.Misc;
using GreenTree.Nachtragsmanagement.Services.Scheduling;
using GreenTree.Nachtragsmanagement.Services.User;
using GreenTree.Nachtragsmanagement.Web.Extensions;
using GreenTree.Nachtragsmanagement.Web.Framework.Authorization;
using GreenTree.Nachtragsmanagement.Web.Models.Config;
using GreenTree.Nachtragsmanagement.Web.Models.Global;
using GreenTree.Nachtragsmanagement.Web.Models.Misc;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Mime;
using System.Web;
using System.Web.Mvc;
using System.Web.UI;
using System.Web.UI.WebControls;
using static GreenTree.Nachtragsmanagement.Web.Extensions.MVCxGridViewGeneratorHelper;

namespace GreenTree.Nachtragsmanagement.Web.Controllers
{
    public class MiscController : Controller
    {
        private readonly IMiscService _miscService;
        private readonly IUserService _userService;
        private readonly INotificationService _notificationService;
        private readonly INotificationScheduler _notificationScheduler;
        private readonly IConfigurationService _configurationService;
        private readonly IUserHelper _userHelper;
        private readonly ILogger _logger;

        public MiscController(
            IMiscService miscService,
            IUserService userService,
            INotificationService notificationService,
            INotificationScheduler notificationScheduler,
            IConfigurationService configurationService,
            IUserHelper userHelper,
            ILogger logger)
        {
            _miscService = miscService;
            _userService = userService;
            _notificationService = notificationService;
            _notificationScheduler = notificationScheduler;
            _configurationService = configurationService;
            _userHelper = userHelper;
            _logger = logger;

            ViewData["AllUsers"] = _userService.GetAllUsers();
            ViewData["AllUsersWithRole"] =
                _userService.GetAllUsers()
                    .Select(u => new
                    {
                        Id = u.Id,
                        Description = String.Format("{0} - {1}", u.Lastname,
                            String.Join(", ", u.Roles
                                .Select(r => r.Description)))
                    })
                    .ToList();

            ViewData["AllNotificationPlugins"] =
                _notificationService.GetNotificationPlugins();
        }

        #region MailNotifications

        /// <summary>
        /// Basic mailNotification view function
        /// </summary>
        [FunctionAuthorize(true, "Misc-MailNotifications")]
        public ActionResult ViewMailNotifications()
        {
            var mailNotifications = _miscService.GetAllMailNotifications();
            var mailNotificationModels = mailNotifications
                .Select(u => MailNotificationDataModel.FromMailNotification(
                    u, false, _notificationService, _notificationScheduler))
                .ToList();

            return View("~/Views/Misc/MailNotifications.cshtml", mailNotificationModels);
        }

        /// <summary>
        /// Get JSON data of specific mailNotification
        /// </summary>
        /// <param name="id">MailNotification id.</param>
        public ActionResult GetMailNotification(int id = -1)
        {
            var mailNotification = _miscService.GetMailNotificationById(id);
            if (mailNotification == null)
                return new JsonResult
                {
                    Data = "notFound",
                    JsonRequestBehavior = JsonRequestBehavior.AllowGet
                };

            var mailNotificationModel = MailNotificationDataModel.FromMailNotification(
                mailNotification, false, _notificationService, _notificationScheduler);
            
            return new JsonResult
            {
                Data = JsonConvert.SerializeObject(mailNotificationModel),
                JsonRequestBehavior = JsonRequestBehavior.AllowGet
            };
        }

        /// <summary>
        /// Callback result for mailNotification grid
        /// </summary>
        /// <param name="scrollHeight">The height of the grid scrollable component.</param>
        public ActionResult PartialMailNotifications(int scrollHeight = -1)
        {
            var mailNotifications = _miscService.GetAllMailNotifications();
            var mailNotificationModels = mailNotifications
                .Select(u => MailNotificationDataModel.FromMailNotification(
                    u, false, _notificationService, _notificationScheduler))
                .ToList();

            ViewData["ScrollHeight"] = scrollHeight;

            return PartialView("~/Views/Misc/_MailNotificationGridPartial.cshtml", mailNotificationModels);
        }

        /// <summary>
        /// Callback result for mailNotification job combobox
        /// </summary>
        /// <param name="pluginSystemName">The system name of the corresponding notification plugin.</param>
        public ActionResult PartialNotificationPluginJobs(string pluginSystemName)
        {
            var notificationPlugin = _notificationService.GetNotificationPlugin(pluginSystemName);

            if (notificationPlugin == null)
                return PartialView("~/Views/Misc/_MailNotificationPluginJobsPartial.cshtml", null);

            var mailNotificationModel = new MailNotificationDataModel
            {
                NotificationPlugin = notificationPlugin
            };

            return PartialView("~/Views/Misc/_MailNotificationPluginJobsPartial.cshtml", mailNotificationModel);
        }

        /// <summary>
        /// Partial edit for editing of existing or for new mailNotification
        /// </summary>
        /// <param name="id">Id for existing mailNotification, otherweise -1.</param>
        public ActionResult EditMailNotification(int id = -1)
        {
            var mailNotification = _miscService.GetMailNotificationById(id);
            var mailNotificationModel = MailNotificationDataModel.FromMailNotification(
                mailNotification, true, _notificationService, _notificationScheduler);

            return PartialView("~/Views/Misc/_MailNotificationEditPartial.cshtml", mailNotificationModel);
        }

        /// <summary>
        /// Partial edit result if ModelState is valid, otherwise simple JSON result for success
        /// </summary>
        /// <param name="mailNotificationModel">MailNotification model to be saved.</param>
        [HttpPost, ValidateInput(false)]
        public ActionResult EditMailNotification(MailNotificationDataModel mailNotificationModel)
        {
            try
            {
                if (!ModelState.IsValid)
                {
                    foreach (var role in mailNotificationModel.UserValues)
                        mailNotificationModel.UserDescriptions.Add(
                            ((IList<User>)ViewData["AllUsers"])
                                .First(r => r.Id == role).Lastname);

                    var notificationPlugin = _notificationService.GetNotificationPlugin(mailNotificationModel.NotificationPluginSystemName);

                    if (notificationPlugin != null)
                        mailNotificationModel.NotificationPlugin = notificationPlugin;

                    return PartialView("~/Views/Misc/_MailNotificationEditPartial.cshtml", mailNotificationModel);
                }

                if (mailNotificationModel.CronExpression.Split(' ').Length == 5)
                    mailNotificationModel.CronExpression = mailNotificationModel.CronExpression + " *";

                var selectedUsers = _userService.GetUsersByIds(mailNotificationModel.UserValues.ToArray());

                if (mailNotificationModel.Id == -1)
                {
                    var mailNotification = mailNotificationModel.ToMailNotification();

                    mailNotification.SetUsers(selectedUsers);

                    _miscService.InsertMailNotification(mailNotification);

                    _logger.Entity(mailNotification, Core.Domain.Logging.LogEntityActivity.Insert, _userHelper.FromCookiesOrSession());
                }
                else
                {
                    var mailNotification = _miscService.GetMailNotificationById(mailNotificationModel.Id);

                    mailNotification.CronExpression = mailNotificationModel.CronExpression;
                    mailNotification.NotificationPluginSystemName = mailNotificationModel.NotificationPluginSystemName;
                    mailNotification.NotificationJobSystemName = mailNotificationModel.NotificationJobSystemName;

                    mailNotification.SetUsers(selectedUsers);

                    _miscService.UpdateMailNotification(mailNotification);

                    _logger.Entity(mailNotification, Core.Domain.Logging.LogEntityActivity.Update, _userHelper.FromCookiesOrSession());
                }

                _notificationScheduler.Start();

                return new JsonResult
                {
                    Data = "success"
                };
            }
            catch (Exception ex)
            {
                _logger.Error("Fehler bei Speicherung einer Mail-Benachrichtigung.", ex, _userHelper.FromCookiesOrSession());

                return PartialView("~/Views/Shared/_PopupError.cshtml", ex);
            }
        }

        /// <summary>
        /// Simple JSON result for deleting a specific mailNotification
        /// </summary>
        /// <param name="id">MailNotification id.</param>
        [HttpPost]
        public ActionResult DeleteMailNotification(int id)
        {
            try
            {
                var mailNotification = _miscService.GetMailNotificationById(id);

                if (mailNotification != null)
                    _miscService.DeleteMailNotification(mailNotification);

                _logger.Entity(mailNotification, Core.Domain.Logging.LogEntityActivity.Delete, _userHelper.FromCookiesOrSession());

                return new JsonResult
                {
                    Data = "success"
                };
            }
            catch (Exception ex)
            {
                _logger.Error("Fehler bei Löschung einer Mail-Benachrichtigung.", ex, _userHelper.FromCookiesOrSession());

                return PartialView("~/Views/Shared/_PopupError.cshtml", ex);
            }
        }

        /// <summary>
        /// Processes the specific mailNotification
        /// </summary>
        /// <param name="id">MailNotification id.</param>
        [HttpPost]
        public ActionResult ProcessMailNotification(int id)
        {
            try
            {
                var mailNotification = _miscService.GetMailNotificationById(id);

                if (mailNotification != null)
                {
                    var notificationPlugin = _notificationService.GetNotificationPlugin(mailNotification.NotificationPluginSystemName);

                    notificationPlugin.ProcessNotifications(new[] { mailNotification });
                }

                return new JsonResult
                {
                    Data = "success"
                };
            }
            catch (Exception ex)
            {
                _logger.Error("Fehler bei Ausführung einer Mail-Benachrichtigung.", ex, _userHelper.FromCookiesOrSession());

                return PartialView("~/Views/Shared/_PopupError.cshtml", ex);
            }
        }

        #endregion

        #region Logs

        /// <summary>
        /// Basic log view function
        /// </summary>
        [FunctionAuthorize(true, "Misc-Logs")]
        public ActionResult ViewLogs()
        {
            var logs = _logger.GetAllLogs();
            var logModels = logs
                .Select(u => LogDataModel.FromLog(u, false))
                .ToList();

            return View("~/Views/Misc/Logs.cshtml", logModels);
        }

        /// <summary>
        /// Get JSON data of specific log
        /// </summary>
        /// <param name="id">Log id.</param>
        public ActionResult GetLog(int id = -1)
        {
            var log = _logger.GetLogById(id);
            if (log == null)
                return new JsonResult
                {
                    Data = "notFound",
                    JsonRequestBehavior = JsonRequestBehavior.AllowGet
                };

            var logModel = LogDataModel.FromLog(log, false);

            return new JsonResult
            {
                Data = JsonConvert.SerializeObject(logModel),
                JsonRequestBehavior = JsonRequestBehavior.AllowGet
            };
        }

        /// <summary>
        /// Callback result for log grid
        /// </summary>
        /// <param name="scrollHeight">The height of the grid scrollable component.</param>
        public ActionResult PartialLogs(int scrollHeight = -1)
        {
            var logs = _logger.GetAllLogs();
            var logModels = logs
                .Select(u => LogDataModel.FromLog(u, false))
                .ToList();

            ViewData["ScrollHeight"] = scrollHeight;

            return PartialView("~/Views/Misc/_LogGridPartial.cshtml", logModels);
        }

        /// <summary>
        /// Export result for misc grid
        /// </summary>
        [HttpPost]
        public ActionResult ExportPartialLogs(string displayMode, string exportformat)
        {
            if (String.IsNullOrEmpty(displayMode))
                return new EmptyResult();

            var currentUser = _userHelper.FromCookiesOrSession();

            var logs = _logger.GetAllLogs();
            var logModels = logs
                .Select(u => LogDataModel.FromLog(u, false))
                .ToList();

            var viewContext = new ViewContext();
            var viewPage = new ViewPage();
            var htmlHelper = new System.Web.Mvc.HtmlHelper(viewContext, viewPage);

            MVCxGridViewState gridViewState = (MVCxGridViewState)Session["LogGridViewState"];

            var settings = GridViewSettingsHelper.LogGridViewSettings(htmlHelper);

            if (gridViewState != null)
            {
                var generator = new MVCReportGeneratonHelper();

                generator.CustomizeColumnsCollection += new CustomizeColumnsCollectionEventHandler(logGenerator_CustomizeColumnsCollection);

                var report = generator.GenerateMVCReport(gridViewState, logModels, "Logliste");

                if (displayMode == "popup")
                {
                    return PartialView("~/Views/Shared/_PrintPopupPartial.cshtml",
                        new PrintGridModel(report, "devGridViewLog",
                            new { Controller = "Misc", Action = "ExportPartialLogs",
                                displayMode = "callback", exportformat = String.Empty },
                            new { Controller = "Misc", Action = "ExportPartialLogs",
                                displayMode = "export", exportformat = String.Empty }));
                }
                else if (displayMode == "callback")
                { 
                    return PartialView("~/Views/Shared/_PrintDocumentViewerPartial.cshtml",
                        new PrintGridModel(report, "devGridViewLog",
                            new { Controller = "Misc", Action = "ExportPartialLogs",
                                displayMode = "callback", exportformat = String.Empty },
                            new { Controller = "Misc", Action = "ExportPartialLogs",
                                displayMode = "export", exportformat = String.Empty }));
                }
                else if (displayMode == "export")
                {
                    switch (exportformat.ToLower())
                    {
                        case "xlsx":
                            return GridViewExtension.ExportToXlsx(settings, logModels);
                        case "xls":
                            return GridViewExtension.ExportToXls(settings, logModels);
                        case "pdf":
                            report.Name = "Logliste";
                            return DocumentViewerExtension.ExportTo(report);
                    }
                }

                return new EmptyResult();
            }
            else
                return new EmptyResult();
        }

        /// <summary>
        /// Customize created columns
        /// </summary>
        private void logGenerator_CustomizeColumnsCollection(object source, ColumnsCreationEventArgs e)
        {
            foreach (var column in e.ColumnsInfo)
            {
                if (column.ColumnCaption == "#") { column.IsVisible = false; }
                if (column.FieldName == "LogLevelDescription") { column.ColumnWidth = 60; }
                if (column.FieldName == "ShortMessage") { column.ColumnWidth = 300; }
                if (column.FieldName == "FullMessage") { column.IsVisible = false; column.IsDetail = true; }
                if (column.FieldName == "IpAddress") { column.ColumnWidth = 70; }
                if (column.FieldName == "UserDescription") { column.ColumnWidth = 70; }
                if (column.FieldName == "EntityType") { column.ColumnWidth = 60; }
                if (column.FieldName == "EntityId") { column.ColumnWidth = 50; }
                if (column.FieldName == "CreatedOnUtc") { column.ColumnWidth = 70; }
            }
        }

        /// <summary>
        /// Partial edit for editing of existing or for new log
        /// </summary>
        /// <param name="id">Id for existing log, otherweise -1.</param>
        public ActionResult ViewLog(int id = -1)
        {
            var log = _logger.GetLogById(id);
            var logModel = LogDataModel.FromLog(log, true);

            return PartialView("~/Views/Misc/_LogViewPartial.cshtml", logModel);
        }

        /// <summary>
        /// Simple JSON result for deleting a specific log
        /// </summary>
        /// <param name="id">Log id.</param>
        [HttpPost]
        public ActionResult DeleteLog(int id)
        {
            try
            {
                var log = _logger.GetLogById(id);

                if (log != null)
                    _logger.DeleteLog(log);

                return new JsonResult
                {
                    Data = "success"
                };
            }
            catch (Exception ex)
            {
                _logger.Error("Fehler bei Löschung eines Logs.", ex, _userHelper.FromCookiesOrSession());

                return PartialView("~/Views/Shared/_PopupError.cshtml", ex);
            }
        }

        #endregion

        #region ConfigItems

        /// <summary>
        /// Basic configItem view function
        /// </summary>
        [FunctionAuthorize(true, "Misc-ConfigItems")]
        public ActionResult ViewConfigItems()
        {
            var configItems = _configurationService.GetAllConfigItems();
            var configItemModels = configItems
                .Select(u => ConfigItemDataModel.FromConfigItem(u, false))
                .ToList();

            return View("~/Views/Config/View.cshtml", configItemModels);
        }

        /// <summary>
        /// Get JSON data of specific configItem
        /// </summary>
        /// <param name="id">ConfigItem id.</param>
        public ActionResult GetConfigItem(int id = -1)
        {
            var configItem = _configurationService.GetConfigItemById(id);
            if (configItem == null)
                return new JsonResult
                {
                    Data = "notFound",
                    JsonRequestBehavior = JsonRequestBehavior.AllowGet
                };

            var configItemModel = ConfigItemDataModel.FromConfigItem(configItem, false);

            return new JsonResult
            {
                Data = JsonConvert.SerializeObject(configItemModel),
                JsonRequestBehavior = JsonRequestBehavior.AllowGet
            };
        }

        /// <summary>
        /// Callback result for configItem grid
        /// </summary>
        /// <param name="scrollHeight">The height of the grid scrollable component.</param>
        public ActionResult PartialConfigItems(int scrollHeight = -1)
        {
            var configItems = _configurationService.GetAllConfigItems();
            var configItemModels = configItems
                .Select(u => ConfigItemDataModel.FromConfigItem(u, false))
                .ToList();

            ViewData["ScrollHeight"] = scrollHeight;

            return PartialView("~/Views/Config/_ConfigItemGridPartial.cshtml", configItemModels);
        }

        /// <summary>
        /// Partial edit for config item value
        /// </summary>
        /// <param name="typeFullName">Value type.</param>
        public ActionResult GetValueTypePartialEdit(string typeFullName)
        {
            var model = new ConfigItemDataModel
            {
                TypeFullName = typeFullName
            };

            if (typeFullName.StartsWith("ConfigurationReference"))
            {
                var configurationReference = ConfigurationHelper.GetConfigurationReferenceByName(typeFullName);

                if (configurationReference != null)
                {
                    model.IsValueCollection = configurationReference.IsMultipleSelection;

                    ViewData["ConfigReferenceValues"] = configurationReference.GetAvailableValues();
                }

                return PartialView("~/Views/Config/_ConfigItemReferenceEditPartial.cshtml", model);
            }
            else
                return PartialView("~/Views/Config/_ConfigItemValueEditPartial.cshtml", model);
        }

        /// <summary>
        /// Partial edit for editing of existing or for new configItem
        /// </summary>
        /// <param name="id">Id for existing configItem, otherweise -1.</param>
        public ActionResult EditConfigItem(int id = -1)
        {
            var configItem = _configurationService.GetConfigItemById(id);
            var configItemModel = ConfigItemDataModel.FromConfigItem(configItem, true);

            if (configItem != null && configItem.TypeFullName.StartsWith("ConfigurationReference"))
            {
                var configurationReference = ConfigurationHelper.GetConfigurationReferenceByName(configItem.TypeFullName);

                if (configurationReference != null)
                    ViewData["ConfigReferenceValues"] = configurationReference.GetAvailableValues();
            }

            return PartialView("~/Views/Config/_ConfigItemEditPartial.cshtml", configItemModel);
        }

        /// <summary>
        /// Partial edit result if ModelState is valid, otherwise simple JSON result for success
        /// </summary>
        /// <param name="configItemModel">ConfigItem model to be saved.</param>
        [HttpPost, ValidateInput(false)]
        public ActionResult EditConfigItem(ConfigItemDataModel configItemModel)
        {
            try
            {
                if (!ModelState.IsValid)
                    return PartialView("~/Views/Config/_ConfigItemEditPartial.cshtml", configItemModel);

                if (configItemModel.Id == -1)
                {
                    var configItem = configItemModel.ToConfigItem();

                    _configurationService.InsertConfigItem(configItem);

                    _logger.Entity(configItem, Core.Domain.Logging.LogEntityActivity.Insert, _userHelper.FromCookiesOrSession());
                }
                else
                {
                    var configItem = _configurationService.GetConfigItemById(configItemModel.Id);

                    configItem.Name = configItemModel.Name;
                    configItem.TypeFullName = configItemModel.TypeFullName;
                    configItem.Description = configItemModel.Description;

                    if (ConfigItemDataModel.FullTypeTranslations.ContainsKey(configItemModel.TypeFullName))
                    {
                        configItem.Value = configItemModel.Value;
                    }
                    else
                    {
                        var configurationReference = ConfigurationHelper.GetConfigurationReferenceByName(configItemModel.TypeFullName);

                        if (configurationReference != null)
                        {
                            if (configurationReference.IsMultipleSelection)
                                configItem.Value = configurationReference.TransformValueCollectionToValue(configItemModel.Values);
                            else
                                configItem.Value = configItemModel.Value;
                        }
                    }

                    _configurationService.UpdateConfigItem(configItem);

                    _logger.Entity(configItem, Core.Domain.Logging.LogEntityActivity.Update, _userHelper.FromCookiesOrSession());
                }

                _notificationScheduler.Start();

                return new JsonResult
                {
                    Data = "success"
                };
            }
            catch (Exception ex)
            {
                _logger.Error("Fehler bei Speicherung einer Einstellung.", ex, _userHelper.FromCookiesOrSession());

                return PartialView("~/Views/Shared/_PopupError.cshtml", ex);
            }
        }

        /// <summary>
        /// Simple JSON result for deleting a specific configItem
        /// </summary>
        /// <param name="id">ConfigItem id.</param>
        [HttpPost]
        public ActionResult DeleteConfigItem(int id)
        {
            try
            {
                var configItem = _configurationService.GetConfigItemById(id);

                if (configItem != null)
                    _configurationService.DeleteConfigItem(configItem);

                _logger.Entity(configItem, Core.Domain.Logging.LogEntityActivity.Delete, _userHelper.FromCookiesOrSession());

                return new JsonResult
                {
                    Data = "success"
                };
            }
            catch (Exception ex)
            {
                _logger.Error("Fehler bei Löschung einer Einstellung.", ex, _userHelper.FromCookiesOrSession());

                return PartialView("~/Views/Shared/_PopupError.cshtml", ex);
            }
        }

        #endregion

        #region HelpPages

        /// <summary>
        /// Default fileSaveSettings for the image uploader of the htmlEditor
        /// </summary>
        private static HtmlEditorFileSaveSettings fileSaveSettings;

        /// <summary>
        /// Default fileSaveSettings for the image uploader of the htmlEditor
        /// </summary>
        public static HtmlEditorFileSaveSettings FileSaveSettings
        {
            get
            {
                if (fileSaveSettings == null)
                {
                    fileSaveSettings = new HtmlEditorFileSaveSettings();
                    fileSaveSettings.FileSystemSettings.UploadFolder = "../Content/Images/HelpPages/";
                }
                return fileSaveSettings;
            }
        }

        /// <summary>
        /// Default validationSettings for the image uploader of the htmlEditor
        /// </summary>
        public static readonly UploadControlValidationSettings ImageUploadValidationSettings = new UploadControlValidationSettings
        {
            AllowedFileExtensions = new string[] { ".jpg", ".jpeg", ".jpe", ".gif", ".png" },
            MaxFileSize = 4000000
        };

        /// <summary>
        /// Creates the helpPage tree recursively
        /// </summary>
        /// <param name="models">Full helpPage model list.</param>
        /// <param name="nodesCollection">Parent node collection.</param>
        /// <param name="parentID">Parent node id.</param>
        public static void CreateHelpPageTree(IEnumerable<HelpPageDataModel> models, MVCxTreeViewNodeCollection nodesCollection, 
            int? parentID)
        {
            var children = models
                .Where(p => p.ParentId == parentID);

            foreach (var model in children)
            {
                var node = nodesCollection.Add(model.Title, model.Id.ToString());
                node.Expanded = true;

                CreateHelpPageTree(models, node.Nodes, model.Id);
            }
        }

        /// <summary>
        /// Basic helpPage view function
        /// </summary>
        /// <param name="id">Id of initial editing helpPage.</param>
        [FunctionAuthorize(true, "Misc-HelpPages")]
        public ActionResult ViewHelpPages(int id = -1)
        {
            var helpPages = _miscService.GetAllHelpPagesWithoutContent();
            var helpPageModels = helpPages
                .Select(u => HelpPageDataModel.FromHelpPage(u, false))
                .OrderBy(u => u.DisplayIndex)
                .ToList();

            var initialHelpPageModelExists = helpPageModels
                .Any(p => p.Id == id);

            if (initialHelpPageModelExists)
                ViewData["InitialEditHelpPage"] = id;

            ViewData["IsHelpPageSelectionTree"] = false;

            return View("~/Views/Misc/HelpPages.cshtml", helpPageModels);
        }

        /// <summary>
        /// Callback result for editing of help page
        /// </summary>
        /// <param name="helpPageModel">HelpPage model to be edited.</param>
        public ActionResult PartialHtmlEditor(HelpPageDataModel helpPageModel)
        {
            return PartialView("~/Views/Misc/_HelpPageHtmlEditPartial.cshtml", helpPageModel);
        }

        /// <summary>
        /// Callback result for processing the upload of an image for a helpPage
        /// </summary>
        public ActionResult UploadProcessingImageUpload()
        {
            FileSavingEventHandler onFileSaving = (s, e) => {
                using (var fileContent = e.UploadedFile.FileContent)
                {
                    using (var image = System.Drawing.Image.FromStream(fileContent))
                    {
                        var memoryStream = new MemoryStream();

                        image.Save(memoryStream, image.RawFormat);

                        e.OutputStream = memoryStream;

                        e.FileName = e.UploadedFile.FileName;
                    }
                }
            };

            HtmlEditorExtension.SaveUploadedFile(FileSaveSettings, ImageUploadValidationSettings, onFileSaving);

            return null;
        }

        /// <summary>
        /// Get JSON data of specific helpPage
        /// </summary>
        /// <param name="id">HelpPage id.</param>
        public ActionResult GetHelpPage(int id = -1)
        {
            var helpPage = _miscService.GetHelpPageById(id);
            if (helpPage == null)
                return new JsonResult
                {
                    Data = "notFound",
                    JsonRequestBehavior = JsonRequestBehavior.AllowGet
                };

            var helpPageModel = HelpPageDataModel.FromHelpPage(helpPage, false);

            return new JsonResult
            {
                Data = JsonConvert.SerializeObject(helpPageModel),
                JsonRequestBehavior = JsonRequestBehavior.AllowGet
            };
        }

        /// <summary>
        /// Partial edit for editing of existing or for new helpPage
        /// </summary>
        /// <param name="id">Id for existing helpPage, otherweise -1.</param>
        public ActionResult ViewHelpPage(int id = -1)
        {
            var helpPage = _miscService.GetHelpPageById(id);
            var helpPageModel = HelpPageDataModel.FromHelpPage(helpPage, true);

            if (helpPage != null)
                return PartialView("~/Views/Misc/_HelpPageViewPartial.cshtml", helpPageModel);

            return new EmptyResult();
        }

        /// <summary>
        /// Partial edit for editing of existing or for new helpPage
        /// </summary>
        /// <param name="id">Id for existing helpPage, otherweise -1.</param>
        public ActionResult EditHelpPage(int id = -1)
        {
            var helpPages = _miscService.GetAllHelpPages();
            var helpPageModels = helpPages
                .Select(u => HelpPageDataModel.FromHelpPage(u, false))
                .ToList();

            var helpPage = _miscService.GetHelpPageById(id);
            var helpPageModel = HelpPageDataModel.FromHelpPage(helpPage, true);

            ViewData["AllHelpPages"] = helpPageModels;
            ViewData["IsHelpPageSelectionTree"] = true;

            return PartialView("~/Views/Misc/_HelpPageEditPartial.cshtml", helpPageModel);
        }

        /// <summary>
        /// Partial edit result if ModelState is valid, otherwise simple JSON result for success
        /// </summary>
        /// <param name="helpPageModel">HelpPage model to be saved.</param>
        [HttpPost, ValidateInput(false)]
        public ActionResult EditHelpPage(HelpPageDataModel helpPageModel)
        {
            try
            {
                if (!ModelState.IsValid)
                {
                    var helpPages = _miscService.GetAllHelpPages();
                    var helpPageModels = helpPages
                        .Select(u => HelpPageDataModel.FromHelpPage(u, false))
                        .ToList();

                    ViewData["IsHelpPageSelectionTree"] = true;
                    ViewData["AllHelpPages"] = helpPageModels;

                    return PartialView("~/Views/Misc/_HelpPageEditPartial.cshtml", helpPageModel);
                }

                if (helpPageModel.Id == -1)
                {
                    var helpPage = helpPageModel.ToHelpPage();

                    _miscService.InsertHelpPage(helpPage);

                    _logger.Entity(helpPage, Core.Domain.Logging.LogEntityActivity.Insert, _userHelper.FromCookiesOrSession());

                    return new JsonResult
                    {
                        Data = String.Format("success-{0}", helpPage.Id)
                    };
                }
                else
                {
                    var helpPage = _miscService.GetHelpPageById(helpPageModel.Id);

                    helpPage.Title = helpPageModel.Title;
                    helpPage.Content = helpPageModel.Content;
                    helpPage.ParentId = helpPageModel.ParentId;
                    helpPage.DisplayIndex = helpPageModel.DisplayIndex;

                    _miscService.UpdateHelpPage(helpPage);

                    _logger.Entity(helpPage, Core.Domain.Logging.LogEntityActivity.Update, _userHelper.FromCookiesOrSession());

                    return new JsonResult
                    {
                        Data = String.Format("success-{0}", helpPage.Id)
                    };
                }
            }
            catch (Exception ex)
            {
                _logger.Error("Fehler bei Speicherung einer Hilfe-Seite.", ex, _userHelper.FromCookiesOrSession());

                return PartialView("~/Views/Shared/_PopupError.cshtml", ex);
            }
        }

        /// <summary>
        /// Simple JSON result for deleting a specific helpPage
        /// </summary>
        /// <param name="id">HelpPage id.</param>
        [HttpPost]
        public ActionResult DeleteHelpPage(int id)
        {
            try
            {
                var helpPage = _miscService.GetHelpPageById(id);

                if (helpPage != null)
                    _miscService.DeleteHelpPage(helpPage);

                return new JsonResult
                {
                    Data = "success"
                };
            }
            catch (Exception ex)
            {
                _logger.Error("Fehler bei Löschung einer Hilfe-Seite.", ex, _userHelper.FromCookiesOrSession());

                return PartialView("~/Views/Shared/_PopupError.cshtml", ex);
            }
        }

        #endregion
    }
}