using System;
using System.Collections;
using System.Text;
using System.IO;
using Ecrion.Ultrascale;

namespace XFDesktopEngineSample
{
    /// <summary>
    /// 
    /// </summary>
    public class CommandLineParameters
    {
        public Engine.InputFormat inputFormat;
        public Engine.OutputFormat outputFormat;
        public string templateName = "";
        public string serverTemplateID = "";
        public bool isMergeOperation = false;
        public string PrinterName = "";

        int xResolution = 0;
        int yResolution = 0;
        int pageIdx = -1;
        Engine.AFPFlags afpOutputFlags = Engine.AFPFlags.UseNativeRasterFonts;
        Engine.PDFFlags pdfOutputFlags = 0;
        Engine.PDFPermissionFlags pdfPermissionsFlags = 0;
        int pdfEncryptionStrength = 0;
        Engine.ReferenceResolverType referenceResolverType = Engine.ReferenceResolverType.Parallel;
        bool preloadDocument = false;
        Engine.ImageErrorsHandlingMode imgErrMode = Engine.ImageErrorsHandlingMode.IgnoreAndDisplayImageNotFound;
        Engine.CompressionAlgorithm encCompType = Engine.CompressionAlgorithm.None;
        Engine.SmoothingMode smoothingMode = Engine.SmoothingMode.Default;
        float zoom = 1;
        string userName = "Guest";
        string password = "";
        Engine.XsltEngine xsltEngine = Engine.XsltEngine.DotNet20;
        string languageID = "";
        string pdfUserPassword = "";
        string pdfOwnerPassword = "";
        string outputPrintFile = "";

        Engine.PDFImageCompression pdfImageCompression = Engine.PDFImageCompression.JPEG;
        Engine.HtmlInputSettings htmlInptSettings = new Engine.HtmlInputSettings();
        Engine.HtmlOutputSettings htmlOuptSettings = new Engine.HtmlOutputSettings();
        
        
        Hashtable xsltParameters = new Hashtable();

