using System;
using System.Collections.Generic;
using FastReport.Export.Image;
using FastReport.Export.RichText;
using FastReport.Export.Xml;
using FastReport.Export.Html;
using FastReport.Export.Mht;
using FastReport.Export.Odf;
using FastReport.Export.Pdf;
using FastReport.Export.Csv;
using FastReport.Export.Dbf;
using FastReport.Export.Dxf;
using FastReport.Export.XAML;
using FastReport.Export.Svg;
using FastReport.Export.Ppml;
using FastReport.Export.PS;
using FastReport.Export.BIFF8;
using FastReport.Export.OoXML;
using FastReport.Export.Json;
using FastReport.Export.LaTeX;
using FastReport.Export.Text;
using FastReport.Export.Zpl;
using FastReport.Cloud.StorageClient;
using FastReport.Messaging;
using FastReport.Export;
using FastReport.Cloud.StorageClient.Ftp;
using FastReport.Cloud.StorageClient.Box;
using FastReport.Cloud.StorageClient.Dropbox;
using FastReport.Cloud.StorageClient.GoogleDrive;
using FastReport.Cloud.StorageClient.SkyDrive;

namespace FastReport.Utils
{
#if !COMMUNITY
    public partial class ExportsOptions
    {
        public partial class ExportsTreeNode
        {
            private const string CLOUD_ITEM_PREFIX = "Cloud,";
            private const string MESSENGER_ITEM_PREFIX = "Messaging,";

            public override string ToString()
            {
                string resPath;
                if (exportType == null)
                {
                    resPath = CATEGORY_PREFIX + name;
                }
                else
                {
                    if (exportType.IsSubclassOf(typeof(ExportBase)))
                    {
                        resPath = EXPORT_ITEM_PREFIX + name + EXPORT_ITEM_POSTFIX;
                    }
                    else
                    {
                        resPath = (exportType.IsSubclassOf(typeof(CloudStorageClient))
                            ? CLOUD_ITEM_PREFIX : MESSENGER_ITEM_PREFIX) + name + ITEM_POSTFIX;
                    }
                }
                return Res.Get(resPath);
            }
        }

