private static void ReadTemplateInfoSDCDefinition(ErrorCollector errorCollector, Template.TemplateInfo info, XElement xe)
        {
            foreach (XElement xeg in xe.Elements())
            {
                if (xeg.Value == null)
                {
                    continue;
                }
                switch (GetXEleName(xeg))
                {
                case "HideZeroObs": info.sdcHideZeroObs = errorCollector.XEleGetBool(xeg, xe); break;

                case "MinObsDefault": info.sdcMinObsDefault = errorCollector.XEleGetInt(xeg, xe); break;

                case "MinObsAlternatives":
                    info.sdcMinObsAlternatives = new Dictionary <string, int>(StringComparer.OrdinalIgnoreCase);
                    foreach (var ele in ReadElementGroup(xeg, ReadSdcMinObsAlternative, errorCollector))
                    {
                        if (ele.Key == null)
                        {
                            continue;
                        }
                        if (info.sdcMinObsAlternatives.ContainsKey(ele.Key))
                        {
                            errorCollector.AddDebugOnlyError($"Double definition of SdcMinObsAlternative '{ele.Key}'.");
                        }
                        else
                        {
                            info.sdcMinObsAlternatives.Add(ele.Key, ele.Value);
                        }
                    }
                    break;

                default: errorCollector.AddXmlUnkownEleError(xeg, xe); break;
                }
            }
        }
        private static Template.Filter ReadFilter(XElement xeFilter, ErrorCollector errorCollector)
        {
            Template.Filter filter = new Template.Filter();
            foreach (XElement xe in xeFilter.Elements())
            {
                if (xe.Value == null)
                {
                    continue;
                }
                switch (GetXEleName(xe))
                {
                case "Name": filter.name = xe.Value; break;

                case "FormulaString": filter.formulaString = xe.Value; break;

                case "Reform": filter.reform = errorCollector.XEleGetBool(xe, xeFilter, filter.name); break;

                case "Parameters": filter.parameters = ReadElementGroup(xe, ReadParameter, errorCollector); break;

                default: errorCollector.AddXmlUnkownEleError(xe, xeFilter, filter.name); break;;
                }
            }
            return(filter);
        }
 public static bool ParseTemplateInfo(string path, out Template.TemplateInfo templateInfo, out ErrorCollector errorCollector)
 {
     errorCollector = new ErrorCollector(); templateInfo = new Template.TemplateInfo();
     try
     {
         using (XmlReader xmlReader = XmlReader.Create(path, new XmlReaderSettings()
         {
             ConformanceLevel = ConformanceLevel.Fragment
         }))
         {
             // first element must always be the TemplateInfo!
             while (xmlReader.NodeType != XmlNodeType.Element || xmlReader.Name != "TemplateInfo")
             {
                 if (!xmlReader.Read())
                 {
                     errorCollector.AddError("<TemplateInfo> not found!"); return(false);
                 }
             }
             XElement xeInfo = XElement.ReadFrom(xmlReader) as XElement;
             if (xeInfo == null || xeInfo.Name != "TemplateInfo")
             {
                 errorCollector.AddError("<TemplateInfo> not found!"); return(false);
             }
             templateInfo = ReadInfo(xeInfo, errorCollector);
             return(true); // the only error ReadInfo may produce (except an exception which is caught below) is unknown element, which does no harm
         }
     }
     catch (Exception exception) { errorCollector.AddError(exception.Message); return(false); }
 }
 private static List <T> ReadElementGroup <T>(XElement xeGroup, Func <XElement, ErrorCollector, T> readFunc, ErrorCollector errorCollector)
 {
     return(GetElementGroupList(xeGroup.Elements(),                                                 // e.g. all elements of <Actions>
                                GetXEleName(xeGroup).Substring(0, GetXEleName(xeGroup).Length - 1), // e.g. Actions -> Action
                                readFunc, errorCollector));
 }
        private static Template.TemplateInfo.UserVariable ReadUserVariable(XElement xeUV, ErrorCollector errorCollector)
        {
            Template.TemplateInfo.UserVariable uv = new Template.TemplateInfo.UserVariable();
            foreach (XElement xe in xeUV.Elements())
            {
                if (xe.Value == null)
                {
                    continue;
                }
                switch (GetXEleName(xe))
                {
                case "UserInputType": uv.inputType = errorCollector.XEleGetEnum <HardDefinitions.UserInputType>(xe, xeUV, uv.name); break;

                case "Name": uv.name = xe.Value; break;

                case "Description": uv.description = xe.Value; break;

                case "Title": uv.title = xe.Value; break;

                case "DefaultValue": uv.defaultValue = xe.Value; break;

                case "DisplayDescription": uv.displayDescription = errorCollector.XEleGetBool(xe, xeUV, uv.name); break;

                case "ComboItems": uv.comboItems = ReadElementGroup(xe, ReadComboItem, errorCollector); break;

                default: errorCollector.AddXmlUnkownEleError(xe, xeUV, uv.name); break;
                }
            }
            return(uv);
        }
        private static DisplayResults.DisplayPage.DisplayTable.DisplayGraph.Legend ReadLegend(XElement xeLegend, ErrorCollector errorCollector)
        {
            DisplayResults.DisplayPage.DisplayTable.DisplayGraph.Legend legend = new DisplayResults.DisplayPage.DisplayTable.DisplayGraph.Legend();
            foreach (XElement xe in xeLegend.Elements())
            {
                if (xe.Value == null)
                {
                    continue;
                }
                switch (GetXEleName(xe))
                {
                case "Title": legend.title = xe.Value; break;       // not supported in the new presenter!

                case "Docking": legend.docking = xe.Value; break;

                case "Visible": legend.visible = errorCollector.XEleGetBool(xe, xeLegend); break;

                default: errorCollector.AddXmlUnkownEleError(xe, xeLegend); break;
                }
            }
            return(legend);
        }
        private static DisplayResults.DisplayPage.DisplayTable.DisplayGraph.Axis ReadAxis(XElement xeAxis, ErrorCollector errorCollector)
        {
            DisplayResults.DisplayPage.DisplayTable.DisplayGraph.Axis axis = new DisplayResults.DisplayPage.DisplayTable.DisplayGraph.Axis();
            foreach (XElement xe in xeAxis.Elements())
            {
                if (xe.Value == null)
                {
                    continue;
                }
                switch (GetXEleName(xe))
                {
                case "Label": axis.label = xe.Value; break;

                case "ValuesFrom": axis.valuesFrom = xe.Value; break;

                case "StartFromZero": axis.startFromZero = errorCollector.XEleGetBool(xe, xeAxis); break;

                case "Interval": axis.interval = errorCollector.XEleGetInt(xe, xeAxis); break;

                case "LabelDocking": axis.labelDocking = xe.Value; break;

                default: errorCollector.AddXmlUnkownEleError(xe, xeAxis); break;
                }
            }
            return(axis);
        }
        private static DisplayResults.DisplayPage.DisplayTable.DisplayGraph.Series ReadGraphSerie(XElement xeSerie, ErrorCollector errorCollector)
        {
            DisplayResults.DisplayPage.DisplayTable.DisplayGraph.Series serie = new DisplayResults.DisplayPage.DisplayTable.DisplayGraph.Series();
            foreach (XElement xe in xeSerie.Elements())
            {
                if (xe.Value == null)
                {
                    continue;
                }
                switch (GetXEleName(xe))
                {
                case "Visible": serie.visible = errorCollector.XEleGetBool(xe, xeSerie); break;

                case "Name": serie.name = xe.Value; break;

                case "Size": serie.size = errorCollector.XEleGetInt(xe, xeSerie); break;

                case "Colour": serie.colour = xe.Value; break;

                case "Type": serie.type = xe.Value; break;

                case "MarkerStyle": serie.markerStyle = xe.Value; break;

                default: errorCollector.AddXmlUnkownEleError(xe, xeSerie); break;
                }
            }
            return(serie);
        }
        private static DisplayResults.DisplayPage.DisplayTable.DisplayGraph ReadGraph(XElement xeGraph, ErrorCollector errorCollector)
        {
            DisplayResults.DisplayPage.DisplayTable.DisplayGraph graph = new DisplayResults.DisplayPage.DisplayTable.DisplayGraph();
            foreach (XElement xe in xeGraph.Elements())
            {
                if (xe.Value == null)
                {
                    continue;
                }
                switch (GetXEleName(xe))
                {
                case "ShowTable": graph.showTable = errorCollector.XEleGetBool(xe, xeGraph); break;

                case "SeriesInRows": graph.seriesInRows = errorCollector.XEleGetBool(xe, xeGraph); break;

                case "Series": graph.allSeries = ReadElementGroup(xe, ReadGraphSerie, errorCollector); break;

                case "Title": graph.title = xe.Value; break;

                case "Legend": graph.legend = ReadLegend(xe, errorCollector); break;

                case "AxisX": graph.axisX = ReadAxis(xe, errorCollector); break;

                case "AxisY": graph.axisY = ReadAxis(xe, errorCollector); break;

                default: errorCollector.AddXmlUnkownEleError(xe, xeGraph); break;
                }
            }

            return(graph);
        }
        private static Template.TemplateInfo.OptionalVariable ReadOptionalVariable(XElement xeOV, ErrorCollector errorCollector)
        {
            Template.TemplateInfo.OptionalVariable ov = new Template.TemplateInfo.OptionalVariable();
            foreach (XElement xe in xeOV.Elements())
            {
                if (xe.Value == null)
                {
                    continue;
                }
                switch (GetXEleName(xe))
                {
                case "Name": ov.name = xe.Value; break;

                case "ReadVar": ov.readVar = xe.Value; break;

                case "DefaultValue": ov.defaultValue = errorCollector.XEleGetDouble(xe, xeOV, ov.name); break;

                default: errorCollector.AddXmlUnkownEleError(xe, xeOV, ov.name); break;
                }
            }
            return(ov);
        }
        private static Template.TemplateInfo.RequiredVariable ReadRequiredVariable(XElement xeRV, ErrorCollector errorCollector)
        {
            Template.TemplateInfo.RequiredVariable rv = new Template.TemplateInfo.RequiredVariable();
            foreach (XElement xe in xeRV.Elements())
            {
                if (xe.Value == null)
                {
                    continue;
                }
                switch (GetXEleName(xe))
                {
                case "Name": rv.name = xe.Value; break;

                case "ReadVar": rv.readVar = xe.Value; break;

                default: errorCollector.AddXmlUnkownEleError(xe, xeRV, rv.name); break;
                }
            }
            return(rv);
        }
        private static Template.TemplateInfo.CalculationLevel ReadCalculationLevel(XElement xeCL, ErrorCollector errorCollector)
        {
            Template.TemplateInfo.CalculationLevel cl = new Template.TemplateInfo.CalculationLevel();
            foreach (XElement xe in xeCL.Elements())
            {
                if (xe.Value == null)
                {
                    continue;
                }
                switch (GetXEleName(xe))
                {
                case "Name": cl.name = xe.Value; break;

                case "GroupingVar": cl.groupingVar = xe.Value; break;

                default: errorCollector.AddXmlUnkownEleError(xe, xeCL, cl.name); break;
                }
            }
            return(cl);
        }
        private static KeyValuePair <string, int> ReadSdcMinObsAlternative(XElement xeAlt, ErrorCollector errorCollector)
        {
            string name = null; int minObs = int.MinValue;

            foreach (XElement xe in xeAlt.Elements())
            {
                if (xe.Value == null)
                {
                    continue;
                }
                switch (GetXEleName(xe))
                {
                case "Name": name = xe.Value; break;

                case "MinObs": minObs = errorCollector.XEleGetInt(xe, xeAlt); break;

                default: errorCollector.AddXmlUnkownEleError(xe, xeAlt); break;
                }
            }
            if (minObs == int.MinValue || name == null)
            {
                errorCollector.AddDebugOnlyError("Incomplete definition of SdcMinObsAlternative" +
                                                 (name == null ? ": missing 'Name'" : $" '{name}': ") +
                                                 (minObs == int.MinValue ? "missing 'MinObs'" : string.Empty));
            }
            return(new KeyValuePair <string, int>(name, minObs));
        }
        public static bool ParseTemplate(string path, out Template template, out ErrorCollector errorCollector)
        {
            errorCollector = new ErrorCollector(); template = new Template();
            try
            {
                using (XmlReader xmlReader = XmlReader.Create(path, new XmlReaderSettings()
                {
                    ConformanceLevel = ConformanceLevel.Fragment
                }))
                {
                    xmlReader.Read();
                    while (xmlReader.NodeType != XmlNodeType.None && (xmlReader.NodeType != XmlNodeType.Element || xmlReader.Name != "Template"))
                    {
                        xmlReader.Read();
                    }
                    if (xmlReader.NodeType == XmlNodeType.None)
                    {
                        errorCollector.AddError("Invalid Xml-structure!"); return(false);
                    }
                    if (!xmlReader.ReadToDescendant("TemplateInfo"))
                    {
                        errorCollector.AddError("<TemplateInfo> not found!"); return(false);
                    }
                    XElement infoElement = XElement.ReadFrom(xmlReader) as XElement;
                    if (infoElement == null || infoElement.Name != "TemplateInfo")
                    {
                        errorCollector.AddError("<TemplateInfo>: invalid Xml-structure!"); return(false);
                    }
                    template.info = ReadInfo(infoElement, errorCollector);

                    if (!xmlReader.ReadToNextSibling("Globals"))
                    {
                        errorCollector.AddError("<Globals> not found!"); return(false);
                    }
                    XElement globalElement = XElement.ReadFrom(xmlReader) as XElement;
                    if (globalElement == null || globalElement.Name != "Globals")
                    {
                        errorCollector.AddError("<Globals>: invalid Xml-structure!"); return(false);
                    }
                    foreach (XElement ele in globalElement.Elements())
                    {
                        if (ele.Name == "Filters")
                        {
                            template.globalFilters = ReadElementGroup(ele, ReadFilter, errorCollector);
                        }
                        else if (ele.Name == "Actions")
                        {
                            template.globalActions = ReadElementGroup(ele, ReadAction, errorCollector);
                        }
                        else
                        {
                            errorCollector.AddXmlUnkownEleError(ele, globalElement);
                        }
                    }

                    if (!xmlReader.ReadToNextSibling("Pages"))
                    {
                        errorCollector.AddError("<Pages> not found!"); return(false);
                    }
                    template.pages = GetElementGroupList(StreamChildElements(xmlReader), "Page", ReadPage, errorCollector);

                    ReplaceNamedSdcMinObsAlternatives(template.pages, template.info.sdcMinObsAlternatives, errorCollector);
                }
                return(!errorCollector.HasErrors());
            }
            catch (Exception exception) { errorCollector.AddError(exception.Message); return(false); }
        }
        private static void ReplaceNamedSdcMinObsAlternatives(List <Template.Page> pages, Dictionary <string, int> sdcMinObsAlternatives, ErrorCollector errorCollector)
        {
            foreach (Template.Page page in pages)
            {
                foreach (Template.Page.Table table in page.tables)
                {
                    if (table.sdcDefinition.minObsAlternative == null && table.sdcDefinition.minObsAlternativeName != null)
                    {
                        Replace(ref table.sdcDefinition);
                        foreach (Template.Page.Table.Row row in table.rows)
                        {
                            Replace(ref row.sdcDefinition);
                        }
                        foreach (Template.Page.Table.Column column in table.columns)
                        {
                            Replace(ref column.sdcDefinition);
                        }
                        foreach (Template.Page.Table.Column column in table.reformColumns)
                        {
                            Replace(ref column.sdcDefinition);
                        }
                        foreach (Template.Page.Table.Cell cell in table.cells)
                        {
                            Replace(ref cell.sdcDefinition);
                        }
                        foreach (Template.Page.Table.Cell cell in table.reformCells)
                        {
                            Replace(ref cell.sdcDefinition);
                        }
                    }
                }
            }

            void Replace(ref Template.Page.Table.SDCDefinition sdcDefinition)
            {
                if (sdcDefinition.minObsAlternativeName == null)
                {
                    return;
                }
                if (int.TryParse(sdcDefinition.minObsAlternativeName, out int i))
                {
                    sdcDefinition.minObsAlternative = i;
                }
                else
                {
                    if (sdcMinObsAlternatives.ContainsKey(sdcDefinition.minObsAlternativeName))
                    {
                        sdcDefinition.minObsAlternative = sdcMinObsAlternatives[sdcDefinition.minObsAlternativeName];
                    }
                    else
                    {
                        errorCollector.AddDebugOnlyError($"Unknown SdcMinObsAlternative '{sdcDefinition.minObsAlternativeName}'.");
                    }
                }
            }
        }