/// <summary>
        /// This method overlays any answer collections passed into it, into a single XML answer collection.
        /// It has two primary uses: it can be used to combine multiple answer collections into a single
        /// answer collection; and/or it can be used to "resolve" or standardize an answer collection
        /// submitted from a browser interview (which may be specially encoded) into standard XML answers.
        /// </summary>
        /// <param name="answers">A sequence of answer collections. Each member of this sequence
        /// must be either an (encoded) interview answer collection or a regular XML answer collection.
        /// Each member will be successively overlaid (overlapped) on top of the prior members to
        /// form one consolidated answer collection.</param>
        /// <include file="../Shared/Help.xml" path="Help/string/param[@name='logRef']"/>
        /// <returns>The consolidated XML answer collection.</returns>
        public string GetAnswers(IEnumerable <TextReader> answers, string logRef)
        {
            // Validate input parameters, creating defaults as appropriate.
            string logStr = logRef == null ? string.Empty : logRef;

            if (answers == null)
            {
                throw new ArgumentNullException("answers", @"Local.Services.GetAnswers: The ""answers"" parameter must not be null, logRef: " + logStr);
            }

            string result = "";

            using (HotDocs.Server.AnswerCollection hdsAnsColl = new HotDocs.Server.AnswerCollection())
            {
                foreach (TextReader tr in answers)
                {
                    hdsAnsColl.OverlayXMLAnswers(tr.ReadToEnd());
                }
                result = hdsAnsColl.XmlAnswers;
            }
            return(result);
        }
        /// <summary>
        /// Assemble a document from the given template, answers and settings.
        /// </summary>
        /// <param name="template">An instance of the Template class.</param>
        /// <param name="answers">Either an XML answer string, or a string containing encoded
        /// interview answers as posted from a HotDocs browser interview.</param>
        /// <param name="settings">An instance of the AssembleDocumentResult class.</param>
        /// <include file="../Shared/Help.xml" path="Help/string/param[@name='logRef']"/>
        /// <returns>An AssemblyResult object containing all the files and data resulting from the request.</returns>
        public AssembleDocumentResult AssembleDocument(Template template, TextReader answers, AssembleDocumentSettings settings, string logRef)
        {
            // Validate input parameters, creating defaults as appropriate.
            string logStr = logRef == null ? string.Empty : logRef;
            if (template == null)
                throw new ArgumentNullException("template", string.Format(@"Local.Services.AssembleDocument: the ""template"" parameter passed in was null, logRef: {0}", logStr));

            if (settings == null)
                settings = new AssembleDocumentSettings();

            HotDocs.Server.AnswerCollection ansColl = new HotDocs.Server.AnswerCollection();
            ansColl.OverlayXMLAnswers(answers == null ? "" : answers.ReadToEnd());
            HotDocs.Server.OutputOptions outputOptions = ConvertOutputOptions(settings.OutputOptions);

            string docPath = CreateTempDocDirAndPath(template, settings.Format);
            _app.AssembleDocument(
                template.GetFullPath(),//Template path
                settings.UseMarkupSyntax ? hdsi.HDAssemblyOptions.asmOptMarkupView : hdsi.HDAssemblyOptions.asmOptNone,
                ansColl,
                docPath,
                outputOptions);

            //Prepare the post-assembly answer set (dropping transient ("don't save") answers when appropriate)
            HotDocs.Sdk.AnswerCollection resultAnsColl = new AnswerCollection();
            resultAnsColl.ReadXml(new StringReader(ansColl.XmlAnswers));
            string resultAnsXml = resultAnsColl.GetXMLString(false, settings.RetainTransientAnswers || _app.PendingAssemblyCmdLineStrings.Count > 0);

            //Build the list of pending assemblies.
            List<Template> pendingAssemblies = new List<Template>();
            for (int i = 0; i < _app.PendingAssemblyCmdLineStrings.Count; i++)
            {
                string cmdLine = _app.PendingAssemblyCmdLineStrings[i];
                string path, switches;
                Util.ParseHdAsmCmdLine(cmdLine, out path, out switches);
                pendingAssemblies.Add(new Template(Path.GetFileName(path), template.Location.Duplicate(), switches));
            }

            //Prepare the document stream and image information for the browser.
            DocumentType docType = settings.Format;
            List<NamedStream> supportingFiles = new List<NamedStream>();
            MemoryStream docStream;
            if (docType == DocumentType.Native)
            {
                docType = Document.GetDocumentType(docPath);
                docStream = LoadFileIntoMemStream(docPath);
            }
            else if (docType == DocumentType.HTMLwDataURIs)
            {
                //If the consumer requested both HTML and HTMLwDataURIs, they'll only get the latter.
                string content = Util.EmbedImagesInURIs(docPath);
                docStream = new MemoryStream(Encoding.UTF8.GetBytes(content));
            }
            else if (docType == DocumentType.MHTML)
            {
                string content = Util.HtmlToMultiPartMime(docPath);
                docStream = new MemoryStream(Encoding.UTF8.GetBytes(content));
            }
            else if (docType == DocumentType.HTML)
            {
                string targetFilenameNoExtention = Path.GetFileNameWithoutExtension(docPath);
                foreach (string img in Directory.EnumerateFiles(Path.GetDirectoryName(docPath)))
                {
                    string ext = Path.GetExtension(img).ToLower();
                    if (Path.GetFileName(img).StartsWith(targetFilenameNoExtention) && (ext == ".jpg" || ext == ".jpeg" || ext == ".gif" || ext == ".png" || ext == ".bmp"))
                        supportingFiles.Add(LoadFileIntoNamedStream(img));
                }

                docStream = LoadFileIntoMemStream(docPath);
            }
            else
            {
                docStream = LoadFileIntoMemStream(docPath);
            }

            //Now that we've loaded all of the assembly results into memory, remove the assembly files.
            FreeTempDocDir(docPath);

            //Return the results.
            Document document = new Document(template, docStream, docType, supportingFiles.ToArray(), _app.UnansweredVariablesList.ToArray());
            AssembleDocumentResult result = new AssembleDocumentResult(document, resultAnsXml, pendingAssemblies.ToArray(), _app.UnansweredVariablesList.ToArray());
            return result;
        }
        ///<summary>
        ///	GetInterview returns an HTML fragment suitable for inclusion in any standards-mode web page, which embeds a HotDocs interview
        ///	directly in that web page.
        ///</summary>
        /// <param name="template">The template for which to return an interview.</param>
        /// <param name="answers">The answers to use when building an interview.</param>
        /// <param name="settings">The <see cref="InterviewSettings"/> to use when building an interview.</param>
        /// <param name="markedVariables">The variables to highlight to the user as needing special attention.
        /// 	This is usually populated with <see cref="AssembleDocumentResult.UnansweredVariables" />
        /// 	from <see cref="AssembleDocument" />.</param>
        /// <include file="../Shared/Help.xml" path="Help/string/param[@name='logRef']"/>
        /// <returns>Returns the results of building the interview as an <see cref="InterviewResult"/> object.</returns>
        public InterviewResult GetInterview(Template template, TextReader answers, InterviewSettings settings, IEnumerable<string> markedVariables, string logRef)
        {
            // Validate input parameters, creating defaults as appropriate.
            string logStr = logRef == null ? string.Empty : logRef;

            if (template == null)
                throw new ArgumentNullException("template", string.Format(@"Local.Services.GetInterview: the ""template"" parameter passed in was null, logRef: {0}", logStr));

            if (settings == null)
                settings = new InterviewSettings();

            // HotDocs Server reads the following settings out of the registry all the time; therefore these items are ignored when running against Server:
            //		settings.AddHdMainDiv
            //		settings.AnswerSummary.*
            //		settings.DefaultDateFormat
            //		settings.DefaultUnansweredFormat
            //		settings.HonorCmpUnansweredFormat
            //		settings.DisableAnswerSummary

            // HotDocs Server does not include the following settings in its .NET or COM APIs, so Util.AppendSdkScriptBlock (below)
            // includes them with the interview script block:
            //		settings.Locale
            //		settings.NextFollowsOutline
            //		settings.ShowAllResourceButtons

            hdsi.interviewFormat fmt;
            switch (settings.Format)
            {
                case InterviewFormat.JavaScript:
                    fmt = hdsi.interviewFormat.javascript;
                    break;
                case InterviewFormat.Silverlight:
                    fmt = hdsi.interviewFormat.Silverlight;
                    break;
                default:
                    fmt = hdsi.interviewFormat.Unspecified;
                    break;
            }

            // Configure the interview options
            hdsi.HDInterviewOptions itvOpts = hdsi.HDInterviewOptions.intOptNoImages; // Instructs HDS not to return images used by the interview; we'll get them ourselves from the template folder.

            if (settings.DisableDocumentPreview)
                itvOpts |= hdsi.HDInterviewOptions.intOptNoPreview; // Disables (omits) the Document Preview button on the interview toolbar.
            if (settings.DisableSaveAnswers)
                itvOpts |= hdsi.HDInterviewOptions.intOptNoSave; // Disables (omits) the Save Answers button on the interview toolbar.
            if (settings.RoundTripUnusedAnswers)
                itvOpts |= hdsi.HDInterviewOptions.intOptStateless; // Prevents original answer file from being encrypted and sent to the interview and then posted back at the end.

            // Get the interview.
            InterviewResult result = new InterviewResult();

            StringBuilder htmlFragment;
            using (var ansColl = new HotDocs.Server.AnswerCollection())
            {
                if (answers != null)
                {
                    if (answers.Peek() == 0xFEFF)
                        answers.Read(); // discard BOM if present
                    ansColl.XmlAnswers = answers.ReadToEnd();
                }

                if (markedVariables == null)
                    _app.UnansweredVariablesList = new string[0];
                else
                    _app.UnansweredVariablesList = markedVariables;

                htmlFragment = new StringBuilder(
                    _app.GetInterview(
                        template.GetFullPath(),
                        template.Key,
                        fmt,
                        itvOpts,
                        settings.InterviewRuntimeUrl,
                        settings.StyleSheetUrl + "/" + settings.ThemeName + ".css",
                        ansColl,
                        settings.PostInterviewUrl,
                        settings.Title,
                        Util.GetInterviewDefinitionUrl(settings, template),
                        null, // the path to which HDS should copy interview images; also the path that may become part of the DocumentPreviewStateString & passed to document preview handler
                        Util.GetInterviewImageUrl(settings, template),
                        settings.SaveAnswersUrl,
                        settings.DocumentPreviewUrl)
                    );
            }
            Util.AppendSdkScriptBlock(htmlFragment, template, settings);

            result.HtmlFragment = htmlFragment.ToString();
            return result;
        }
        /// <summary>
        /// This method overlays any answer collections passed into it, into a single XML answer collection.
        /// It has two primary uses: it can be used to combine multiple answer collections into a single
        /// answer collection; and/or it can be used to "resolve" or standardize an answer collection
        /// submitted from a browser interview (which may be specially encoded) into standard XML answers.
        /// </summary>
        /// <param name="answers">A sequence of answer collections. Each member of this sequence
        /// must be either an (encoded) interview answer collection or a regular XML answer collection.
        /// Each member will be successively overlaid (overlapped) on top of the prior members to
        /// form one consolidated answer collection.</param>
        /// <include file="../Shared/Help.xml" path="Help/string/param[@name='logRef']"/>
        /// <returns>The consolidated XML answer collection.</returns>
        public string GetAnswers(IEnumerable<TextReader> answers, string logRef)
        {
            // Validate input parameters, creating defaults as appropriate.
            string logStr = logRef == null ? string.Empty : logRef;
            if (answers == null)
                throw new ArgumentNullException("answers", @"Local.Services.GetAnswers: The ""answers"" parameter must not be null, logRef: " + logStr);

            string result = "";
            using (HotDocs.Server.AnswerCollection hdsAnsColl = new HotDocs.Server.AnswerCollection())
            {
                foreach (TextReader tr in answers)
                    hdsAnsColl.OverlayXMLAnswers(tr.ReadToEnd());
                result = hdsAnsColl.XmlAnswers;
            }
            return result;
        }
        /// <summary>
        /// Assemble a document from the given template, answers and settings.
        /// </summary>
        /// <param name="template">An instance of the Template class.</param>
        /// <param name="answers">Either an XML answer string, or a string containing encoded
        /// interview answers as posted from a HotDocs browser interview.</param>
        /// <param name="settings">An instance of the AssembleDocumentResult class.</param>
        /// <include file="../Shared/Help.xml" path="Help/string/param[@name='logRef']"/>
        /// <returns>An AssemblyResult object containing all the files and data resulting from the request.</returns>
        public AssembleDocumentResult AssembleDocument(Template template, TextReader answers, AssembleDocumentSettings settings, string logRef)
        {
            // Validate input parameters, creating defaults as appropriate.
            string logStr = logRef == null ? string.Empty : logRef;

            if (template == null)
            {
                throw new ArgumentNullException("template", string.Format(@"Local.Services.AssembleDocument: the ""template"" parameter passed in was null, logRef: {0}", logStr));
            }

            if (settings == null)
            {
                settings = new AssembleDocumentSettings();
            }


            HotDocs.Server.AnswerCollection ansColl = new HotDocs.Server.AnswerCollection();
            ansColl.OverlayXMLAnswers(answers == null ? "" : answers.ReadToEnd());
            HotDocs.Server.OutputOptions outputOptions = ConvertOutputOptions(settings.OutputOptions);

            string docPath = CreateTempDocDirAndPath(template, settings.Format);

            _app.AssembleDocument(
                template.GetFullPath(),                //Template path
                hdsi.HDAssemblyOptions.asmOptMarkupView,
                ansColl,
                docPath,
                outputOptions);

            //Prepare the post-assembly answer set.
            HotDocs.Sdk.AnswerCollection resultAnsColl = new AnswerCollection();
            resultAnsColl.ReadXml(new StringReader(ansColl.XmlAnswers));
            if (!settings.RetainTransientAnswers && _app.PendingAssemblyCmdLineStrings.Count == 0)
            {
                // Create a list of all "transient" answers to remove.
                IEnumerable <Answer> transAnswers    = from a in resultAnsColl where !a.Save select a;
                List <string>        answersToRemove = new List <string>();
                foreach (Answer ans in transAnswers)
                {
                    answersToRemove.Add(ans.Name);
                }

                // Iterate through the list of answers to remove and remove them from the result answer collection.
                // This is done as a separate step so we are not modifying the collecion over which we are iterating.
                foreach (string s in answersToRemove)
                {
                    resultAnsColl.RemoveAnswer(s);
                }
            }

            //Build the list of pending assemblies.
            List <Template> pendingAssemblies = new List <Template>();

            for (int i = 0; i < _app.PendingAssemblyCmdLineStrings.Count; i++)
            {
                string cmdLine = _app.PendingAssemblyCmdLineStrings[i];
                string path, switches;
                Util.ParseHdAsmCmdLine(cmdLine, out path, out switches);
                pendingAssemblies.Add(new Template(Path.GetFileName(path), template.Location.Duplicate(), switches));
            }

            //Prepare the document stream and image information for the browser.
            DocumentType       docType         = settings.Format;
            List <NamedStream> supportingFiles = new List <NamedStream>();
            MemoryStream       docStream;

            if (docType == DocumentType.Native)
            {
                docType   = Document.GetDocumentType(docPath);
                docStream = LoadFileIntoMemStream(docPath);
            }
            else if (docType == DocumentType.HTMLwDataURIs)
            {
                //If the consumer requested both HTML and HTMLwDataURIs, they'll only get the latter.
                string content = Util.EmbedImagesInURIs(docPath);
                docStream = new MemoryStream(Encoding.UTF8.GetBytes(content));
            }
            else if (docType == DocumentType.MHTML)
            {
                string content = Util.HtmlToMultiPartMime(docPath);
                docStream = new MemoryStream(Encoding.UTF8.GetBytes(content));
            }
            else if (docType == DocumentType.HTML)
            {
                string targetFilenameNoExtention = Path.GetFileNameWithoutExtension(docPath);
                foreach (string img in Directory.EnumerateFiles(Path.GetDirectoryName(docPath)))
                {
                    string ext = Path.GetExtension(img).ToLower();
                    if (Path.GetFileName(img).StartsWith(targetFilenameNoExtention) && (ext == ".jpg" || ext == ".jpeg" || ext == ".gif" || ext == ".png" || ext == ".bmp"))
                    {
                        supportingFiles.Add(LoadFileIntoNamedStream(img));
                    }
                }

                docStream = LoadFileIntoMemStream(docPath);
            }
            else
            {
                docStream = LoadFileIntoMemStream(docPath);
            }

            //Now that we've loaded all of the assembly results into memory, remove the assembly files.
            FreeTempDocDir(docPath);

            //Return the results.
            Document document             = new Document(template, docStream, docType, supportingFiles.ToArray(), _app.UnansweredVariablesList.ToArray());
            AssembleDocumentResult result = new AssembleDocumentResult(document, resultAnsColl.XmlAnswers, pendingAssemblies.ToArray(), _app.UnansweredVariablesList.ToArray());

            return(result);
        }
        ///<summary>
        ///	GetInterview returns an HTML fragment suitable for inclusion in any standards-mode web page, which embeds a HotDocs interview
        ///	directly in that web page.
        ///</summary>
        /// <param name="template">The template for which to return an interview.</param>
        /// <param name="answers">The answers to use when building an interview.</param>
        /// <param name="settings">The <see cref="InterviewSettings"/> to use when building an interview.</param>
        /// <param name="markedVariables">The variables to highlight to the user as needing special attention.
        ///     This is usually populated with <see cref="AssembleDocumentResult.UnansweredVariables" />
        ///     from <see cref="AssembleDocument" />.</param>
        /// <include file="../Shared/Help.xml" path="Help/string/param[@name='logRef']"/>
        /// <returns>Returns the results of building the interview as an <see cref="InterviewResult"/> object.</returns>
        public InterviewResult GetInterview(Template template, TextReader answers, InterviewSettings settings, IEnumerable <string> markedVariables, string logRef)
        {
            // Validate input parameters, creating defaults as appropriate.
            string logStr = logRef == null ? string.Empty : logRef;

            if (template == null)
            {
                throw new ArgumentNullException("template", string.Format(@"Local.Services.GetInterview: the ""template"" parameter passed in was null, logRef: {0}", logStr));
            }

            if (settings == null)
            {
                settings = new InterviewSettings();
            }

            // HotDocs Server reads the following settings out of the registry all the time; therefore these items are ignored when running against Server:
            //		settings.AddHdMainDiv
            //		settings.AnswerSummary.*
            //		settings.DefaultDateFormat
            //		settings.DefaultUnansweredFormat
            //		settings.HonorCmpUnansweredFormat
            //		settings.DisableAnswerSummary

            // HotDocs Server does not include the following settings in its .NET or COM APIs, so Util.AppendSdkScriptBlock (below)
            // includes them with the interview script block:
            //		settings.Locale
            //		settings.NextFollowsOutline
            //		settings.ShowAllResourceButtons

            hdsi.interviewFormat fmt;
            switch (settings.Format)
            {
            case InterviewFormat.JavaScript:
                fmt = hdsi.interviewFormat.javascript;
                break;

            case InterviewFormat.Silverlight:
                fmt = hdsi.interviewFormat.Silverlight;
                break;

            default:
                fmt = hdsi.interviewFormat.Unspecified;
                break;
            }

            // Configure the interview options
            hdsi.HDInterviewOptions itvOpts = hdsi.HDInterviewOptions.intOptNoImages;             // Instructs HDS not to return images used by the interview; we'll get them ourselves from the template folder.

            if (settings.DisableDocumentPreview)
            {
                itvOpts |= hdsi.HDInterviewOptions.intOptNoPreview;                 // Disables (omits) the Document Preview button on the interview toolbar.
            }
            if (settings.DisableSaveAnswers)
            {
                itvOpts |= hdsi.HDInterviewOptions.intOptNoSave;                 // Disables (omits) the Save Answers button on the interview toolbar.
            }
            if (settings.RoundTripUnusedAnswers)
            {
                itvOpts |= hdsi.HDInterviewOptions.intOptStateless;                 // Prevents original answer file from being encrypted and sent to the interview and then posted back at the end.
            }
            // Get the interview.
            InterviewResult result = new InterviewResult();

            StringBuilder htmlFragment;

            using (var ansColl = new HotDocs.Server.AnswerCollection())
            {
                if (answers != null)
                {
                    if (answers.Peek() == 0xFEFF)
                    {
                        answers.Read();                         // discard BOM if present
                    }
                    ansColl.XmlAnswers = answers.ReadToEnd();
                }

                if (markedVariables == null)
                {
                    _app.UnansweredVariablesList = new string[0];
                }
                else
                {
                    _app.UnansweredVariablesList = markedVariables;
                }

                htmlFragment = new StringBuilder(
                    _app.GetInterview(
                        template.GetFullPath(),
                        template.Key,
                        fmt,
                        itvOpts,
                        settings.InterviewRuntimeUrl,
                        settings.StyleSheetUrl + "/" + settings.ThemeName + ".css",
                        ansColl,
                        settings.PostInterviewUrl,
                        settings.Title,
                        Util.GetInterviewDefinitionUrl(settings, template),
                        null,                         // the path to which HDS should copy interview images; also the path that may become part of the DocumentPreviewStateString & passed to document preview handler
                        Util.GetInterviewImageUrl(settings, template),
                        settings.SaveAnswersUrl,
                        settings.DocumentPreviewUrl)
                    );
            }
            Util.AppendSdkScriptBlock(htmlFragment, template, settings);

            result.HtmlFragment = htmlFragment.ToString();
            return(result);
        }