        /// <summary>
        /// Default Exports menu
        /// </summary>
        /// <returns>Tree that contains default Exports menu</returns>
        public List<ExportsTreeNode> DefaultExports()
        {
            List<ExportsTreeNode> defaultMenu = new List<ExportsTreeNode>();

            defaultMenu.Add(new ExportsTreeNode("Pdf", typeof(PDFExport), 201, true, RegisteredObjects.FindExport(typeof(PDFExport))));
            defaultMenu.Add(new ExportsTreeNode("Office", 190, true));
            defaultMenu[1].Nodes.Add(new ExportsTreeNode("RichText", typeof(RTFExport), 190, true, RegisteredObjects.FindExport(typeof(RTFExport))));
            defaultMenu[1].Nodes.Add(new ExportsTreeNode("Xlsx", typeof(Excel2007Export), 191, true, RegisteredObjects.FindExport(typeof(Excel2007Export))));
            defaultMenu[1].Nodes.Add(new ExportsTreeNode("Xls", typeof(Excel2003Document), 191, true, RegisteredObjects.FindExport(typeof(Excel2003Document))));
            defaultMenu[1].Nodes.Add(new ExportsTreeNode("Docx", typeof(Word2007Export), 190, true, RegisteredObjects.FindExport(typeof(Word2007Export))));
            defaultMenu[1].Nodes.Add(new ExportsTreeNode("Pptx", typeof(PowerPoint2007Export), true, RegisteredObjects.FindExport(typeof(PowerPoint2007Export))));
            defaultMenu[1].Nodes.Add(new ExportsTreeNode("Ods", typeof(ODSExport), true, RegisteredObjects.FindExport(typeof(ODSExport))));
            defaultMenu[1].Nodes.Add(new ExportsTreeNode("Odt", typeof(ODTExport), true, RegisteredObjects.FindExport(typeof(ODTExport))));
            defaultMenu.Add(new ExportsTreeNode("XML", 191, true));
            defaultMenu[2].Nodes.Add(new ExportsTreeNode("Xml", typeof(XMLExport), true, RegisteredObjects.FindExport(typeof(XMLExport))));
            defaultMenu[2].Nodes.Add(new ExportsTreeNode("Xaml", typeof(XAMLExport), true, RegisteredObjects.FindExport(typeof(XAMLExport))));
            defaultMenu.Add(new ExportsTreeNode("Web", 246, true));
            defaultMenu[3].Nodes.Add(new ExportsTreeNode("Html", typeof(HTMLExport), true, RegisteredObjects.FindExport(typeof(HTMLExport))));
            defaultMenu[3].Nodes.Add(new ExportsTreeNode("Mht", typeof(MHTExport), true, RegisteredObjects.FindExport(typeof(MHTExport))));
            defaultMenu.Add(new ExportsTreeNode("Image", 103, true));
            defaultMenu[4].Nodes.Add(new ExportsTreeNode("Image", typeof(ImageExport), true, RegisteredObjects.FindExport(typeof(ImageExport))));
            defaultMenu[4].Nodes.Add(new ExportsTreeNode("Svg", typeof(SVGExport), true, RegisteredObjects.FindExport(typeof(SVGExport))));
            defaultMenu.Add(new ExportsTreeNode("DataBase", 53, true));
            defaultMenu[5].Nodes.Add(new ExportsTreeNode("Csv", typeof(CSVExport), true, RegisteredObjects.FindExport(typeof(CSVExport))));
            defaultMenu[5].Nodes.Add(new ExportsTreeNode("Dbf", typeof(DBFExport), true, RegisteredObjects.FindExport(typeof(DBFExport))));
            defaultMenu[5].Nodes.Add(new ExportsTreeNode("Json", typeof(JsonExport), true, RegisteredObjects.FindExport(typeof(JsonExport))));
            defaultMenu.Add(new ExportsTreeNode("Print", 195, true));
            defaultMenu[6].Nodes.Add(new ExportsTreeNode("Text", typeof(TextExport), true, RegisteredObjects.FindExport(typeof(TextExport))));
            defaultMenu[6].Nodes.Add(new ExportsTreeNode("Zpl", typeof(ZplExport), true, RegisteredObjects.FindExport(typeof(ZplExport))));
            defaultMenu[6].Nodes.Add(new ExportsTreeNode("Ppml", typeof(PPMLExport), true, RegisteredObjects.FindExport(typeof(PPMLExport))));
            defaultMenu[6].Nodes.Add(new ExportsTreeNode("PS", typeof(PSExport), true, RegisteredObjects.FindExport(typeof(PSExport))));
            defaultMenu.Add(new ExportsTreeNode("Other", true));
            defaultMenu[7].Nodes.Add(new ExportsTreeNode("Xps", typeof(XPSExport), true, RegisteredObjects.FindExport(typeof(XPSExport))));
            defaultMenu[7].Nodes.Add(new ExportsTreeNode("LaTeX", typeof(LaTeXExport), true, RegisteredObjects.FindExport(typeof(LaTeXExport))));
            defaultMenu[7].Nodes.Add(new ExportsTreeNode("Dxf", typeof(DxfExport), true, RegisteredObjects.FindExport(typeof(DBFExport))));

            return defaultMenu;
        }

        private ExportsTreeNode cloudNodes;
        private ExportsTreeNode messengerNodes = new ExportsTreeNode("Messengers", false);

        /// <summary>
        /// All cloud exports available in the preview.
        /// </summary>
        public ExportsTreeNode CloudMenu
        {
            get
            {
                if (cloudNodes.Nodes.Count <= 0)
                    RestoreOptionsFor("Cloud");
                return cloudNodes;
            }
        }

        /// <summary>
        /// All messengers exports available in the preview.
        /// </summary>
        public ExportsTreeNode MessengerMenu
        {
            get
            {
                if (messengerNodes.Nodes.Count <= 0)
                    RestoreOptionsFor("Messenger");
                return messengerNodes;
            }
        }

