public static Task <IHtmlContent> RenderContentZone(this IViewComponentHelper component, AgilityPage page, string zoneName)
        {
            try
            {
                HttpContext currentContext = AgilityContext.HttpContext;

                String websiteName = AgilityContext.WebsiteName;
                if (page == null)
                {
                    if (AgilityContext.IsTemplatePreview)
                    {
                        //TODO render the template preview


                        //var templates = from cs in AgilityContext.CurrentPageTemplateInPreview.ContentSections
                        //				where string.Equals(cs.Name, zoneName, StringComparison.CurrentCultureIgnoreCase)
                        //				orderby cs.XModuleOrder
                        //				select cs;
                        //TextWriter tw = helper.ViewContext.Writer;

                        //foreach (var cs in templates)
                        //{
                        //	tw.Write(string.Format("<div class=\"AgilityContentSectionDefinition\"><div class=\"ContentSectionTitle\">{0}</div></div>", cs.Name));
                        //}
                    }

                    return(Task.Run <IHtmlContent>(() => { return new HtmlString("TODO: implement template preview"); }));
                }



                //regular page rendering
                var sections = from cs in page.ContentSections
                               where string.Equals(cs.Name, zoneName, StringComparison.CurrentCultureIgnoreCase)
                               orderby cs.ModuleOrder
                               select cs;

                List <Task <string> > sectionTasks = new List <Task <string> >();
                DateTime dtStart = DateTime.Now;

                foreach (var cs in sections)
                {
                    //only continue if we have a content ref name...
                    if (string.IsNullOrEmpty(cs.ContentReferenceName))
                    {
                        continue;
                    }

                    //keep track of the various way this module can be rendered
                    List <ModuleRender> renders = new List <ModuleRender>()
                    {
                        new ModuleRender()
                        {
                            ContentReferenceName = cs.ContentReferenceName
                        }
                    };

                    //if this content zone is part of a Module AB test Experiment
                    if (cs.ExperimentID > 0)
                    {
                        var lst = BaseCache.GetExperiments(AgilityContext.WebsiteName);
                        AgilityContentServer.AgilityExperiment experiment = lst.GetExperiment(cs.ExperimentID);

                        if (experiment != null)
                        {
                            foreach (var variant in experiment.Variants.Where(v => !string.IsNullOrWhiteSpace(v.ContentReferenceName)))
                            {
                                renders.Add(new ModuleRender()
                                {
                                    ContentReferenceName = variant.ContentReferenceName,
                                    Variant = variant
                                });
                            }
                        }
                    }

                    foreach (ModuleRender moduleRender in renders)
                    {
                        try
                        {
                            string contentReferenceName = moduleRender.ContentReferenceName;

                            Agility.Web.AgilityContentServer.AgilityContent moduleContent = BaseCache.GetContent(contentReferenceName, AgilityContext.LanguageCode, websiteName);
                            if (moduleContent == null ||
                                moduleContent.DataSet == null ||
                                moduleContent.DataSet.Tables["ContentItems"] == null ||
                                moduleContent.DataSet.Tables["ContentItems"].Rows.Count == 0)
                            {
                                continue;
                            }


                            DataRowView drv = moduleContent.DataSet.Tables["ContentItems"].DefaultView[0];

                            int moduleContentID = -1;
                            int moduleVersionID = -1;

                            if (!int.TryParse($"{drv["ContentID"]}", out moduleContentID))
                            {
                                moduleContentID = -1;
                            }
                            if (!int.TryParse($"{drv["VersionID"]}", out moduleVersionID))
                            {
                                moduleVersionID = -1;
                            }


                            Agility.Web.AgilityContentServer.AgilityModule module = BaseCache.GetModule(cs.ModuleID, websiteName);
                            if (module == null)
                            {
                                continue;
                            }


                            object model = new AgilityModuleModel()
                            {
                                ModuleContentName = contentReferenceName,
                                ModuleProperties  = drv,
                                LanguageCode      = AgilityContext.LanguageCode
                            };

                            string viewComponentName  = null;
                            string agilityCodeRefName = null;

                            using (StringReader sr = new StringReader(module.XmlSchema))
                            {
                                DataSet ds = new DataSet();
                                ds.ReadXmlSchema(sr);

                                viewComponentName  = ds.ExtendedProperties["ViewComponent"] as string;
                                agilityCodeRefName = ds.ExtendedProperties["AgilityCodeRefName"] as string;
                            }

                            if (!string.IsNullOrEmpty(viewComponentName))
                            {
                                #region *** VIEW COMPONENTS **
                                var viewComponentFactory = HtmlHelperViewExtensions.GetServiceOrFail <IViewComponentSelector>(AgilityContext.HttpContext);
                                var componentDesc        = viewComponentFactory.SelectComponent(viewComponentName);

                                if (componentDesc == null)
                                {
                                    throw new ApplicationException(string.Format("The view component {0} was not found.", viewComponentName));
                                }

                                MethodInfo method = componentDesc.MethodInfo;


                                if (method == null)
                                {
                                    throw new ApplicationException(string.Format("The component invoke method was not found in the component {0}", viewComponentName));
                                }

                                ParameterInfo[] paramAry = method.GetParameters();
                                if (paramAry.Length > 0)
                                {
                                    ParameterInfo paramInfo = paramAry[0];
                                    Type          paramType = paramInfo.ParameterType;
                                    if (paramType.IsSubclassOf(typeof(AgilityContentItem)) || paramType == typeof(AgilityContentItem))
                                    {
                                        ConstructorInfo ci = paramType.GetConstructor(System.Type.EmptyTypes);

                                        if (ci == null)
                                        {
                                            throw new ApplicationException(string.Format("No default constructor found for type {0}", paramType.Name));
                                        }

                                        AgilityContentItem moduleItem = ci.Invoke(new object[0]) as AgilityContentItem;
                                        moduleItem.DataRow       = drv.Row;
                                        moduleItem.LanguageCode  = AgilityContext.LanguageCode;
                                        moduleItem.ReferenceName = contentReferenceName;
                                        moduleItem.ContentID     = moduleContentID;
                                        moduleItem.VersionID     = moduleVersionID;


                                        try
                                        {
                                            Task <IHtmlContent> task = component.InvokeAsync(viewComponentName, moduleItem);

                                            moduleRender.RenderTask = task;
                                            moduleRender.ContentID  = moduleContentID;
                                        }
                                        catch (Exception ex)
                                        {
                                            moduleRender.PreRenderedContent = new HtmlString($"<p>Error rendering Component {viewComponentName}</p><pre>{ex}</pre>");
                                            moduleRender.ContentID          = moduleContentID;
                                        }
                                    }
                                    else
                                    {
                                        throw new ApplicationException(string.Format("The component invoke method parameter was not of type AgilityContent in the component {0}", viewComponentName));
                                    }
                                    #endregion
                                }
                            }
                            else if (!string.IsNullOrEmpty(agilityCodeRefName))
                            {
                                #region *** Agility Inline Code ***
                                DataView dv = Data.GetContentView(AgilityDynamicCodeFile.REFNAME_AgilityModuleCodeTemplates, AgilityDynamicCodeFile.LANGUAGECODE_CODE);

                                string    filter = string.Format("ReferenceName = '{0}' AND Visible = true", agilityCodeRefName);
                                DataRow[] rows   = dv.Table.Select(filter);
                                if (rows.Length > 0)
                                {
                                    string modulePath =
                                        $"~/Views/{rows[0]["VersionID"]}/DynamicAgilityCode/{AgilityDynamicCodeFile.REFNAME_AgilityModuleCodeTemplates}/{agilityCodeRefName}.cshtml";

                                    AgilityContentItem moduleItem = new AgilityContentItem();
                                    moduleItem.DataRow       = drv.Row;
                                    moduleItem.LanguageCode  = AgilityContext.LanguageCode;
                                    moduleItem.ReferenceName = contentReferenceName;
                                    moduleItem.ContentID     = moduleContentID;
                                    moduleItem.VersionID     = moduleVersionID;
                                    //moduleItem.InlineCodePath = modulePath;

                                    try
                                    {
                                        Task <IHtmlContent> task = component.InvokeAsync("AgilityInlineCode", new { inlineCodePath = modulePath, module = moduleItem });

                                        moduleRender.RenderTask = task;
                                        moduleRender.ContentID  = moduleContentID;
                                    }
                                    catch (Exception ex)
                                    {
                                        moduleRender.PreRenderedContent = new HtmlString($"<p>Error rendering Inline Code</p><pre>{ex}</pre>");
                                        moduleRender.ContentID          = moduleContentID;
                                    }
                                }
                                else
                                {
                                    moduleRender.PreRenderedContent = new HtmlString($"<p>Error rendering Inline Code</p>");
                                    moduleRender.ContentID          = moduleContentID;
                                }
                                #endregion
                            }
                            else if (!string.IsNullOrEmpty(module.ControlPath))
                            {
                                #region *** Control Path - Partial View ***
                                string className = GetClassName(module.ReferenceName ?? module.Name);
                                string typeName  = string.Format("Module_{0}", className);

                                Type paramType = Agility.Web.Utils.FileUtils.GetTypeFromReflection(null, typeName);
                                if (paramType.IsSubclassOf(typeof(AgilityContentItem)) || paramType == typeof(AgilityContentItem))
                                {
                                    ConstructorInfo ci = paramType.GetConstructor(System.Type.EmptyTypes);

                                    if (ci == null)
                                    {
                                        throw new ApplicationException(string.Format("No default constructor found for type {0}", paramType.Name));
                                    }

                                    AgilityContentItem moduleItem = ci.Invoke(new object[0]) as AgilityContentItem;
                                    moduleItem.DataRow       = drv.Row;
                                    moduleItem.LanguageCode  = AgilityContext.LanguageCode;
                                    moduleItem.ReferenceName = contentReferenceName;
                                    moduleItem.ContentID     = moduleContentID;
                                    moduleItem.VersionID     = moduleVersionID;


                                    try
                                    {
                                        Task <IHtmlContent> task = component.InvokeAsync("AgilityPartialView", new { partialViewPath = module.ControlPath, module = moduleItem });

                                        moduleRender.RenderTask = task;
                                        moduleRender.ContentID  = moduleContentID;
                                    }
                                    catch (Exception ex)
                                    {
                                        moduleRender.PreRenderedContent = new HtmlString($"<p>Error rendering Partial View at {module.ControlPath}</p><pre>{ex}</pre>");
                                        moduleRender.ContentID          = moduleContentID;
                                    }
                                }
                                else
                                {
                                    throw new ApplicationException(string.Format("The component invoke method parameter was not of type AgilityContent in the component {0}", viewComponentName));
                                }
                                #endregion
                            }
                            else if (!string.IsNullOrEmpty(module.Markup))
                            {
                                if (module.Markup.StartsWith("@"))
                                {
                                    #region *** Inline Razor Markup ***
                                    AgilityContentItem item = new AgilityContentItem();
                                    item.DataRow       = drv.Row;
                                    item.LanguageCode  = AgilityContext.LanguageCode;
                                    item.ReferenceName = contentReferenceName;
                                    item.ContentID     = moduleContentID;
                                    item.VersionID     = moduleVersionID;
                                    model = item;

                                    string viewPath = string.Format("~/Views/DynamicAgilityModule/MVC/{0}/{1}.cshtml", AgilityContext.CurrentMode, module.ID);

                                    try
                                    {
                                        Task <IHtmlContent> task = component.InvokeAsync("AgilityInlineCode", new { inlineCodePath = viewPath, module = item });

                                        moduleRender.RenderTask = task;
                                        moduleRender.ContentID  = moduleContentID;
                                    }
                                    catch (Exception ex)
                                    {
                                        moduleRender.PreRenderedContent = new HtmlString($"<p>Error rendering Dynamic Agility Module</p><pre>{ex}</pre>");
                                        moduleRender.ContentID          = moduleContentID;
                                    }
                                    #endregion
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            if (Current.Settings.DevelopmentMode)
                            {
                                moduleRender.PreRenderedContent = new HtmlString($"<div>Could not output zone {cs.Name}</div><div>{ex.ToString().Replace("\n", "<br/>")}</div>");
                            }
                            else
                            {
                                moduleRender.PreRenderedContent = new HtmlString($"<!-- Could not output zone {cs.Name} - See web log -->");
                                Agility.Web.Tracing.WebTrace.WriteException(ex);
                            }
                        }
                    }

                    Task <string> sectionTask = Task <string> .Run(() =>
                    {
                        AgilityContext.HttpContext = currentContext;
                        var rendersToOutput        = renders.Where(r => r.RenderTask != null || r.PreRenderedContent != null).ToList();
                        return(AgilityHelpers.RenderModuleHtml(rendersToOutput, cs));
                    });

                    sectionTasks.Add(sectionTask);
                }


                Task <IHtmlContent> retTask = Task.Run <IHtmlContent>(() =>
                {
                    AgilityContext.HttpContext = currentContext;

                    try
                    {
                        Task.WaitAll(sectionTasks.ToArray());
                    } catch { }

                    using (StringWriter htmlStringWriter = new StringWriter())
                    {
                        foreach (var t in sectionTasks)
                        {
                            if (t.IsFaulted)
                            {
                                Agility.Web.Tracing.WebTrace.WriteException(t.Exception, $"Error rendering module in zone {zoneName} - {t.AsyncState}");
                            }
                            else
                            {
                                htmlStringWriter.Write(t.Result);
                            }
                        }

                        TimeSpan ts = DateTime.Now - dtStart;
                        if (ts.TotalSeconds > 1)
                        {
                            string renderTimeMessage = string.Format("Content Zone: {0} - Render Time: {1:F2} seconds.", zoneName, ts.TotalMilliseconds / 1000);
                            Agility.Web.Tracing.WebTrace.WriteVerboseLine(renderTimeMessage);
                            htmlStringWriter.Write(string.Format("<!-- {0} -->", renderTimeMessage));
                        }

                        return(new HtmlString(htmlStringWriter.ToString()));
                    }
                });


                return(retTask);
            }
            catch (Exception ex)
            {
                string errHtml = null;
                string msg     = string.Format("Could not output content zone {0}.", zoneName);
                if (ex is InvalidOperationException && ex.Message.Contains("No route"))
                {
                    msg +=
                        @" This error is usually caused by a missing route in your Global.asax.cs. Ensure the following route is defined after the normal Agility route.\n
routes.MapRoute(""Default"", ""{controller}/{action}/{id}"",\n
    new { controller = """", action = """", id = """" }\n
);";
                }

                if (Current.Settings.DevelopmentMode)
                {
                    errHtml = ex.ToString().Replace("\n", "<br/>");
                }
                else
                {
                    errHtml = msg;
                }

                Agility.Web.Tracing.WebTrace.WriteException(ex, msg);

                return(Task.Run <IHtmlContent>(() => { return new HtmlString(errHtml); }));
            }
        }
        internal static string GetStatusPanelScript()
        {
            //Add the Style Sheets for the StatusBar and Edit In Place:
            StringBuilder sb = new StringBuilder();
            //HACK

            bool isPublished = false;
            bool containsUnpublishedModules = false;

            string pageTemplatePath = string.Empty;
            int    pageTemplateID   = -1;
            int    pageID           = -1;

            if (AgilityContext.Page != null)
            {
                AgilityPage page = AgilityContext.Page;

                pageID = page.ID;
                if (page.IsPublished)
                {
                    isPublished = true;
                }

                if (!string.IsNullOrEmpty(page.TemplatePath) && page.TemplateID > 0)
                {
                    pageTemplatePath = page.TemplatePath;
                    if (pageTemplatePath.StartsWith("~/"))
                    {
                        pageTemplatePath = pageTemplatePath.Substring(1);

                        string appPath = "/";
                        if (appPath != "/")
                        {
                            pageTemplatePath = string.Format("{0}{1}{2}", appPath, "/TemplatePreview", pageTemplatePath);
                        }
                        else
                        {
                            pageTemplatePath = string.Format("{0}{1}", "/TemplatePreview", pageTemplatePath);
                        }
                    }

                    pageTemplateID = page.TemplateID;
                }



                bool switchMode = false;
                if (AgilityContext.CurrentMode == Agility.Web.Enum.Mode.Live)
                {
                    //if the site is in live mode, switch to staging to check if any modules are required publishing.
                    switchMode = true;
                    AgilityContext.CurrentMode = Agility.Web.Enum.Mode.Staging;
                }

                //check if there are any modules that have not yet been publish
                foreach (ContentSection sect in AgilityContext.Page.ContentSections)
                {
                    if (sect.ModuleID > 0)
                    {
                        AgilityContentServer.AgilityModule module = BaseCache.GetModule(sect.ModuleID, AgilityContext.WebsiteName);
                        if (module != null && !module.IsPublished && module.IsPublishedSpecified)
                        {
                            containsUnpublishedModules = true;
                        }
                    }
                }

                if (switchMode)
                {
                    AgilityContext.CurrentMode = Agility.Web.Enum.Mode.Live;
                }
            }

            //generate the preview key
            string securityKey = Current.Settings.SecurityKey;

            byte[] data = UnicodeEncoding.Unicode.GetBytes(string.Format("{0}_{1}_Preview", -1, securityKey));
            SHA512 shaM = new SHA512Managed();

            byte[] result = shaM.ComputeHash(data);


            string previewKey  = Convert.ToBase64String(result);
            string appendQuery = string.Format("agilitypreviewkey={0}&agilityts={1}&lang={2}",
                                               HttpUtility.UrlEncode(previewKey),
                                               DateTime.Now.ToString("yyyyMMddhhmmss"),
                                               HttpUtility.UrlEncode(AgilityContext.LanguageCode));

            string pageUrl = AgilityContext.UrlForPreviewBar;

            if (string.IsNullOrEmpty(pageUrl))
            {
                pageUrl = AgilityContext.HttpContext.Request.GetEncodedUrl();
            }


            string innerUrl = Agility.Web.Util.Url.ModifyQueryString(
                HttpUtility.UrlPathEncode(pageUrl),
                appendQuery,
                "ispreview");

            string subject = string.Format("Agility {0} Preview", AgilityContext.WebsiteName);
            string body    = string.Format("Click the link below to preview the {0} site:\n{1}\n____________________\nSent from Agility\nhttp://www.agilitycms.com",
                                           AgilityContext.WebsiteName,
                                           innerUrl);

            string previewURL = string.Format("mailto:?subject={0}&body={1}",
                                              HttpUtility.UrlEncode(subject).Replace("+", "%20"),
                                              HttpUtility.UrlEncode(body).Replace("+", "%20"));

            //channel listing
            string[] channels = (from c in BaseCache.GetDigitalChannels(AgilityContext.WebsiteName).Channels
                                 select string.Format("{{Name:\"{0}\",ID:'{1}'}}", c.DisplayName.Replace("\"", "\\\""), c.ReferenceName)).ToArray();

            string uniqueID = Guid.NewGuid().ToString();

            string previewDateStr = AgilityContext.PreviewDateTime.ToString("yyyy-M-d h:mm tt", CultureInfo.InvariantCulture);

            if (AgilityContext.PreviewDateTime == DateTime.MinValue)
            {
                previewDateStr = string.Empty;
            }

            //output the script for the onload
            sb.Append("<script type='text/javascript'>");

            //output the context object
            sb.AppendFormat(@"var agilityContextObj = {{
					currentMode:""{0}"", 
					isPreview:{1}, 
					isTemplatePreview:{2}, 
					languageCode:""{3}"", 
					websiteName:""{4}"", 
					isDevelopmentMode:{5}, 
					controlUniqueID:""{6}"", 
					previewDateTime:""{7}"",
					isPublished:{8}, 
					containsUnpublishedModules:{9}, 
					pageTemplatePath:""{10}"", 
					pageTemplateID:{11}, 
					previewURL:""{12}"",
					cookieDomain:""{13}"",
					pageID:""{14}"",
					errorLink:{15},
					channel:'{16}',
					channels:[{17}]
				}}; "                ,
                            new object[] {
                AgilityContext.CurrentMode,                                        //0
                AgilityContext.IsPreview.ToString().ToLowerInvariant(),            //1
                AgilityContext.IsTemplatePreview.ToString().ToLowerInvariant(),    //2
                AgilityContext.LanguageCode,                                       //3
                AgilityContext.WebsiteName.Replace("\"", "\\\"").Replace(" ", ""), //4
                Current.Settings.DevelopmentMode.ToString().ToLowerInvariant(),    //5
                uniqueID,                                                          //6
                previewDateStr,                                                    //7
                isPublished.ToString().ToLowerInvariant(),                         //8
                containsUnpublishedModules.ToString().ToLowerInvariant(),          //9
                pageTemplatePath.Replace("\"", "\\\""),                            //10
                pageTemplateID,                                                    //11
                previewURL.Replace("\"", "\\\""),                                  //12
                Current.Settings.CookieDomain,                                     //13
                pageID,
                Current.Settings.DevelopmentMode && WebTrace.HasErrorOccurred ? string.Format("'{0}?enc={1}'", Agility.Web.HttpModules.AgilityHttpModule.ECMS_ERRORS_KEY, HttpUtility.UrlEncode(WebTrace.GetEncryptionQueryStringForLogFile(DateTime.Now))) : "null",
                AgilityContext.CurrentChannel.ReferenceName,
                string.Join(",", channels)
            });
            sb.Append(Environment.NewLine);
            sb.Append("var agilityLanguages = [");

            foreach (Language lang in AgilityContext.Domain.Languages)
            {
                sb.AppendFormat("['{0}', '{1}'],", lang.LanguageName, lang.LanguageCode);
            }
            sb = sb.Remove(sb.Length - 1, 1);
            sb.Append("];");
            sb.Append(Environment.NewLine);
            sb.Append("</script>");

            sb.Append("<script type='text/javascript' src='https://media.agilitycms.com/preview-bar/2018-11/agility-preview-bar.es5.min.js'></script>");


            return(sb.ToString());
        }
        private string GetCodeContent()
        {
            Agility.Web.AgilityContentServer.AgilityModule module = BaseCache.GetModule(moduleID, AgilityContext.WebsiteName);

            return(module.Markup);
        }