1 using System;
2 using System.Collections.Generic;
3 using System.Collections.ObjectModel;
4 using System.IO;
5 using System.Linq;
6 using System.Xml.Linq;
7 using System.Xml.XPath;
8 using OpenBveApi.Colors;
9 using OpenBveApi.Interface;
10 using TrainEditor2.Extensions;
11 using TrainEditor2.Models.Panels;
12 using TrainEditor2.Models.Sounds;
13 using TrainEditor2.Models.Trains;
14 using TrainManager.BrakeSystems;
15 using TrainManager.Car;
16 using TrainManager.Handles;
17 using TrainManager.SafetySystems;
18 
19 namespace TrainEditor2.IO.IntermediateFile
20 {
21 	internal static partial class IntermediateFile
22 	{
Parse(string fileName, out Train train, out Panel panel, out Sound sound)23 		internal static void Parse(string fileName, out Train train, out Panel panel, out Sound sound)
24 		{
25 			XDocument xml = XDocument.Load(fileName);
26 			if (xml.XPathSelectElement("/openBVE") != null)
27 			{
28 				throw new InvalidDataException();
29 			}
30 			train = ParseTrainNode(xml.XPathSelectElement("/TrainEditor/Train"));
31 			panel = ParsePanelNode(xml.XPathSelectElement("/TrainEditor/Panel"));
32 			sound = ParseSoundsNode(xml.XPathSelectElement("/TrainEditor/Sounds"));
33 		}
34 
ParseTrainNode(XElement parent)35 		private static Train ParseTrainNode(XElement parent)
36 		{
37 			return new Train
38 			{
39 				Handle = ParseHandleNode(parent.Element("Handle")),
40 				Cab = ParseCabNode(parent.Element("Cab")),
41 				Device = ParseDeviceNode(parent.Element("Device")),
42 				Cars = new ObservableCollection<Car>(parent.XPathSelectElements("Cars/Car").Select(ParseCarNode)),
43 				Couplers = new ObservableCollection<Models.Trains.Coupler>(parent.XPathSelectElements("Couplers/Coupler").Select(ParseCouplerNode))
44 			};
45 		}
46 
ParseHandleNode(XElement parent)47 		private static Handle ParseHandleNode(XElement parent)
48 		{
49 			return new Handle
50 			{
51 				HandleType = (HandleType)Enum.Parse(typeof(HandleType), (string)parent.Element("HandleType")),
52 				PowerNotches = (int)parent.Element("PowerNotches"),
53 				BrakeNotches = (int)parent.Element("BrakeNotches"),
54 				PowerNotchReduceSteps = (int)parent.Element("PowerNotchReduceSteps"),
55 				HandleBehaviour = (EbHandleBehaviour)Enum.Parse(typeof(EbHandleBehaviour), (string)parent.Element("EbHandleBehaviour")),
56 				LocoBrake = (LocoBrakeType)Enum.Parse(typeof(LocoBrakeType), (string)parent.Element("LocoBrakeType")),
57 				LocoBrakeNotches = (int)parent.Element("LocoBrakeNotches"),
58 				DriverPowerNotches = (int)parent.Element("DriverPowerNotches"),
59 				DriverBrakeNotches = (int)parent.Element("DriverBrakeNotches")
60 			};
61 		}
62 
ParseCabNode(XElement parent)63 		private static Cab ParseCabNode(XElement parent)
64 		{
65 			double[] position = ((string)parent.Element("Position")).Split(',').Select(double.Parse).ToArray();
66 
67 			return new Cab
68 			{
69 				PositionX = position[0],
70 				PositionY = position[1],
71 				PositionZ = position[2],
72 				DriverCar = (int)parent.Element("DriverCar")
73 			};
74 		}
75 
ParseDeviceNode(XElement parent)76 		private static Device ParseDeviceNode(XElement parent)
77 		{
78 			return new Device
79 			{
80 				Ats = (AtsModes)Enum.Parse(typeof(AtsModes), (string)parent.Element("Ats")),
81 				Atc = (AtcModes)Enum.Parse(typeof(AtcModes), (string)parent.Element("Atc")),
82 				Eb = (bool)parent.Element("Eb"),
83 				ConstSpeed = (bool)parent.Element("ConstSpeed"),
84 				HoldBrake = (bool)parent.Element("HoldBrake"),
85 				ReAdhesionDevice = (ReadhesionDeviceType)Enum.Parse(typeof(ReadhesionDeviceType), (string)parent.Element("ReAdhesionDevice")),
86 				LoadCompensatingDevice = (double)parent.Element("LoadCompensatingDevice"),
87 				PassAlarm = (PassAlarmType)Enum.Parse(typeof(PassAlarmType), (string)parent.Element("PassAlarm")),
88 				DoorOpenMode = (DoorMode)Enum.Parse(typeof(DoorMode), (string)parent.Element("DoorOpenMode")),
89 				DoorCloseMode = (DoorMode)Enum.Parse(typeof(DoorMode), (string)parent.Element("DoorCloseMode")),
90 				DoorWidth = (double)parent.Element("DoorWidth"),
91 				DoorMaxTolerance = (double)parent.Element("DoorMaxTolerance")
92 			};
93 		}
94 
ParseCarNode(XElement parent)95 		private static Car ParseCarNode(XElement parent)
96 		{
97 			Car car;
98 
99 			if ((bool)parent.Element("IsMotorCar"))
100 			{
101 				car = new MotorCar();
102 			}
103 			else
104 			{
105 				car = new TrailerCar();
106 			}
107 
108 			car.Mass = (double)parent.Element("Mass");
109 			car.Length = (double)parent.Element("Length");
110 			car.Width = (double)parent.Element("Width");
111 			car.Height = (double)parent.Element("Height");
112 			car.CenterOfGravityHeight = (double)parent.Element("CenterOfGravityHeight");
113 			car.DefinedAxles = (bool)parent.Element("DefinedAxles");
114 			car.FrontAxle = (double)parent.Element("FrontAxle");
115 			car.RearAxle = (double)parent.Element("RearAxle");
116 
117 			car.FrontBogie = ParseBogieNode(parent.Element("FrontBogie"));
118 			car.RearBogie = ParseBogieNode(parent.Element("RearBogie"));
119 
120 			car.ExposedFrontalArea = (double)parent.Element("ExposedFrontalArea");
121 			car.UnexposedFrontalArea = (double)parent.Element("UnexposedFrontalArea");
122 
123 			car.Performance = ParsePerformanceNode(parent.Element("Performance"));
124 			car.Delay = ParseDelayNode(parent.Element("Delay"));
125 			car.Move = ParseMoveNode(parent.Element("Move"));
126 			car.Brake = ParseBrakeNode(parent.Element("Brake"));
127 			car.Pressure = ParsePressureNode(parent.Element("Pressure"));
128 
129 			MotorCar motorCar = car as MotorCar;
130 
131 			if (motorCar != null)
132 			{
133 				motorCar.Acceleration = ParseAccelerationNode(parent.Element("Acceleration"));
134 				motorCar.Motor = ParseMotorNode(parent.Element("Motor"));
135 			}
136 
137 			car.Reversed = (bool)parent.Element("Reversed");
138 			car.Object = (string)parent.Element("Object");
139 			car.LoadingSway = (bool)parent.Element("LoadingSway");
140 
141 			return car;
142 		}
143 
ParseBogieNode(XElement parent)144 		private static Car.Bogie ParseBogieNode(XElement parent)
145 		{
146 			return new Car.Bogie
147 			{
148 				DefinedAxles = (bool)parent.Element("DefinedAxles"),
149 				FrontAxle = (double)parent.Element("FrontAxle"),
150 				RearAxle = (double)parent.Element("RearAxle"),
151 				Reversed = (bool)parent.Element("Reversed"),
152 				Object = (string)parent.Element("Object")
153 			};
154 		}
155 
ParsePerformanceNode(XElement parent)156 		private static Performance ParsePerformanceNode(XElement parent)
157 		{
158 			return new Performance
159 			{
160 				Deceleration = (double)parent.Element("Deceleration"),
161 				CoefficientOfStaticFriction = (double)parent.Element("CoefficientOfStaticFriction"),
162 				CoefficientOfRollingResistance = (double)parent.Element("CoefficientOfRollingResistance"),
163 				AerodynamicDragCoefficient = (double)parent.Element("AerodynamicDragCoefficient")
164 			};
165 		}
166 
ParseDelayNode(XElement parent)167 		private static Delay ParseDelayNode(XElement parent)
168 		{
169 			return new Delay
170 			{
171 				DelayPower = new ObservableCollection<Delay.Entry>(parent.XPathSelectElements("DelayPower/Entry").Select(ParseDelayEntryNode)),
172 				DelayBrake = new ObservableCollection<Delay.Entry>(parent.XPathSelectElements("DelayBrake/Entry").Select(ParseDelayEntryNode)),
173 				DelayLocoBrake = new ObservableCollection<Delay.Entry>(parent.XPathSelectElements("DelayLocoBrake/Entry").Select(ParseDelayEntryNode))
174 			};
175 		}
176 
ParseDelayEntryNode(XElement parent)177 		private static Delay.Entry ParseDelayEntryNode(XElement parent)
178 		{
179 			return new Delay.Entry
180 			{
181 				Up = (double)parent.Element("Up"),
182 				Down = (double)parent.Element("Down")
183 			};
184 		}
185 
ParseMoveNode(XElement parent)186 		private static Move ParseMoveNode(XElement parent)
187 		{
188 			return new Move
189 			{
190 				JerkPowerUp = (double)parent.Element("JerkPowerUp"),
191 				JerkPowerDown = (double)parent.Element("JerkPowerDown"),
192 				JerkBrakeUp = (double)parent.Element("JerkBrakeUp"),
193 				JerkBrakeDown = (double)parent.Element("JerkBrakeDown")
194 			};
195 		}
196 
ParseBrakeNode(XElement parent)197 		private static Brake ParseBrakeNode(XElement parent)
198 		{
199 			return new Brake
200 			{
201 				BrakeType = (BrakeSystemType)Enum.Parse(typeof(BrakeSystemType), (string)parent.Element("BrakeType")),
202 				LocoBrakeType = (Brake.LocoBrakeTypes)Enum.Parse(typeof(Brake.LocoBrakeTypes), (string)parent.Element("LocoBrakeType")),
203 				BrakeControlSystem = (EletropneumaticBrakeType)Enum.Parse(typeof(EletropneumaticBrakeType), (string)parent.Element("BrakeControlSystem")),
204 				BrakeControlSpeed = (double)parent.Element("BrakeControlSpeed")
205 			};
206 		}
207 
ParsePressureNode(XElement parent)208 		private static Pressure ParsePressureNode(XElement parent)
209 		{
210 			return new Pressure
211 			{
212 				BrakeCylinderServiceMaximumPressure = (double)parent.Element("BrakeCylinderServiceMaximumPressure"),
213 				BrakeCylinderEmergencyMaximumPressure = (double)parent.Element("BrakeCylinderEmergencyMaximumPressure"),
214 				MainReservoirMinimumPressure = (double)parent.Element("MainReservoirMinimumPressure"),
215 				MainReservoirMaximumPressure = (double)parent.Element("MainReservoirMaximumPressure"),
216 				BrakePipeNormalPressure = (double)parent.Element("BrakePipeNormalPressure")
217 			};
218 		}
219 
ParseAccelerationNode(XElement parent)220 		private static Acceleration ParseAccelerationNode(XElement parent)
221 		{
222 			return new Acceleration
223 			{
224 				Entries = new ObservableCollection<Acceleration.Entry>(parent.Elements("Entry").Select(n => new Acceleration.Entry
225 				{
226 					A0 = (double)n.Element("a0"),
227 					A1 = (double)n.Element("a1"),
228 					V1 = (double)n.Element("v1"),
229 					V2 = (double)n.Element("v2"),
230 					E = (double)n.Element("e")
231 				}))
232 			};
233 		}
234 
ParseMotorNode(XElement parent)235 		private static Motor ParseMotorNode(XElement parent)
236 		{
237 			return new Motor
238 			{
239 				Tracks = new ObservableCollection<Motor.Track>(parent.Elements("Track").Select(ParseTrackNode))
240 			};
241 		}
242 
ParseTrackNode(XElement parent)243 		private static Motor.Track ParseTrackNode(XElement parent)
244 		{
245 			Motor.Track track = new Motor.Track();
246 
247 			ParseVertexLineNode(parent.Element("Pitch"), out track.PitchVertices, out track.PitchLines);
248 			ParseVertexLineNode(parent.Element("Volume"), out track.VolumeVertices, out track.VolumeLines);
249 			ParseAreaNode(parent.Element("SoundIndex"), out track.SoundIndices);
250 
251 			return track;
252 		}
253 
ParseVertexLineNode(XElement parent, out Motor.VertexLibrary vertices, out ObservableCollection<Motor.Line> lines)254 		private static void ParseVertexLineNode(XElement parent, out Motor.VertexLibrary vertices, out ObservableCollection<Motor.Line> lines)
255 		{
256 			vertices = new Motor.VertexLibrary();
257 
258 			foreach (XElement n in parent.XPathSelectElements("Vertices/Vertex"))
259 			{
260 				double[] position = ((string)n.Element("Position")).Split(',').Select(double.Parse).ToArray();
261 
262 				vertices.Add((int)n.Element("Id"), new Motor.Vertex(position[0], position[1]));
263 			}
264 
265 			lines = new ObservableCollection<Motor.Line>(parent.XPathSelectElements("Lines/Line").Select(n => new Motor.Line((int)n.Element("LeftID"), (int)n.Element("RightID"))));
266 		}
267 
ParseAreaNode(XElement parent, out ObservableCollection<Motor.Area> areas)268 		private static void ParseAreaNode(XElement parent, out ObservableCollection<Motor.Area> areas)
269 		{
270 			areas = new ObservableCollection<Motor.Area>(parent.XPathSelectElements("Areas/Area").Select(n => new Motor.Area((double)n.Element("LeftX"), (double)n.Element("RightX"), (int)n.Element("Index"))));
271 		}
272 
ParseCouplerNode(XElement parent)273 		private static Models.Trains.Coupler ParseCouplerNode(XElement parent)
274 		{
275 			return new Models.Trains.Coupler
276 			{
277 				Min = (double)parent.Element("Min"),
278 				Max = (double)parent.Element("Max"),
279 				Object = (string)parent.Element("Object")
280 			};
281 		}
282 
ParsePanelNode(XElement parent)283 		private static Panel ParsePanelNode(XElement parent)
284 		{
285 			return new Panel
286 			{
287 				This = ParseThisNode(parent.Element("This")),
288 				Screens = new ObservableCollection<Screen>(parent.XPathSelectElements("Screens/Screen").Select(ParseScreenNode)),
289 				PanelElements = new ObservableCollection<PanelElement>(parent.XPathSelectElements("PanelElements/*").Select(ParsePanelElementNode).Where(x => x != null))
290 			};
291 		}
292 
ParseThisNode(XElement parent)293 		private static This ParseThisNode(XElement parent)
294 		{
295 			double[] center = ((string)parent.Element("Center")).Split(',').Select(double.Parse).ToArray();
296 			double[] origin = ((string)parent.Element("Origin")).Split(',').Select(double.Parse).ToArray();
297 
298 			return new This
299 			{
300 				Resolution = (double)parent.Element("Resolution"),
301 				Left = (double)parent.Element("Left"),
302 				Right = (double)parent.Element("Right"),
303 				Top = (double)parent.Element("Top"),
304 				Bottom = (double)parent.Element("Bottom"),
305 				DaytimeImage = (string)parent.Element("DaytimeImage"),
306 				NighttimeImage = (string)parent.Element("NighttimeImage"),
307 				TransparentColor = Color24.ParseHexColor((string)parent.Element("TransparentColor")),
308 				CenterX = center[0],
309 				CenterY = center[1],
310 				OriginX = origin[0],
311 				OriginY = origin[1]
312 			};
313 		}
314 
ParseScreenNode(XElement parent)315 		private static Screen ParseScreenNode(XElement parent)
316 		{
317 			Screen screen = new Screen
318 			{
319 				Number = (int)parent.Element("Number"),
320 				Layer = (int)parent.Element("Layer"),
321 				PanelElements = new ObservableCollection<PanelElement>(parent.XPathSelectElements("PanelElements/*").Select(ParsePanelElementNode).Where(x => x != null))
322 			};
323 
324 			screen.TouchElements = new ObservableCollection<Models.Panels.TouchElement>(parent.XPathSelectElements("TouchElements/Touch").Select(x => ParseTouchElementNode(screen, x)));
325 
326 			return screen;
327 		}
328 
ParsePanelElementNode(XElement parent)329 		private static PanelElement ParsePanelElementNode(XElement parent)
330 		{
331 			PanelElement element = null;
332 
333 			switch (parent.Name.LocalName)
334 			{
335 				case "PilotLamp":
336 					ParsePilotLampElementNode(parent, out element);
337 					break;
338 				case "Needle":
339 					ParseNeedleElementNode(parent, out element);
340 					break;
341 				case "DigitalNumber":
342 					ParseDigitalNumberElementNode(parent, out element);
343 					break;
344 				case "DigitalGauge":
345 					ParseDigitalGaugeElementNode(parent, out element);
346 					break;
347 				case "LinearGauge":
348 					ParseLinearGaugeElementNode(parent, out element);
349 					break;
350 				case "Timetable":
351 					ParseTimetableElementNode(parent, out element);
352 					break;
353 			}
354 
355 			return element;
356 		}
357 
ParsePilotLampElementNode(XElement parent, out PanelElement element)358 		private static void ParsePilotLampElementNode(XElement parent, out PanelElement element)
359 		{
360 			double[] location = ((string)parent.Element("Location")).Split(',').Select(double.Parse).ToArray();
361 
362 			element = new Models.Panels.PilotLampElement
363 			{
364 				LocationX = location[0],
365 				LocationY = location[1],
366 				Layer = (int)parent.Element("Layer"),
367 				Subject = ParseSubjectNode(parent.Element("Subject")),
368 				DaytimeImage = (string)parent.Element("DaytimeImage"),
369 				NighttimeImage = (string)parent.Element("NighttimeImage"),
370 				TransparentColor = Color24.ParseHexColor((string)parent.Element("TransparentColor"))
371 			};
372 		}
373 
ParseNeedleElementNode(XElement parent, out PanelElement element)374 		private static void ParseNeedleElementNode(XElement parent, out PanelElement element)
375 		{
376 			double[] location = ((string)parent.Element("Location")).Split(',').Select(double.Parse).ToArray();
377 			double[] origin = ((string)parent.Element("Origin")).Split(',').Select(double.Parse).ToArray();
378 
379 			element = new NeedleElement
380 			{
381 				LocationX = location[0],
382 				LocationY = location[1],
383 				Layer = (int)parent.Element("Layer"),
384 				Subject = ParseSubjectNode(parent.Element("Subject")),
385 				DaytimeImage = (string)parent.Element("DaytimeImage"),
386 				NighttimeImage = (string)parent.Element("NighttimeImage"),
387 				TransparentColor = Color24.ParseHexColor((string)parent.Element("TransparentColor")),
388 				DefinedRadius = (bool)parent.Element("DefinedRadius"),
389 				Radius = (double)parent.Element("Radius"),
390 				Color = Color24.ParseHexColor((string)parent.Element("Color")),
391 				DefinedOrigin = (bool)parent.Element("DefinedOrigin"),
392 				OriginX = origin[0],
393 				OriginY = origin[1],
394 				InitialAngle = (double)parent.Element("InitialAngle"),
395 				LastAngle = (double)parent.Element("LastAngle"),
396 				Minimum = (double)parent.Element("Minimum"),
397 				Maximum = (double)parent.Element("Maximum"),
398 				DefinedNaturalFreq = (bool)parent.Element("DefinedNaturalFreq"),
399 				NaturalFreq = (double)parent.Element("NaturalFreq"),
400 				DefinedDampingRatio = (bool)parent.Element("DefinedDampingRatio"),
401 				DampingRatio = (double)parent.Element("DampingRatio"),
402 				Backstop = (bool)parent.Element("Backstop"),
403 				Smoothed = (bool)parent.Element("Smoothed")
404 			};
405 		}
406 
ParseDigitalNumberElementNode(XElement parent, out PanelElement element)407 		private static void ParseDigitalNumberElementNode(XElement parent, out PanelElement element)
408 		{
409 			double[] location = ((string)parent.Element("Location")).Split(',').Select(double.Parse).ToArray();
410 
411 			element = new DigitalNumberElement
412 			{
413 				LocationX = location[0],
414 				LocationY = location[1],
415 				Layer = (int)parent.Element("Layer"),
416 				Subject = ParseSubjectNode(parent.Element("Subject")),
417 				DaytimeImage = (string)parent.Element("DaytimeImage"),
418 				NighttimeImage = (string)parent.Element("NighttimeImage"),
419 				TransparentColor = Color24.ParseHexColor((string)parent.Element("TransparentColor")),
420 				Interval = (int)parent.Element("Interval")
421 			};
422 		}
423 
ParseDigitalGaugeElementNode(XElement parent, out PanelElement element)424 		private static void ParseDigitalGaugeElementNode(XElement parent, out PanelElement element)
425 		{
426 			double[] location = ((string)parent.Element("Location")).Split(',').Select(double.Parse).ToArray();
427 
428 			element = new DigitalGaugeElement
429 			{
430 				LocationX = location[0],
431 				LocationY = location[1],
432 				Layer = (int)parent.Element("Layer"),
433 				Subject = ParseSubjectNode(parent.Element("Subject")),
434 				Radius = (double)parent.Element("Radius"),
435 				Color = Color24.ParseHexColor((string)parent.Element("Color")),
436 				InitialAngle = (double)parent.Element("InitialAngle"),
437 				LastAngle = (double)parent.Element("LastAngle"),
438 				Minimum = (double)parent.Element("Minimum"),
439 				Maximum = (double)parent.Element("Maximum"),
440 				Step = (double)parent.Element("Step")
441 			};
442 		}
443 
ParseLinearGaugeElementNode(XElement parent, out PanelElement element)444 		private static void ParseLinearGaugeElementNode(XElement parent, out PanelElement element)
445 		{
446 			double[] location = ((string)parent.Element("Location")).Split(',').Select(double.Parse).ToArray();
447 			int[] direction = ((string)parent.Element("Direction")).Split(',').Select(int.Parse).ToArray();
448 
449 			element = new LinearGaugeElement
450 			{
451 				LocationX = location[0],
452 				LocationY = location[1],
453 				Layer = (int)parent.Element("Layer"),
454 				Subject = ParseSubjectNode(parent.Element("Subject")),
455 				DaytimeImage = (string)parent.Element("DaytimeImage"),
456 				NighttimeImage = (string)parent.Element("NighttimeImage"),
457 				TransparentColor = Color24.ParseHexColor((string)parent.Element("TransparentColor")),
458 				Minimum = (double)parent.Element("Minimum"),
459 				Maximum = (double)parent.Element("Maximum"),
460 				DirectionX = direction[0],
461 				DirectionY = direction[1],
462 				Width = (int)parent.Element("Width")
463 			};
464 		}
465 
ParseTimetableElementNode(XElement parent, out PanelElement element)466 		private static void ParseTimetableElementNode(XElement parent, out PanelElement element)
467 		{
468 			double[] location = ((string)parent.Element("Location")).Split(',').Select(double.Parse).ToArray();
469 
470 			element = new TimetableElement
471 			{
472 				LocationX = location[0],
473 				LocationY = location[1],
474 				Layer = (int)parent.Element("Layer"),
475 				Width = (double)parent.Element("Width"),
476 				Height = (double)parent.Element("Height"),
477 				TransparentColor = Color24.ParseHexColor((string)parent.Element("TransparentColor"))
478 			};
479 		}
480 
ParseSubjectNode(XElement parent)481 		private static Subject ParseSubjectNode(XElement parent)
482 		{
483 			return new Subject
484 			{
485 				Base = (SubjectBase)Enum.Parse(typeof(SubjectBase), (string)parent.Element("Base")),
486 				BaseOption = (int)parent.Element("BaseOption"),
487 				Suffix = (SubjectSuffix)Enum.Parse(typeof(SubjectSuffix), (string)parent.Element("Suffix")),
488 				SuffixOption = (int)parent.Element("SuffixOption")
489 			};
490 		}
491 
ParseTouchElementNode(Screen screen, XElement parent)492 		private static Models.Panels.TouchElement ParseTouchElementNode(Screen screen, XElement parent)
493 		{
494 			double[] location = ((string)parent.Element("Location")).Split(',').Select(double.Parse).ToArray();
495 			double[] size = ((string)parent.Element("Size")).Split(',').Select(double.Parse).ToArray();
496 
497 			Models.Panels.TouchElement element = new Models.Panels.TouchElement(screen)
498 			{
499 				LocationX = location[0],
500 				LocationY = location[1],
501 				SizeX = size[0],
502 				SizeY = size[1],
503 				JumpScreen = (int)parent.Element("JumpScreen")
504 			};
505 
506 			if (parent.Element("SoundIndex") != null)
507 			{
508 				element.SoundEntries.Add(new Models.Panels.TouchElement.SoundEntry
509 				{
510 					Index = (int)parent.Element("SoundIndex")
511 				});
512 			}
513 
514 			if (parent.Element("CommandInfo") != null && parent.Element("CommandOption") != null)
515 			{
516 				element.CommandEntries.Add(new Models.Panels.TouchElement.CommandEntry
517 				{
518 					Info = Translations.CommandInfos.TryGetInfo((Translations.Command)Enum.Parse(typeof(Translations.Command), (string)parent.Element("CommandInfo"))),
519 					Option = (int)parent.Element("CommandOption")
520 				});
521 			}
522 
523 			element.SoundEntries.AddRange(parent.XPathSelectElements("SoundEntries/Entry").Select(ParseTouchElementSoundEntryNode));
524 			element.CommandEntries.AddRange(parent.XPathSelectElements("CommandEntries/Entry").Select(ParseTouchElementCommandEntryNode));
525 			element.Layer = (int)parent.Element("Layer");
526 
527 			return element;
528 		}
529 
ParseTouchElementSoundEntryNode(XElement parent)530 		private static Models.Panels.TouchElement.SoundEntry ParseTouchElementSoundEntryNode(XElement parent)
531 		{
532 			return new Models.Panels.TouchElement.SoundEntry
533 			{
534 				Index = (int)parent.Element("Index")
535 			};
536 		}
537 
ParseTouchElementCommandEntryNode(XElement parent)538 		private static Models.Panels.TouchElement.CommandEntry ParseTouchElementCommandEntryNode(XElement parent)
539 		{
540 			return new Models.Panels.TouchElement.CommandEntry
541 			{
542 				Info = Translations.CommandInfos.TryGetInfo((Translations.Command)Enum.Parse(typeof(Translations.Command), (string)parent.Element("Info"))),
543 				Option = (int)parent.Element("Option")
544 			};
545 		}
546 
ParseSoundsNode(XElement parent)547 		private static Sound ParseSoundsNode(XElement parent)
548 		{
549 			Sound sound = new Sound();
550 
551 			ParseArraySoundNode<RunElement>(parent.Element("Run"), sound.SoundElements);
552 			ParseArraySoundNode<FlangeElement>(parent.Element("Flange"), sound.SoundElements);
553 			ParseArraySoundNode<MotorElement>(parent.Element("Motor"), sound.SoundElements);
554 			ParseArraySoundNode<FrontSwitchElement>(parent.Element("FrontSwitch"), sound.SoundElements);
555 			ParseArraySoundNode<RearSwitchElement>(parent.Element("RearSwitch"), sound.SoundElements);
556 			ParseArraySoundNode<BrakeElement, BrakeKey>(parent.Element("Brake"), sound.SoundElements);
557 			ParseArraySoundNode<CompressorElement, CompressorKey>(parent.Element("Compressor"), sound.SoundElements);
558 			ParseArraySoundNode<SuspensionElement, SuspensionKey>(parent.Element("Suspension"), sound.SoundElements);
559 			ParseArraySoundNode<PrimaryHornElement, HornKey>(parent.Element("PrimaryHorn"), sound.SoundElements);
560 			ParseArraySoundNode<SecondaryHornElement, HornKey>(parent.Element("SecondaryHorn"), sound.SoundElements);
561 			ParseArraySoundNode<MusicHornElement, HornKey>(parent.Element("MusicHornHorn"), sound.SoundElements);
562 			ParseArraySoundNode<DoorElement, DoorKey>(parent.Element("Door"), sound.SoundElements);
563 			ParseArraySoundNode<AtsElement>(parent.Element("Ats"), sound.SoundElements);
564 			ParseArraySoundNode<BuzzerElement, BuzzerKey>(parent.Element("Buzzer"), sound.SoundElements);
565 			ParseArraySoundNode<Models.Sounds.PilotLampElement, PilotLampKey>(parent.Element("PilotLamp"), sound.SoundElements);
566 			ParseArraySoundNode<BrakeHandleElement, BrakeHandleKey>(parent.Element("BrakeHandle"), sound.SoundElements);
567 			ParseArraySoundNode<MasterControllerElement, MasterControllerKey>(parent.Element("MasterController"), sound.SoundElements);
568 			ParseArraySoundNode<ReverserElement, ReverserKey>(parent.Element("Reverser"), sound.SoundElements);
569 			ParseArraySoundNode<BreakerElement, BreakerKey>(parent.Element("Breaker"), sound.SoundElements);
570 			ParseArraySoundNode<RequestStopElement, RequestStopKey>(parent.Element("RequestStop"), sound.SoundElements);
571 			ParseArraySoundNode<Models.Sounds.TouchElement>(parent.Element("Touch"), sound.SoundElements);
572 			ParseArraySoundNode<OthersElement, OthersKey>(parent.Element("Others"), sound.SoundElements);
573 
574 			return sound;
575 		}
576 
577 		private static T ParseSoundNode<T>(XElement parent) where T : SoundElement<int>, new()
578 		{
579 			double[] position = ((string)parent.Element("Position")).Split(',').Select(double.Parse).ToArray();
580 
581 			return new T
582 			{
583 				Key = (int)parent.Element("Key"),
584 				FilePath = (string)parent.Element("FilePath"),
585 				DefinedPosition = (bool)parent.Element("DefinedPosition"),
586 				PositionX = position[0],
587 				PositionY = position[1],
588 				PositionZ = position[2],
589 				DefinedRadius = (bool)parent.Element("DefinedRadius"),
590 				Radius = (double)parent.Element("Radius")
591 			};
592 		}
593 
594 		private static T ParseSoundNode<T, U>(XElement parent) where T : SoundElement<U>, new()
595 		{
596 			double[] position = ((string)parent.Element("Position")).Split(',').Select(double.Parse).ToArray();
597 
598 			return new T
599 			{
600 				Key = (U)Enum.Parse(typeof(U), (string)parent.Element("Key")),
601 				FilePath = (string)parent.Element("FilePath"),
602 				DefinedPosition = (bool)parent.Element("DefinedPosition"),
603 				PositionX = position[0],
604 				PositionY = position[1],
605 				PositionZ = position[2],
606 				DefinedRadius = (bool)parent.Element("DefinedRadius"),
607 				Radius = (double)parent.Element("Radius")
608 			};
609 		}
610 
611 		private static void ParseArraySoundNode<T>(XElement parent, ICollection<SoundElement> elements) where T : SoundElement<int>, new()
612 		{
613 			if (parent != null)
614 			{
615 				elements.AddRange(parent.Elements("Sound").Select(ParseSoundNode<T>));
616 			}
617 		}
618 
619 		private static void ParseArraySoundNode<T, U>(XElement parent, ICollection<SoundElement> elements) where T : SoundElement<U>, new()
620 		{
621 			if (parent != null)
622 			{
623 				elements.AddRange(parent.Elements("Sound").Select(ParseSoundNode<T, U>));
624 			}
625 		}
626 	}
627 }
628