        /// <summary>
        /// Default cloud exports menu.
        /// </summary>
        /// <returns>Tree that contains default cloud exports menu.</returns>
        public ExportsTreeNode DefaultCloud()
        {
            cloudNodes = new ExportsTreeNode("Cloud", 238, false);
            cloudNodes.Nodes.Add(new ExportsTreeNode("Ftp", typeof(FtpStorageClient), false, RegisteredObjects.FindObject(typeof(FtpStorageClient))));
            cloudNodes.Nodes.Add(new ExportsTreeNode("Box", typeof(BoxStorageClient), 238, false, RegisteredObjects.FindObject(typeof(BoxStorageClient))));
            cloudNodes.Nodes.Add(new ExportsTreeNode("Dropbox", typeof(DropboxStorageClient), 238, false, RegisteredObjects.FindObject(typeof(DropboxStorageClient))));
            cloudNodes.Nodes.Add(new ExportsTreeNode("GoogleDrive", typeof(GoogleDriveStorageClient), 238, false, RegisteredObjects.FindObject(typeof(GoogleDriveStorageClient))));
            cloudNodes.Nodes.Add(new ExportsTreeNode("SkyDrive", typeof(SkyDriveStorageClient), 238, false, RegisteredObjects.FindObject(typeof(SkyDriveStorageClient))));

            return cloudNodes;
        }

        /// <summary>
        /// Default messengers.
        /// </summary>
        /// <returns></returns>
        public ExportsTreeNode DefaultMessengers()
        {
            messengerNodes = new ExportsTreeNode("Messengers", false);
            //messengerNodes.Nodes.Add(new ExportsTreeNode("Xmpp", typeof(XmppMessenger), false));

            return messengerNodes;
        }

        /// <summary>
        /// Register all clouds.
        /// </summary>
        public void RegisterClouds()
        {
            foreach (ExportsTreeNode node in cloudNodes.Nodes)
            {
                var tag = RegisteredObjects.AddCloud(node.ExportType, node.ToString(), node.ImageIndex);
                node.Tag = tag;
            }
        }

        /// <summary>
        /// Register all messengers.
        /// </summary>
        public void RegisterMessengers()
        {
            foreach (ExportsTreeNode node in messengerNodes.Nodes)
            {
                var tag = RegisteredObjects.InternalAddMessenger(node.ExportType, node.ToString());
                node.Tag = tag;
            }
        }

        private XmlItem SaveItem(ExportsTreeNode node)
        {
            XmlItem newItem = new XmlItem();
            newItem.Name = node.Name;
            if (node.ExportType != null)
            {
                newItem.SetProp("ExportType", node.ExportType.FullName);
            }
            if (node.ImageIndex != -1)
            {
                newItem.SetProp("Icon", node.ImageIndex.ToString());
            }
            newItem.SetProp("Enabled", node.Enabled.ToString());
            return newItem;
        }

        private void SaveMenuTree(XmlItem xi, List<ExportsTreeNode> nodes)
        {
            xi.Items.Clear();

            foreach (ExportsTreeNode node in nodes)
            {
                if (node.ContainsIn(DefaultExports()) || node.Equals(DefaultCloud()) || node.ContainsIn(DefaultCloud()))
                    continue;

                XmlItem newItem = SaveItem(node);
                xi.Items.Add(newItem);
                if (node.Nodes.Count != 0)
                {
                    SaveMenuTree(newItem, node.Nodes);
                }
            }
        }

        private void UpdateExportItemInConfig(XmlItem item)
        {
            Type exportType = Type.GetType(item.GetProp("ExportType"));
            bool isExport = exportType != null && item.Name != "Cloud" && item.Name != "Messengers" &&
                !exportType.IsSubclassOf(typeof(CloudStorageClient)) &&
                !exportType.IsSubclassOf(typeof(MessengerBase));

            if (isExport && item.GetProp("Enabled").ToLower() == "true")
            {
                PreviewExports type;
                bool parsed = Enum.TryParse(exportType.Name, out type);
                if (parsed)
                    Config.PreviewSettings.Exports |= type;
            }
        }

        /// <summary>
        /// Update Config.PreviewSettings.Exports property.
        /// </summary>
        private void UpdateExportsInConfig(XmlItem exportsItem)
        {
            if ((Config.PreviewSettings.Exports & PreviewExports.Prepared) != 0)
            {
                Config.PreviewSettings.Exports = PreviewExports.Prepared;
            }
            else
            {
                Config.PreviewSettings.Exports = PreviewExports.None;
            }
                        
            foreach (XmlItem item in exportsItem.Items)
            {
                if (item.Items.Count > 0)
                {
                    foreach (XmlItem subItem in item.Items)
                    {
                        UpdateExportItemInConfig(subItem);
                    }
                }
                else
                {
                    UpdateExportItemInConfig(item);
                }
            }
        }

