/// <summary>
        /// Creates a new WeibullMarkovModel object loading from the XML file
        /// </summary>
        /// <param name="xmlFileName">Name (path) of the XML file</param>
        /// <param name="xsdFileName">Optional (may be null) name of the schema (XSD) file to falidate the XML file against.</param>
        /// <param name="errorMessage">out Error message</param>
        /// <returns>Created model object, null on failure</returns>
        public static WeibullMarkovModel LoadFromXml(String xmlFileName, String xsdFileName, out String errorMessage)
        {
            errorMessage = null;
            WeibullMarkovModel model = null;;

            try
            {
                Log.InfoFormat("Loading Weibull-Markov model from {0} - started", xmlFileName);
                if (!String.IsNullOrEmpty(xsdFileName))
                {
                    Boolean ok = Utilities.ValidateXMLvsXSD(xmlFileName, xsdFileName, Log, out errorMessage);
                    if (!ok)
                    {
                        throw new Exception(errorMessage);
                    }
                }

                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.Load(xmlFileName);

                XmlElement rootElement = xmlDoc.DocumentElement;

                model = WeibullMarkovModel.FromXmlElement(rootElement, out errorMessage);
                if (model == null)
                {
                    throw new Exception(errorMessage);
                }
            }
            catch (Exception ex)
            {
                model        = null;
                errorMessage = ex.Message;
                Log.Error(errorMessage);
            }

            Log.InfoFormat("Loading Weibull-Markov model from {0} - ended.  OK={1}", xmlFileName, model != null);

            return(model);
        }
        /// <summary>
        /// Constructs an object from XML element
        /// </summary>
        /// <param name="xml">XML element</param>
        /// <param name="errorMessage">out Error message</param>
        /// <returns>Constructed element, null on failure</returns>
        public static WeibullMarkovModel FromXmlElement(XmlElement xml, out String errorMessage)
        {
            WeibullMarkovModel model = null;

            errorMessage = null;

            try
            {
                if (xml.Name != WEIBULL_MARKOV_MODEL)
                {
                    throw new Exception("A <" + WEIBULL_MARKOV_MODEL + "...> XML element expected");
                }
                model = new WeibullMarkovModel(0, 0, true, null, false, 0.0);

                String numStates = xml.GetAttribute(_NUM_STATES);
                if (String.IsNullOrEmpty(numStates))
                {
                    throw new Exception("The '" + _NUM_STATES + "' attribute is missing in the WEIBULL-MARKOV-MODEL XML element");
                }
                model.NumStates = Int32.Parse(numStates);

                String numActions = xml.GetAttribute(_NUM_ACTIONS);
                if (String.IsNullOrEmpty(numActions))
                {
                    throw new Exception("The '" + _NUM_ACTIONS + "' attribute is missing in the WEIBULL-MARKOV-MODEL XML element");
                }
                model.NumActions = Int32.Parse(numActions);

                String failCostEstimate = xml.GetAttribute(_FAIL_COST_ESTIMATE);
                if (String.IsNullOrEmpty(failCostEstimate))
                {
                    throw new Exception("The '" + _FAIL_COST_ESTIMATE + "' attribute is missing in the WEIBULL-MARKOV-MODEL XML element");
                }
                model.FailCostEstimate = failCostEstimate == "1" || failCostEstimate.ToUpper() == "Y";

                String discRatePct = xml.GetAttribute(_DISCOUNT_RATE_PCT);
                model.DiscRate    = Double.Parse(discRatePct);
                model._discFactor = 1.0 / (1.0 + model.DiscRate / 100.0);

                if (!model.FailCostEstimate)
                {
                    String failCost = xml.GetAttribute(_FAIL_COST_VALUE);
                    if (String.IsNullOrEmpty(failCost))
                    {
                        throw new Exception("The '" + _FAIL_COST_VALUE + "' attribute is missing in the WEIBULL-MARKOV-MODEL XML element");
                    }
                    model.FailureCost = Double.Parse(failCost);
                    String failCostOverride = xml.GetAttribute(_FAIL_COST_OVERRIDE);
                    if (String.IsNullOrEmpty(failCostOverride))
                    {
                        throw new Exception("The '" + _FAIL_COST_OVERRIDE + "'attribute is missing in the WEIBULL-MARKOV-MODEL XML element");
                    }
                    model.FailCostOverride = failCostOverride == "1" || failCostOverride.ToUpper() == "Y";
                }

                String failCostPolicy = xml.GetAttribute(_FAIL_COST_POLICY);
                if (!String.IsNullOrEmpty(failCostPolicy))
                {
                    model.FailureCostUsedInPolicy = Double.Parse(failCostPolicy);
                }

                String numKeys = xml.GetAttribute(_NUM_KEYS);
                if (!String.IsNullOrEmpty(numKeys))
                {
                    Int32 n = Int32.Parse(numKeys);
                    if (n > 0)
                    {
                        String[] keys = model.AllocateKeys(n, out errorMessage);
                        if (keys == null)
                        {
                            throw new Exception(errorMessage);
                        }
                    }
                }

                if (xml.HasChildNodes)
                {
                    foreach (XmlNode n1 in xml.ChildNodes)
                    {
                        if (n1.Name == _CONDITION_STATES)
                        {
                            model.States = null;
                            model.States = new List <WeibullMarkovConditionState>(model.NumStates);
                            for (Int32 i = 0; i < model.NumStates; i++)
                            {
                                model.States.Add(null); // We reserve slots in the list so that the states were always going in order of their numbers in the list
                            }
                            if (n1.HasChildNodes)
                            {
                                foreach (XmlNode n2 in n1.ChildNodes)
                                {
                                    if (n2.Name == WeibullMarkovConditionState.CONDITION_STATE)
                                    {
                                        WeibullMarkovConditionState state = WeibullMarkovConditionState.FromXmlElement(n2 as XmlElement, out errorMessage);
                                        if (state == null)
                                        {
                                            throw new Exception(errorMessage);
                                        }
                                        if (state.Number < 1 || state.Number > model.NumStates)
                                        {
                                            String err = String.Format("The number of the condition state ({0}) is out of range (1 - {1})", state.Number, model.NumStates);
                                            throw new Exception(err);
                                        }
                                        model.States[state.Number - 1] = state;
                                    }
                                }
                            }
                        }

                        else if (n1.Name == _KEYS && model.Keys != null && model.Keys.Length > 0)
                        {
                            if (n1.HasChildNodes)
                            {
                                foreach (XmlNode n2 in n1.ChildNodes)
                                {
                                    if (n2.Name == _KEY)
                                    {
                                        String number = (n2 as XmlElement).GetAttribute(_NUMBER);
                                        if (!String.IsNullOrEmpty(number))
                                        {
                                            throw new Exception("'" + _NUMBER + "' attribute missing in the <" + _KEY + " ...> XML element.");
                                        }
                                        String val = (n2 as XmlElement).GetAttribute(_VALUE);
                                        if (!String.IsNullOrEmpty(val))
                                        {
                                            throw new Exception("'" + _VALUE + "' attribute missing in the <" + _KEY + " ...> XML element.");
                                        }
                                        Int32 num = Int32.Parse(number);
                                        if (num < 1 || model.Keys.Length < num)
                                        {
                                            throw new Exception(String.Format("Key number {0} is outof range (1 - {1}).", num, model.Keys.Length));
                                        }
                                        model.Keys[num - 1] = val;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                errorMessage = ex.Message;
                model        = null;
            }

            return(model);
        }