/// <param name="consumeNode"></param>
        private void readConsumptionNode(XmlNode consumeNode)
        {
            foreach (XmlNode node in consumeNode.ChildNodes)
            {
                try
                {
                    // Extract power, water, sewage, garbage and wealth
                    string[] attr    = node.Name.Split(new char[] { '_' });
                    string   name    = attr[0];
                    int      level   = Convert.ToInt32(attr[1]) - 1;
                    int      power   = Convert.ToInt32(node.Attributes["power"].InnerText);
                    int      water   = Convert.ToInt32(node.Attributes["water"].InnerText);
                    int      sewage  = Convert.ToInt32(node.Attributes["sewage"].InnerText);
                    int      garbage = Convert.ToInt32(node.Attributes["garbage"].InnerText);
                    int      wealth  = Convert.ToInt32(node.Attributes["wealth"].InnerText);
                    int[]    array   = getArray(name, level, "readConsumptionNode");

                    setConsumptionRates(array, power, water, sewage, garbage, wealth);
                }
                catch (Exception e)
                {
                    Debugging.bufferWarning("readConsumptionNode: " + e.Message);
                }
            }
        }
        /// <param name="node"></param>
        private void ReadPrintWorkers(XmlNode parent)
        {
            foreach (XmlNode node in parent.ChildNodes)
            {
                if (node.Name.Equals(meshName))
                {
                    try
                    {
                        string name       = node.InnerText;
                        int    PrintValue = 5;
                        PrintValue = Convert.ToInt32(node.Attributes["value"].InnerText);

                        if (name.Length > 0)
                        {
                            // Needs a value to be valid
                            int endResult = PrintValue;
                            DataStore.workerPrintOutCache.Add(name, endResult);
                        }
                    }
                    catch (Exception e)
                    {
                        Debugging.bufferWarning("readPrintWorkers: " + e.Message + ". Setting to 5");
                    }
                }
            }
        }
        /// <param name="node"></param>
        private void ReadBonusHouseNode(XmlNode parent)
        {
            foreach (XmlNode node in parent.ChildNodes)
            {
                if (node.Name.Equals(meshName))
                {
                    try
                    {
                        string name       = node.InnerText;
                        int    BonusValue = 1;
                        BonusValue = Convert.ToInt32(node.Attributes["value"].InnerText);

                        if (name.Length > 0)
                        {
                            // Needs a value to be valid
                            DataStore.bonusHouseholdCache.Add(name, BonusValue);
                        }
                    }
                    catch (Exception e)
                    {
                        Debugging.bufferWarning("readBonusHouseNode: " + e.Message + ". Setting to 1");
                    }
                }
            }
        }
        /// <summary>
        ///
        /// </summary>
        private void ReadFromXML()
        {
            // Check the exe directory first
            DataStore.currentFileLocation = ColossalFramework.IO.DataLocation.executableDirectory + Path.DirectorySeparatorChar + XML_FILE;
            bool fileAvailable = File.Exists(DataStore.currentFileLocation);

            if (!fileAvailable)
            {
                // Switch to default which is the cities skylines in the application data area.
                DataStore.currentFileLocation = ColossalFramework.IO.DataLocation.localApplicationData + Path.DirectorySeparatorChar + XML_FILE;
                fileAvailable = File.Exists(DataStore.currentFileLocation);
            }

            if (fileAvailable)
            {
                // Load in from XML - Designed to be flat file for ease
                WG_XMLBaseVersion reader = new XML_VersionSix();
                XmlDocument       doc    = new XmlDocument();
                try
                {
                    doc.Load(DataStore.currentFileLocation);

                    int version = Convert.ToInt32(doc.DocumentElement.Attributes["version"].InnerText);
                    if (version > 3 && version <= 5)
                    {
                        // Use version 5
                        reader = new XML_VersionFive();

                        // Make a back up copy of the old system to be safe
                        File.Copy(DataStore.currentFileLocation, DataStore.currentFileLocation + ".ver5", true);
                        string error = "Detected an old version of the XML (v5). " + DataStore.currentFileLocation + ".ver5 has been created for future reference and will be upgraded to the new version.";
                        Debugging.bufferWarning(error);
                        UnityEngine.Debug.Log(error);
                    }
                    else if (version <= 3) // Uh oh... version 4 was a while back..
                    {
                        string error = "Detected an unsupported version of the XML (v4 or less). Backing up for a new configuration as :" + DataStore.currentFileLocation + ".ver4";
                        Debugging.bufferWarning(error);
                        UnityEngine.Debug.Log(error);
                        File.Copy(DataStore.currentFileLocation, DataStore.currentFileLocation + ".ver4", true);
                        return;
                    }
                    reader.readXML(doc);
                }
                catch (Exception e)
                {
                    // Game will now use defaults
                    Debugging.bufferWarning("The following exception(s) were detected while loading the XML file. Some (or all) values may not be loaded.");
                    Debugging.bufferWarning(e.Message);
                    UnityEngine.Debug.LogException(e);
                }
            }
            else
            {
                UnityEngine.Debug.Log("Configuration file not found. Will output new file to : " + DataStore.currentFileLocation);
            }
        }
        /// <param name="doc"></param>
        public override void readXML(XmlDocument doc)
        {
            XmlElement root = doc.DocumentElement;

            try
            {
                //DataStore.enableExperimental = Convert.ToBoolean(root.Attributes["experimental"].InnerText);
                //DataStore.timeBasedRealism = Convert.ToBoolean(root.Attributes["enableTimeVariation"].InnerText);
            }
            catch (Exception)
            {
                DataStore.enableExperimental = false;
            }

            foreach (XmlNode node in root.ChildNodes)
            {
                try
                {
                    if (node.Name.Equals(popNodeName))
                    {
                        readPopulationNode(node);
                    }
                    else if (node.Name.Equals(consumeNodeName))
                    {
                        readConsumptionNode(node);
                    }
                    else if (node.Name.Equals(visitNodeName))
                    {
                        readVisitNode(node);
                    }
                    else if (node.Name.Equals(pollutionNodeName))
                    {
                        readPollutionNode(node);
                    }
                    else if (node.Name.Equals(productionNodeName))
                    {
                        readProductionNode(node);
                    }
                    else if (node.Name.Equals(bonusHouseName))
                    {
                        readBonusHouseNode(node);
                    }
                    else if (node.Name.Equals(bonusWorkName))
                    {
                        readBonusWorkers(node);
                    }
                }
                catch (Exception e)
                {
                    Debugging.bufferWarning(e.Message);
                    UnityEngine.Debug.LogException(e);
                }
            }
        } // end readXML
        /// <param name="node"></param>
        private void readBonusWorkers(XmlNode parent)
        {
            try
            {
                DataStore.printEmploymentNames = Convert.ToBoolean(parent.Attributes["printWorkNames"].InnerText);
            }
            catch (Exception)
            {
                // Do nothing
            }

            try
            {
                DataStore.mergeEmploymentNames = Convert.ToBoolean(parent.Attributes["mergeWorkNames"].InnerText);
            }
            catch (Exception)
            {
                // Do nothing
            }

            foreach (XmlNode node in parent.ChildNodes)
            {
                if (node.Name.Equals(meshName))
                {
                    try
                    {
                        string name  = node.InnerText;
                        int    bonus = 5;
                        bonus = Convert.ToInt32(node.Attributes["bonus"].InnerText);

                        if (name.Length > 0)
                        {
                            // Needs a value to be valid
                            DataStore.bonusWorkerCache.Add(name, bonus);
                        }
                    }
                    catch (Exception e)
                    {
                        Debugging.bufferWarning("readBonusWorkers: " + e.Message + ". Setting to 5");
                    }
                }
            }
        }
        /// <param name="node"></param>
        private void ReadOverrideWorkers(XmlNode parent)
        {
            try
            {
                DataStore.printEmploymentNames = Convert.ToBoolean(parent.Attributes["printWorkNames"].InnerText);
            }
            catch (Exception)
            {
                // Do nothing
            }

            try
            {
                DataStore.mergeEmploymentNames = Convert.ToBoolean(parent.Attributes["mergeWorkNames"].InnerText);
            }
            catch (Exception)
            {
                // Do nothing
            }

            foreach (XmlNode node in parent.ChildNodes)
            {
                string name          = node.InnerText;
                int    overrideValue = 5;
                if (node.Name.Equals(meshName) && (name.Length > 0))
                {
                    try
                    {
                        overrideValue = Convert.ToInt32(node.Attributes["value"].InnerText);
                    }
                    catch (Exception e)
                    {
                        Debugging.bufferWarning("readOverrideWorkers: " + e.Message + ". Setting to 5");
                        overrideValue = 5;
                    }
                    DataStore.workerCache.Add(name, overrideValue);
                }
            }
        }
        /// <param name="node"></param>
        private void ReadOverrideHouseNode(XmlNode parent)
        {
            try
            {
                DataStore.printResidentialNames = Convert.ToBoolean(parent.Attributes["printResNames"].InnerText);
            }
            catch (Exception)
            {
                // Do nothing
            }

            try
            {
                DataStore.mergeResidentialNames = Convert.ToBoolean(parent.Attributes["mergeResNames"].InnerText);
            }
            catch (Exception)
            {
                // Do nothing
            }

            foreach (XmlNode node in parent.ChildNodes)
            {
                string name          = node.InnerText;
                int    overrideValue = 1;
                if (node.Name.Equals(meshName) && (name.Length > 0))
                {
                    try
                    {
                        overrideValue = Convert.ToInt32(node.Attributes["value"].InnerText);
                    }
                    catch (Exception e)
                    {
                        Debugging.bufferWarning("readOverrideHouseNode: " + e.Message + ". Setting to 1");
                        overrideValue = 1;
                    }
                    DataStore.householdCache.Add(name, overrideValue);
                }
            }
        }
        /// <param name="produceNode"></param>
        private void readProductionNode(XmlNode produceNode)
        {
            foreach (XmlNode node in produceNode.ChildNodes)
            {
                try
                {
                    // Extract power, water, sewage, garbage and wealth
                    string[] attr  = node.Name.Split(new char[] { '_' });
                    string   name  = attr[0];
                    int      level = Convert.ToInt32(attr[1]) - 1;
                    int[]    array = getArray(name, level, "readProductionNode");

                    array[DataStore.PRODUCTION] = Convert.ToInt32(node.Attributes["production"].InnerText);
                    if (array[DataStore.PRODUCTION] <= 0)
                    {
                        array[DataStore.PRODUCTION] = 1;
                    }
                }
                catch (Exception e)
                {
                    Debugging.bufferWarning("readProductionNode: " + e.Message);
                }
            }
        }
        /// <param name="popNode"></param>
        private void readPopulationNode(XmlNode popNode)
        {
            try
            {
                DataStore.strictCapacity = Convert.ToBoolean(popNode.Attributes["strictCapacity"].InnerText);
            }
            catch (Exception)
            {
                // Do nothing
            }

            foreach (XmlNode node in popNode.ChildNodes)
            {
                // TODO - These two to be removed in Jan 2017
                if (node.Name.Equals(bonusHouseName))
                {
                    readBonusHouseNode(node);
                }
                else if (node.Name.Equals(bonusWorkName))
                {
                    readBonusWorkers(node);
                }
                else
                {
                    string[] attr  = node.Name.Split(new char[] { '_' });
                    string   name  = attr[0];
                    int      level = Convert.ToInt32(attr[1]) - 1;
                    int[]    array = new int[12];

                    try
                    {
                        array = getArray(name, level, "readPopulationNode");
                        int temp = Convert.ToInt32(node.Attributes["level_height"].InnerText);
                        array[DataStore.LEVEL_HEIGHT] = temp > 0 ? temp : 10;

                        temp = Convert.ToInt32(node.Attributes["space_pp"].InnerText);
                        if (temp <= 0)
                        {
                            temp = 100;  // Bad person trying to give negative or div0 error.
                        }
                        array[DataStore.PEOPLE] = transformPopulationModifier(name, level, temp, false);
                    }
                    catch (Exception e)
                    {
                        Debugging.bufferWarning("readPopulationNode, part a: " + e.Message);
                    }

                    try
                    {
                        if (Convert.ToBoolean(node.Attributes["calc"].InnerText.Equals("plot")))
                        {
                            array[DataStore.CALC_METHOD] = 1;
                        }
                        else
                        {
                            array[DataStore.CALC_METHOD] = 0;
                        }
                    }
                    catch
                    {
                    }

                    if (!name.Contains("Residential"))
                    {
                        try
                        {
                            int dense = Convert.ToInt32(node.Attributes["ground_mult"].InnerText);
                            array[DataStore.DENSIFICATION] = dense >= 0 ? dense : 0;  // Force to be greater than 0

                            int level0 = Convert.ToInt32(node.Attributes["lvl_0"].InnerText);
                            int level1 = Convert.ToInt32(node.Attributes["lvl_1"].InnerText);
                            int level2 = Convert.ToInt32(node.Attributes["lvl_2"].InnerText);
                            int level3 = Convert.ToInt32(node.Attributes["lvl_3"].InnerText);

                            // Ensure all is there first
                            array[DataStore.WORK_LVL0] = level0;
                            array[DataStore.WORK_LVL1] = level1;
                            array[DataStore.WORK_LVL2] = level2;
                            array[DataStore.WORK_LVL3] = level3;
                        }
                        catch (Exception e)
                        {
                            Debugging.bufferWarning("readPopulationNode, part b: " + e.Message);
                        }
                    }
                } // end if
            }     // end foreach
        }
        /// <param name="pollutionNode"></param>
        private void readPollutionNode(XmlNode pollutionNode)
        {
            string name = "";

            foreach (XmlNode node in pollutionNode.ChildNodes)
            {
                try
                {
                    // Extract power, water, sewage, garbage and wealth
                    string[] attr = node.Name.Split(new char[] { '_' });
                    name = attr[0];
                    int level  = Convert.ToInt32(attr[1]) - 1;
                    int ground = Convert.ToInt32(node.Attributes["ground"].InnerText);
                    int noise  = Convert.ToInt32(node.Attributes["noise"].InnerText);

                    switch (name)
                    {
                    case "ResidentialLow":
                        setPollutionRates(DataStore.residentialLow[level], ground, noise);
                        break;

                    case "ResidentialHigh":
                        setPollutionRates(DataStore.residentialHigh[level], ground, noise);
                        break;

                    case "CommercialLow":
                        setPollutionRates(DataStore.commercialLow[level], ground, noise);
                        break;

                    case "CommercialHigh":
                        setPollutionRates(DataStore.commercialHigh[level], ground, noise);
                        break;

                    case "CommercialTourist":
                        setPollutionRates(DataStore.commercialTourist[level], ground, noise);
                        break;

                    case "CommercialLeisure":
                        setPollutionRates(DataStore.commercialLeisure[level], ground, noise);
                        break;

                    case "Office":
                        setPollutionRates(DataStore.office[level], ground, noise);
                        break;

                    case "Industry":
                        setPollutionRates(DataStore.industry[level], ground, noise);
                        break;

                    case "IndustryOre":
                        setPollutionRates(DataStore.industry_ore[level], ground, noise);
                        break;

                    case "IndustryOil":
                        setPollutionRates(DataStore.industry_oil[level], ground, noise);
                        break;

                    case "IndustryForest":
                        setPollutionRates(DataStore.industry_forest[level], ground, noise);
                        break;

                    case "IndustryFarm":
                        setPollutionRates(DataStore.industry_farm[level], ground, noise);
                        break;
                    }
                }
                catch (Exception e)
                {
                    Debugging.bufferWarning("readPollutionNode: " + name + " " + e.Message);
                }
            } // end foreach
        }