        /// <summary>
        /// Update Config.PreviewSettings.Clouds property.
        /// </summary>
        private void UpdateCloudsInConfig(XmlItem cloudsItem)
        {
            Config.PreviewSettings.Clouds = PreviewClouds.None;
            Type exportType;
            bool isCloud;

            foreach (XmlItem item in cloudsItem.Items)
            {
                exportType = Type.GetType(item.GetProp("ExportType"));
                isCloud = item.Name != "Cloud" && item.Name != "Messengers" &&
                    exportType != null && exportType.IsSubclassOf(typeof(CloudStorageClient));
                if (isCloud && item.GetProp("Enabled").ToLower() == "true")
                {
                    PreviewClouds type;
                    bool parsed = Enum.TryParse(exportType.Name.Replace("StorageClient", ""), out type);
                    if (parsed)
                    {
                        Config.PreviewSettings.Clouds |= type;
                    }
                }
            }
        }

        /// <summary>
        /// Update Config.PreviewSettings.Messengers property.
        /// </summary>
        private void UpdateMessengersInConfig(XmlItem messengersItem)
        {
            Config.PreviewSettings.Messengers = PreviewMessengers.None;
            Type exportType;
            bool isMessenger;

            foreach (XmlItem item in messengersItem.Items)
            {
                exportType = Type.GetType(item.GetProp("ExportType"));
                isMessenger = item.Name != "Cloud" && item.Name != "Messengers" &&
                    exportType != null && exportType.IsSubclassOf(typeof(MessengerBase));
                if (isMessenger && item.GetProp("Enabled").ToLower() == "true")
                {
                    PreviewMessengers type;
                    bool parsed = Enum.TryParse(exportType.Name.Replace("Messenger", ""), out type);
                    if (parsed)
                    {
                        Config.PreviewSettings.Messengers |= type;
                    }
                }
            }
        }

        /// <summary>
        /// Update  availability of exports, clouds and messengers in Config.
        /// </summary>
        public void UpdateConfig()
        {
            UpdateExportsInConfig(Config.Root.FindItem("ExportOptions"));
            UpdateCloudsInConfig(Config.Root.FindItem("Cloud"));
            UpdateMessengersInConfig(Config.Root.FindItem("Messengers"));
        }

        private void SaveExportOption(string option)
        {
            XmlItem options = Config.Root.FindItem(option);

            List<ExportsTreeNode> nodes;
            if (option == "ExportOptions")
            {
                RemoveCloudsAndMessengersDuplicatesInMenuNodes();
                nodes = menuNodes;
            }
            else if (option == "Cloud")
            {
                if (Config.PreviewSettings.Clouds != PreviewClouds.None)
                {
                    cloudNodes.Enabled = true;
                }
                options.SetProp("Enabled", cloudNodes.Enabled.ToString());
                options.SetProp("Icon", cloudNodes.ImageIndex.ToString());
                nodes = cloudNodes.Nodes;
            }
            else
            {
                if (Config.PreviewSettings.Messengers != PreviewMessengers.None)
                {
                    messengerNodes.Enabled = true;
                }
                //options.SetProp("Enabled", messengerNodes.Enabled.ToString());
                options.SetProp("Enabled", "false");
                nodes = messengerNodes.Nodes;
            }
            SaveMenuTree(options, nodes);
        }