        /// <summary>
        /// Parse a command line string
        /// </summary>
        /// <param name="paramsList">-parameters:p1=v1;p2=v2;...pn=vn</param>
        /// <param name="printInfo">Print parsed values to the standard output.</param>
        /// <returns>A new RenderingParameters instance.</returns>
        public void Parse(String paramsList, bool printInfo)
        {
            if (paramsList.Length == 0)
                return;

            paramsList = paramsList.Substring(12);
            string[] paramPairs = paramsList.Split(';');

            foreach (String paramPair in paramPairs)
            {
                string[] paramNameVal = paramPair.Split('=');

                if (paramNameVal.Length == 2)
                {
                    switch (paramNameVal[0])
                    {
                        case "merge":
                            if (paramNameVal[1] == "true")
                            {
                                isMergeOperation = true;
                                if (printInfo)
                                    Console.Out.WriteLine("This is a \'merge\' operation.");
                            }
                            break;
                        case "logfile":
                            Settings.Log.LogFile = paramNameVal[1];
                            if (printInfo)
                                Console.Out.WriteLine(String.Format("Log file set to '{0}'.", paramNameVal[1]));
                            break;
                        case "loglevel":
                            switch (paramNameVal[1].ToUpper())
                            {
                                case "NONE":
                                    Settings.Log.LogLevel = LogLevel.None;
                                    if (printInfo)
                                        Console.Out.WriteLine("Log level set to 'None'.");
                                    break;
                                case "ERRORS":
                                    Settings.Log.LogLevel = LogLevel.Errors;
                                    if (printInfo)
                                        Console.Out.WriteLine("Log level set to 'Errors'.");
                                    break;
                                case "ALL":
                                    Settings.Log.LogLevel = LogLevel.All;
                                    if (printInfo)
                                        Console.Out.WriteLine("Log level set to 'all'.");
                                    break;
                            }
                            break;
                        case "resolution":
                            xResolution = yResolution = Int32.Parse(paramNameVal[1]);
                            if (printInfo)
                                Console.Out.WriteLine("X/Y resolution set to {0}.", xResolution);
                            break;
                        case "pageidx":
                            pageIdx = Int32.Parse(paramNameVal[1]);
                            if (printInfo)
                                Console.Out.WriteLine("Page index set to {0}.", pageIdx);
                            break;
                        case "afpconverttograyscale":
                            if (paramNameVal[1] == "true")
                            {
                                afpOutputFlags |= Engine.AFPFlags.ConvertColorsToGrayscale;
                                if (printInfo)
                                    Console.Out.WriteLine("Flag Engine.AFPFlags.ConvertColorsToGrayscale is set.");
                            }
                            break;
                        case "pdfconformance":
                            switch (paramNameVal[1].ToUpper())
                            {
                                case "PDF1.4":
                                    pdfOutputFlags |= Engine.PDFFlags.PDF14;
                                    if (printInfo)
                                        Console.Out.WriteLine("Flag Engine.PDFFlags.PDF14 is set");
                                    break;
                                case "PDF_X":
                                    pdfOutputFlags |= Engine.PDFFlags.PDFX;
                                    if (printInfo)
                                        Console.Out.WriteLine("Flag Engine.PDFFlags.PDFX is set");
                                    break;
                                case "PDFA_1A":
                                    pdfOutputFlags |= Engine.PDFFlags.PDFA_1A;
                                    if (printInfo)
                                        Console.Out.WriteLine("Flag Engine.PDFFlags.PDFA_1A is set");
                                    break;
                                case "PDFA_1B":
                                    pdfOutputFlags |= Engine.PDFFlags.PDFA_1B;
                                    if (printInfo)
                                        Console.Out.WriteLine("Flag Engine.PDFFlags.PDFA_1B is set");
                                    break;
                                default:
                                    if (printInfo)
                                        Console.Out.WriteLine("Unrecognized pdf conformance");
                                    break;
                            }
                            break;
                        case "pdfpermissions":
                            {
                                char[] separator = { ',', ' ' };
                                string[] permissions = paramNameVal[1].Split(separator);
                                for (int i = 0; i < permissions.Length; ++i)
                                    switch (permissions[i].ToUpper())
                                    {
                                        case "ALLOWPRINTING":
                                            pdfPermissionsFlags |= Engine.PDFPermissionFlags.AllowPrinting;
                                            break;
                                        case "ALLOWMODIFYCONTENTS":
                                            pdfPermissionsFlags |= Engine.PDFPermissionFlags.AllowModifyContents;
                                            break;
                                        case "ALLOWCOPY":
                                            pdfPermissionsFlags |= Engine.PDFPermissionFlags.AllowCopy;
                                            break;
                                        case "ALLOWMODIFYANNOTATIONS":
                                            pdfPermissionsFlags |= Engine.PDFPermissionFlags.AllowModifyAnnotations;
                                            break;
                                        case "ALLOWFILLIN":
                                            pdfPermissionsFlags |= Engine.PDFPermissionFlags.AllowFillIn;
                                            break;
                                        case "ALLOWSCREENREADERS":
                                            pdfPermissionsFlags |= Engine.PDFPermissionFlags.AllowScreenReaders;
                                            break;
                                        case "ALLOWASSEMBLY":
                                            pdfPermissionsFlags |= Engine.PDFPermissionFlags.AllowAssembly;
                                            break;
                                        case "ALLOWDEGRADEDPRINTING":
                                            pdfPermissionsFlags |= Engine.PDFPermissionFlags.AllowDegradedPrinting;
                                            break;
                                        default:
                                            if (printInfo)
                                                Console.Out.WriteLine(String.Format("Unrecognized PDF permission: {0}", permissions[i]));
                                            break;
                                    }
                                if (printInfo)
                                    Console.Out.WriteLine("PDF permissions flags are set.");
                                break;
                            }
                        case "pdfuserpassword":
                            pdfUserPassword = paramNameVal[1];
                            if (printInfo)
                                Console.Out.WriteLine("PDF user password is set");
                            break;
                        case "pdfownerpassword":
                            pdfOwnerPassword = paramNameVal[1];
                            if (printInfo)
                                Console.Out.WriteLine("PDF owner password is set");
                            break;
                        case "printername":
                            PrinterName = paramNameVal[1];
                            if (printInfo)
                                Console.Out.WriteLine("Printer name set");
                            break;
                        case "outputprintfile":
                            outputPrintFile = paramNameVal[1];
                            if (printInfo)
                                Console.Out.WriteLine("Output print file set to {0}", outputPrintFile);
                            break;
                        case "pdfencryptionstrength":
                            pdfEncryptionStrength = Convert.ToInt32(paramNameVal[1]);

                            if (pdfEncryptionStrength == 40 || pdfEncryptionStrength == 128)
                                if (printInfo)
                                    Console.Out.WriteLine("Encryption strength is set");
                                else
                                    if (printInfo)
                                        Console.Out.WriteLine("Valid values for encryption strength are 128 and 40. Encryption strength could not be set.");
                            break;
                        case "useresolverthread":
                            if (paramNameVal[1] == "false")
                            {
                                referenceResolverType = Engine.ReferenceResolverType.Serial;
                                if (printInfo)
                                    Console.Out.WriteLine("Serial resolver is enabled.");
                            }
                            else if (paramNameVal[1] == "true")
                            {
                                referenceResolverType = Engine.ReferenceResolverType.Parallel;
                                if (printInfo)
                                    Console.Out.WriteLine("Resolver thread is enabled.");
                            }
                            break;
                        case "referenceresolvertype":
                            if (paramNameVal[1] == "parallel")
                            {
                                referenceResolverType = Engine.ReferenceResolverType.Parallel;
                                if (printInfo)
                                    Console.Out.WriteLine("Resolver thread is enabled.");
                            }
                            else if (paramNameVal[1] == "serial")
                            {
                                referenceResolverType = Engine.ReferenceResolverType.Serial;
                                if (printInfo)
                                    Console.Out.WriteLine("Serial resolver is enabled.");
                            }
                            else if (paramNameVal[1] == "disabled")
                            {
                                referenceResolverType = Engine.ReferenceResolverType.Disabled;
                                if (printInfo)
                                    Console.Out.WriteLine("Reference resolving is disabled.");
                            }
                            
                            break;
                        case "preloaddocument":
                            if (paramNameVal[1] == "true")
                            {
                                preloadDocument = true;
                                if (printInfo)
                                    Console.Out.WriteLine("Document will be loaded entirely in memory.");
                            }
                            break;
                        case "imageerrors":
                            if (paramNameVal[1].ToUpper() == "THROW")
                            {
                                imgErrMode = Engine.ImageErrorsHandlingMode.ThrowError;
                                if (printInfo)
                                    Console.Out.WriteLine("Image errors will be reported.");
                            }
                            else if (paramNameVal[1].ToUpper() == "IGNORE")
                            {
                                imgErrMode = Engine.ImageErrorsHandlingMode.Ignore;
                                if (printInfo)
                                    Console.Out.WriteLine("Image errors will be ignored.");
                            }
                            else if (paramNameVal[1].ToUpper() == "USESTOCK")
                            {
                                imgErrMode = Engine.ImageErrorsHandlingMode.IgnoreAndDisplayImageNotFound;
                                if (printInfo)
                                    Console.Out.WriteLine("A stock image will be used whenever an image is not found.");
                            }
                            break;
                        case "encodercompressiontype":
                            if (paramNameVal[1].ToUpper() == "NONE")
                            {
                                encCompType = Engine.CompressionAlgorithm.None;
                                if (printInfo)
                                    Console.Out.WriteLine("Compression set to {0}", paramNameVal[1]);
                            }
                            else if (paramNameVal[1].ToUpper() == "CCITT3")
                            {
                                encCompType = Engine.CompressionAlgorithm.CCITT3;
                                if (printInfo)
                                    Console.Out.WriteLine("Compression set to {0}", paramNameVal[1]);
                            }
                            else if (paramNameVal[1].ToUpper() == "CCITT4")
                            {
                                encCompType = Engine.CompressionAlgorithm.CCITT4;
                                if (printInfo)
                                    Console.Out.WriteLine("Compression set to {0}", paramNameVal[1]);
                            }
                            else if (paramNameVal[1].ToUpper() == "LZW")
                            {
                                encCompType = Engine.CompressionAlgorithm.LZW;
                                if (printInfo)
                                    Console.Out.WriteLine("Compression set to {0}", paramNameVal[1]);
                            }
                            else if (paramNameVal[1].ToUpper() == "RLE")
                            {
                                encCompType = Engine.CompressionAlgorithm.RLE;
                                if (printInfo)
                                    Console.Out.WriteLine("Compression set to {0}", paramNameVal[1]);
                            }
                            break;
                        case "smoothingmode":
                            if (paramNameVal[1].ToUpper() == "DEFAULT")
                            {
                                smoothingMode = Engine.SmoothingMode.Default;
                                if (printInfo)
                                    Console.Out.WriteLine("Smoothing mode set to {0}", paramNameVal[1]);
                            }
                            else if (paramNameVal[1].ToUpper() == "NONE")
                            {
                                smoothingMode = Engine.SmoothingMode.None;
                                if (printInfo)
                                    Console.Out.WriteLine("Smoothing mode set to {0}", paramNameVal[1]);
                            }
                            else if (paramNameVal[1].ToUpper() == "ANTIALIAS")
                            {
                                smoothingMode = Engine.SmoothingMode.AntiAlias;
                                if (printInfo)
                                    Console.Out.WriteLine("Smoothing mode set to {0}", paramNameVal[1]);
                            }
                            break;
                        case "zoom":
                            zoom = Int32.Parse(paramNameVal[1]);
                            if (printInfo)
                                Console.Out.WriteLine("Zoom set to {0}.", zoom);
                            break;
                        case "servertemplateid":
                            serverTemplateID = paramNameVal[1];
                            if (printInfo)
                                Console.Out.WriteLine("Using server template '{0}'.", serverTemplateID);
                            break;
                        case "username":
                            userName = paramNameVal[1];
                            if (printInfo)
                                Console.Out.WriteLine("Logging in as '{0}'.", userName);
                            break;
                        case "password":
                            password = paramNameVal[1];
                            break;
                        case "template":
                            templateName = paramNameVal[1];
                            if (printInfo)
                                Console.Out.WriteLine("Using client-specified template '{0}'.", templateName);
                            break;
                        case "xsltengine":
                            if (paramNameVal[1].ToUpper() == "DOTNET20" || paramNameVal[1].ToUpper() == "DOTNET")
                            {
                                xsltEngine = Engine.XsltEngine.DotNet20;
                                if (printInfo)
                                    Console.Out.WriteLine("Using .NET XSLT processing engine.");
                            }
                            else if (paramNameVal[1].ToUpper() == "SAXON")
                            {
                                xsltEngine = Engine.XsltEngine.Saxon;
                                if (printInfo)
                                    Console.Out.WriteLine("Using Saxon XSLT processing engine.");
                            }
                            else if (paramNameVal[1].ToUpper() == "MSXML")
                            {
                                xsltEngine = Engine.XsltEngine.MSXML;
                                if (printInfo)
                                    Console.Out.WriteLine("Using MSXML XSLT processing engine.");
                            }
                            else
                                Console.WriteLine("Warning: Invalid XSLT engine option for user template, defaulting to .NET 2.0.");
                            break;
                        case "languageid":
                            languageID = paramNameVal[1];
                            break;
                        case "pdfimagecompression":
                            if (paramNameVal[1].ToUpper() == "FLAT")
                            {
                                pdfImageCompression = Engine.PDFImageCompression.FLAT;
                                if (printInfo)
                                    Console.Out.WriteLine("Using PDF Image compression FLAT.");
                            }
                            else if (paramNameVal[1].ToUpper() == "JPEG")
                            {
                                pdfImageCompression = Engine.PDFImageCompression.JPEG;
                                if (printInfo)
                                    Console.Out.WriteLine("Using PDF Image compression JPEG.");
                            }
                            break;
                        case "htmlpagewidth":
                            htmlInptSettings.PageWidth = paramNameVal[1].ToLower();
                            break;
                        case "htmlpageheight":
                            htmlInptSettings.PageHeight = paramNameVal[1].ToLower();
                            break;
                        case "htmlpagemargintop":
                            htmlInptSettings.PageMarginTop = paramNameVal[1].ToLower();
                            break;
                        case "htmlpagemarginleft":
                            htmlInptSettings.PageMarginLeft = paramNameVal[1].ToLower();
                            break;
                        case "htmlpagemarginright":
                            htmlInptSettings.PageMarginRight = paramNameVal[1].ToLower();
                            break;
                        case "htmlpagemarginbottom":
                            htmlInptSettings.PageMarginBottom = paramNameVal[1].ToLower();
                            break;
                        case "htmlpageheadermargin":
                            htmlInptSettings.PageHeaderMargin = paramNameVal[1].ToLower();
                            break;
                        case "htmlpagefootermaring":
                            htmlInptSettings.PageFooterMargin = paramNameVal[1].ToLower();
                            break;
                        case "htmlshowpagenumber":
                            if (paramNameVal[1].ToLower() == "true")
                                htmlInptSettings.ShowPageNumber = true;
                            else
                                htmlInptSettings.ShowPageNumber = false;
                            break;
                        case "htmlshowtitle":
                            if (paramNameVal[1].ToLower() == "true")
                                htmlInptSettings.ShowTitle = true;
                            else
                                htmlInptSettings.ShowTitle = false;
                            break;
                        case "htmlgeneratehtmltag":
                            if (paramNameVal[1].ToLower() == "true")
                                htmlOuptSettings.GenerateHtmlDocument = true;
                            else
                                htmlOuptSettings.GenerateHtmlDocument = false;
                            break;
                        case "htmlusefixedbodywidth":
                            if (paramNameVal[1].ToLower() == "true")
                                htmlOuptSettings.UseFixedBodyWidth = true;
                            else
                                htmlOuptSettings.UseFixedBodyWidth = false;
                            break;
                        case "htmlhidestaticcontent":
                            if (paramNameVal[1].ToLower() == "true")
                                htmlOuptSettings.HideStaticContent = true;
                            else
                                htmlOuptSettings.HideStaticContent = false;
                            break;
                        case "renderedimagesbaseurl":
                            htmlOuptSettings.RenderedImagesBaseUrl = paramNameVal[1];
                            if (printInfo)
                                Console.Out.WriteLine("Rendered images base url set to {0}", paramNameVal[1]);
                            break;
                        case "renderedimagesoutputfolder":
                            htmlOuptSettings.RenderedImagesOutputFolder = paramNameVal[1];
                            if (printInfo)
                                Console.Out.WriteLine("Rendered images output folder set to {0}", paramNameVal[1]);
                            break;                        
                        case "xsltparameters":
                            {
                                String[] xsltParams = paramNameVal[1].Trim().Split(")(".ToCharArray());
                                foreach (String xsltPair in xsltParams)
                                {
                                    String temp = xsltPair.Trim();
                                    if (temp == "")
                                        continue;
                                    if (temp.StartsWith("(") && temp.Length > 1)
                                        temp = temp.Substring(1);
                                    if (temp.EndsWith(")") && temp.Length > 1)
                                        temp = temp.Substring(0, temp.Length - 2);
                                    if (temp.IndexOf(',') == -1)
                                        continue;

                                    int commaPos = temp.IndexOf(',');
                                    if (commaPos == 0 || commaPos == temp.Length - 1)
                                        continue;

                                    String name = temp.Substring(0, commaPos);
                                    String value = temp.Substring(commaPos + 1);
                                    xsltParameters.Add(name, value);
                                }
                            }
                            break;
                    }
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public RenderingParameters GetRenderingParameters()
        {
            RenderingParameters p = new RenderingParameters();
            
            p.OutputFormat = outputFormat;
            
            p.XResolution = xResolution;
            p.YResolution = yResolution;
            p.AFPOutputFlags = afpOutputFlags;
            p.PDFOutputFlags = pdfOutputFlags;
            p.ReferenceResolverType = referenceResolverType;
            p.PreloadDocument = preloadDocument;
            p.ImageErrorsHandlingMode = imgErrMode;
            p.CompressionAlgorithm = encCompType;
            p.SmoothingMode = smoothingMode;
            p.ZoomFactor = zoom;
            if (!IsNullOrEmpty(serverTemplateID))
                p.Template = new ServerDocumentTemplate(serverTemplateID, xsltParameters, languageID);
            else if (!IsNullOrEmpty(templateName))
                p.Template = new LocalDocumentTemplate(templateName, xsltParameters, xsltEngine, languageID);

            p.UserName = userName;
            p.Password = password;
            p.PDFUserPassword = pdfUserPassword;
            p.PDFOwnerPassword = pdfOwnerPassword;
            p.PrinterSettings.PrinterName = PrinterName;
            if (outputPrintFile.Length != 0)
                p.PrinterSettings.OutputPrintFile = outputPrintFile;
            p.PDFOutputPermissionFlags = pdfPermissionsFlags;
            p.PDFImageCompression = pdfImageCompression;
            p.HtmlInputSettings = htmlInptSettings;
            p.HtmlOutputSettings = htmlOuptSettings;
            p.PageIdx = pageIdx;

            if (isMergeOperation)
                p.MergeContextID = Engine.GetNewMergeContextID();
            return p;
        }

        /// <summary>
        /// Prints a list of supported parameter names.
        /// </summary>
        public static void PrintSupportedParameters()
        {
            Console.Error.WriteLine("    merge=boolValue");
            Console.Error.WriteLine("    logfile=stringValue");
            Console.Error.WriteLine("    loglevel=none|errors|all");
            Console.Error.WriteLine("    resolution=intValue");
            Console.Error.WriteLine("    pageidx=intValue");
            Console.Error.WriteLine("    afpconverttograyscale=boolValue");
            Console.Error.WriteLine("    referenceresolvertype=parallel|serial|disabled");
            Console.Error.WriteLine("    preloaddocument=boolValue");
            Console.Error.WriteLine("    imageerrors=throw|ignore|usestock");
            Console.Error.WriteLine("    encodercompressiontype=none|ccitt3|ccitt4|lzw|rle");
            Console.Error.WriteLine("    smoothingmode=default|none|antialias");
            Console.Error.WriteLine("    zoom=intValue");
            Console.Error.WriteLine("    username=stringValue");
            Console.Error.WriteLine("    password=stringValue");
            Console.Error.WriteLine("    servertemplateid=stringValue");
            Console.Error.WriteLine("    template=stringValue");
            Console.Error.WriteLine("    xsltparameters=(param1,value1)(param2,value2)");
            Console.Error.WriteLine("    xsltengine=MSXML|DOTNET|SAXON");
            Console.Error.WriteLine("    languageid=stringValue");
            Console.Error.WriteLine("    pdfconformance=PDF1.4|PDF_X|PDFA_1A|PDFA_1B");
            Console.Error.WriteLine("    pdfpermissions=stringValue");
            Console.Error.WriteLine("    pdfuserpassword=stringValue");
            Console.Error.WriteLine("    pdfownerpassword=stringValue");
            Console.Error.WriteLine("    pdfimagecompression=jpeg|flat");
            Console.Error.WriteLine("    pdfencryptionstrength=intValue");
            Console.Error.WriteLine("    printername=stringValue");
            Console.Error.WriteLine("    outputprintfile=stringValue");
            Console.Error.WriteLine("    htmlpagewidth=stringValue");
            Console.Error.WriteLine("    htmlpageheight=stringValue");
            Console.Error.WriteLine("    htmlpagemargintop=stringValue");
            Console.Error.WriteLine("    htmlpagemarginleft=stringValue");
            Console.Error.WriteLine("    htmlpagemarginright=stringValue");
            Console.Error.WriteLine("    htmlpagemarginbottom=stringValue");
            Console.Error.WriteLine("    htmlpageheadermargin=stringValue");
            Console.Error.WriteLine("    htmlpagefootermaring=stringValue");
            Console.Error.WriteLine("    htmlshowpagenumber=boolValue");
            Console.Error.WriteLine("    htmlshowtitle=boolValue");
            Console.Error.WriteLine("    htmlgeneratehtmltag=boolValue");
            Console.Error.WriteLine("    htmlusefixedbodywidth=boolValue");
            Console.Error.WriteLine("    renderedimagesbaseurl=stringValue");
            Console.Error.WriteLine("    renderedimagesoutputfolder=stringValue\n");
        }

        static internal bool IsNullOrEmpty(String str)
        {	//.NET 1.1 doesn't have String.IsNullOrEmpty
            return str == null || str.Length == 0;
        }
    }
}
