private static void ProcessGunNode(XElement gun, XElement commonVehicleData, bool assignDefaultValues)
        {
            gun.ProcessArmorList(commonVehicleData)
            .ProcessShellList()
            .Select("turretYawLimits", t => t.TextToElements("left", "right"))
            .Select("armor",
                    a => a.AppendCommonArmorGroup(commonVehicleData, "gunBreech")
                    .AppendCommonArmorGroup(commonVehicleData, "surveyingDevice"));             //surveyingDevice exists for guns on oscillating turret

            if (gun.Element("turretYawLimits") == null)
            {
                if (assignDefaultValues)
                {
                    var turretYawLimitsElement = new XElement("turretYawLimits");
                    turretYawLimitsElement.SetElementValue("left", -180);
                    turretYawLimitsElement.SetElementValue("right", 180);
                    gun.Add(turretYawLimitsElement);
                }
            }

            var pitchLimitsElement = gun.Element("pitchLimits");

            if (pitchLimitsElement != null)
            {
                var minPitchElement = pitchLimitsElement.Element("minPitch");
                var maxPitchElement = pitchLimitsElement.Element("maxPitch");
                if (minPitchElement != null || maxPitchElement != null) // post 9.9
                {
                    gun.Add(BigworldXmlPreprocessor.CreatePitchLimitComponentElement("elevation",
                                                                                     minPitchElement,
                                                                                     0.0));

                    gun.Add(BigworldXmlPreprocessor.CreatePitchLimitComponentElement("depression",
                                                                                     maxPitchElement,
                                                                                     0.0));
                }
                else
                {
                    throw new NotSupportedException("pre-9.9 format of gun pitch limitation is not supported any more");
                }
            }

            var clip = gun.Element("clip");

            if (clip == null)
            {
                if (assignDefaultValues)
                {
                    gun.Add(clip = new XElement("clip"));
                    clip.SetElementValue("count", 1);
                    clip.SetElementValue("rate", 0);
                    clip.SetElementValue("reloadTime", 0);
                }
            }
            else
            {
                var clipRateElement = clip.Element("rate");
                Debug.Assert(clipRateElement != null, "clipRateElement != null");

                clip.SetElementValue("reloadTime", 60.0 / double.Parse(clipRateElement.Value, CultureInfo.InvariantCulture));
            }

            var burst = gun.Element("burst");

            if (burst == null)
            {
                if (assignDefaultValues)
                {
                    gun.Add(burst = new XElement("burst"));
                    burst.SetElementValue("count", 1);
                    burst.SetElementValue("rate", 0);
                }
            }

            BigworldXmlPreprocessor.ProcessHitTester(gun);
        }
        public XElement ProcessTankFile(string nation, string key)
        {
            var element = BigworldXmlPreprocessor.LoadFile(_paths.GetTankFile(nation, key));

            element.TrimNameTail()
            .NameToAttribute("tank")
            .RenameElement("crew", "crews")
            .RenameElement("camouflage", "camouflageInfo")
            .ProcessElements("crews",
                             e => e.NameToAttribute("crew", "role")
                             .TextToElement("secondaryRoles")
                             .Select("secondaryRoles",
                                     s =>
                                     s.TextToElementList("secondaryRole")))
            .Select("hull",
                    e =>
            {
                e.ProcessArmorList(this.CommonVehicleData)
                .Select("armor",
                        a => a.AppendCommonArmorGroup(this.CommonVehicleData, "surveyingDevice")
                        .AppendCommonArmorGroup(this.CommonVehicleData, "turretRotator"));

                BigworldXmlPreprocessor.ProcessHitTester(e);
            })
            .ProcessTankModuleListNode("chassis",
                                       "chassis",
                                       _localization,
                                       e =>
            {
                e.ProcessArmorList(this.CommonVehicleData)
                .Select("terrainResistance",
                        t => t.TextToElements("hard", "medium", "soft"));

                BigworldXmlPreprocessor.ProcessHitTester(e);
            })
            .RenameElement("turrets0", "turrets")
            .ProcessTankModuleListNode("turrets",
                                       "turret",
                                       _localization,
                                       e =>
            {
                e.ProcessArmorList(this.CommonVehicleData)
                .Select("armor", a => a.AppendCommonArmorGroup(this.CommonVehicleData, "surveyingDevice"))
                .ProcessTankModuleListNode("guns",
                                           "gun",
                                           _localization,
                                           g => BigworldXmlPreprocessor.ProcessGunNode(g, this.CommonVehicleData, false));


                BigworldXmlPreprocessor.ProcessHitTester(e);
            })
            .ProcessTankModuleListNode("engines",
                                       "engine",
                                       _localization,
                                       BigworldXmlPreprocessor.ProcessEngineNode)
            .ProcessTankModuleListNode("fuelTanks", "fuelTank", _localization)
            .ProcessTankModuleListNode("radios", "radio", _localization);

            var unlockNodes = element.XPathSelectElements("(chassis/chassis|turrets/turret|turrets/turret/guns/gun|engines/engine|radios/radio)/unlocks/*");

            foreach (var unlockNode in unlockNodes)
            {
                string searchRootPath;
                switch (unlockNode.Name.LocalName)
                {
                case "gun":
                    searchRootPath = "turrets/turret/guns/gun";
                    break;

                case "chassis":
                    searchRootPath = "chassis/chassis";
                    break;

                case "turret":
                    searchRootPath = "turrets/turret";
                    break;

                case "engine":
                    searchRootPath = "engines/engine";
                    break;

                case "radio":
                    searchRootPath = "radios/radio";
                    break;

                default:
                    continue;
                }

                var targetElements = element.XPathSelectElements(string.Format("{0}[@key='{1}']",
                                                                               searchRootPath,
                                                                               unlockNode.Attribute("key").Value));

                foreach (var targetElement in targetElements)
                {
                    var costElement = unlockNode.Element("cost");
                    Debug.Assert(costElement != null, "costElement != null");
                    targetElement.SetElementValue("experience", costElement.Value);
                }
            }

            return(element);
        }