        private ExportsTreeNode RestoreItem(XmlItem item)
        {
            Type exportType = null;
            string typeProp = item.GetProp("ExportType");
            if (!string.IsNullOrEmpty(typeProp))
            {
                exportType = Type.GetType(typeProp);
            }

            string imageIndexProp = item.GetProp("Icon");
            int imageIndex = -1;
            if (!string.IsNullOrEmpty(imageIndexProp))
            {
                int.TryParse(imageIndexProp, out imageIndex);
            }

            string enabledProp = item.GetProp("Enabled");
            bool enabled = true;
            if (!string.IsNullOrEmpty(enabledProp) && Config.PreviewSettings.Exports != PreviewExports.All)
            {
                bool.TryParse(enabledProp, out enabled);
            }

            bool isExport = item.Name != "Cloud" && item.Name != "Messengers" &&
                (exportType != null && !exportType.IsSubclassOf(typeof(CloudStorageClient)) &&
                !exportType.IsSubclassOf(typeof(MessengerBase)) || exportType == null);
            if (isExport && Config.PreviewSettings.Exports != PreviewExports.All && exportType != null)
            {
                enabled = Config.PreviewSettings.Exports.ToString().ToLower().Contains(exportType.Name.ToLower());
            }

            bool isCloud = item.Name != "Cloud" && item.Name != "Messengers" &&
                exportType != null && exportType.IsSubclassOf(typeof(CloudStorageClient));
            if (isCloud && Config.PreviewSettings.Clouds != PreviewClouds.All && exportType != null)
            {
                enabled = Config.PreviewSettings.Clouds.ToString().Contains(exportType.Name.Replace("StorageClient", ""));
            }

            bool isMessenger = item.Name != "Cloud" && item.Name != "Messengers" &&
                exportType != null && exportType.IsSubclassOf(typeof(MessengerBase));
            if (isMessenger && Config.PreviewSettings.Messengers != PreviewMessengers.All && exportType != null)
            {
                enabled = false;//Config.PreviewSettings.Messengers.ToString().Contains(exportType.Name.Replace("Messenger", ""));
            }

            return new ExportsTreeNode(item.Name, exportType, imageIndex, enabled, isExport);
        }

        private void RestoreMenuTree(XmlItem xi, List<ExportsTreeNode> nodes)
        {
            foreach (XmlItem item in xi.Items)
            {
                ExportsTreeNode currentNode = RestoreItem(item);

                if (item.Items.Count > 0)
                {
                    RestoreMenuTree(item, currentNode.Nodes);
                    currentNode.Enabled = false;
                    foreach (ExportsTreeNode subNode in currentNode.Nodes)
                    {
                        if (subNode.Enabled)
                        {
                            currentNode.Enabled = true;
                            break;
                        }
                    }

                    foreach (ExportsTreeNode node in nodes)
                    {
                        if (node.Name == currentNode.Name && !node.Equals(currentNode))
                        {
                            foreach(ExportsTreeNode subNode in node.Nodes)
                                foreach(ExportsTreeNode currentSubNode in currentNode.Nodes)
                                    if (subNode.Name == currentSubNode.Name)
                                        subNode.Enabled = currentSubNode.Enabled;
                        }
                    }
                }

                if (currentNode.ContainsIn(DefaultExports()) || currentNode.Equals(DefaultCloud()) || currentNode.ContainsIn(DefaultCloud()))
                {
                    continue;
                }
                nodes.Add(currentNode);
            }
        }

        private void RestoreOptionsFor(string option)
        {
            XmlItem options = Config.Root.FindItem(option);

            List<ExportsTreeNode> nodes = null;
            if (option == "ExportOptions")
            {
                nodes = menuNodes;
                menuNodes.AddRange(DefaultExports());
            }
            else if (option == "Cloud")
            {
                cloudNodes = DefaultCloud();
                cloudNodes.Enabled = RestoreItem(options).Enabled;
                nodes = cloudNodes.Nodes;
                if (Config.PreviewSettings.Clouds == PreviewClouds.None)
                {
                    cloudNodes.Enabled = false;
                }
            }
            //else
            //{
            //    messengerNodes = RestoreItem(options);
            //    nodes = messengerNodes.Nodes;
            //    if (options.Items.Count == 0)
            //    {
            //        messengerNodes = DefaultMessengers();
            //    }
            //    if (Config.PreviewSettings.Messengers == PreviewMessengers.None)
            //    {
            //        messengerNodes.Enabled = false;
            //    }
            //}
            if (options.Items.Count != 0)
            {
                RestoreMenuTree(options, nodes);
            }
        }

        private void RestoreOptions()
        {
            RestoreOptionsFor("ExportOptions");
            RestoreOptionsFor("Cloud");
            //RestoreOptionsFor("Messengers");
        }

        private void SaveOptions()
        {
            SaveExportOption("ExportOptions");
            SaveExportOption("Cloud");
            //SaveExportOption("Messengers");
            UpdateConfig();
        }
    }
#endif
}
