Completed
Push — master ( caabd8...c07396 )
by Oleksandr
01:11
created

_parse_new_version_extra()   A

Complexity

Conditions 3

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 3
Metric Value
cc 3
dl 0
loc 13
ccs 9
cts 9
cp 1
crap 3
rs 9.4286
1
# -*- coding: utf-8 -*-
2
3 1
from il2fb.commons.flight import Formations, RoutePointTypes
4 1
from il2fb.commons.spatial import Point3D
5 1
from il2fb.commons.structures import BaseStructure
6
7 1
from ..constants import (
8
    ROUTE_POINT_EXTRA_PARAMETERS_MARK, ROUTE_POINT_RADIO_SILENCE_ON,
9
    ROUTE_POINT_RADIO_SILENCE_OFF,
10
)
11
12 1
from . import CollectingParser
13
14
15 1
class FlightRoutePoint(BaseStructure):
16 1
    __slots__ = ['type', 'pos', 'speed', 'formation', 'radio_silence', ]
17
18 1
    def __init__(self, type, pos, speed, formation, radio_silence):
19 1
        self.type = type
20 1
        self.pos = pos
21 1
        self.speed = speed
22 1
        self.formation = formation
23 1
        self.radio_silence = radio_silence
24
25 1
    def __repr__(self):
26 1
        return ("<{0} '{1};{2};{3}'>"
27
                .format(self.__class__.__name__,
28
                        self.pos.x, self.pos.y, self.pos.z))
29
30
31 1
class FlightRouteTakeoffPoint(FlightRoutePoint):
32 1
    __slots__ = FlightRoutePoint.__slots__ + ['delay', 'spacing', ]
33
34 1
    def __init__(self, type, pos, speed, formation, radio_silence, delay,
35
                 spacing):
36 1
        super(FlightRouteTakeoffPoint, self).__init__(
37
            type, pos, speed, formation, radio_silence)
38 1
        self.delay = delay
39 1
        self.spacing = spacing
40
41
42 1
class FlightRoutePatrolPoint(FlightRoutePoint):
43 1
    __slots__ = FlightRoutePoint.__slots__ + [
44
        'patrol_cycles', 'patrol_timeout',
45
        'pattern_angle', 'pattern_side_size', 'pattern_altitude_difference',
46
    ]
47
48 1
    def __init__(self, type, pos, speed, formation, radio_silence,
49
                 patrol_cycles, patrol_timeout, pattern_angle,
50
                 pattern_side_size, pattern_altitude_difference):
51 1
        super(FlightRoutePatrolPoint, self).__init__(
52
            type, pos, speed, formation, radio_silence)
53 1
        self.patrol_cycles = patrol_cycles
54 1
        self.patrol_timeout = patrol_timeout
55 1
        self.pattern_angle = pattern_angle
56 1
        self.pattern_side_size = pattern_side_size
57 1
        self.pattern_altitude_difference = pattern_altitude_difference
58
59
60 1
class FlightRouteAttackPoint(FlightRoutePoint):
61 1
    __slots__ = FlightRoutePoint.__slots__ + [
62
        'target_id', 'target_route_point',
63
    ]
64
65 1
    def __init__(self, type, pos, speed, formation, radio_silence, target_id,
66
                 target_route_point):
67 1
        super(FlightRouteAttackPoint, self).__init__(
68
            type, pos, speed, formation, radio_silence)
69 1
        self.target_id = target_id
70 1
        self.target_route_point = target_route_point
71
72
73 1
class FlightRouteSectionParser(CollectingParser):
74
    """
75
    Parses ``*_Way`` section.
76
    View :ref:`detailed description <flight-route-section>`.
77
    """
78 1
    input_suffix = "_Way"
79 1
    output_prefix = 'flight_route_'
80
81 1
    def check_section_name(self, section_name):
82 1
        return section_name.endswith(self.input_suffix)
83
84 1
    def _extract_flight_code(self, section_name):
85 1
        return section_name[:-len(self.input_suffix)]
86
87 1
    def init_parser(self, section_name):
88 1
        super(FlightRouteSectionParser, self).init_parser(section_name)
89 1
        flight_code = self._extract_flight_code(section_name)
90 1
        self.output_key = "{}{}".format(self.output_prefix, flight_code)
91 1
        self.point = None
92 1
        self.point_class = None
93
94 1
    def parse_line(self, line):
95 1
        params = line.split()
96 1
        type_code, params = params[0], params[1:]
97 1
        if type_code == ROUTE_POINT_EXTRA_PARAMETERS_MARK:
98 1
            self._parse_options(params)
99
        else:
100 1
            self._finalize_current_point()
101 1
            pos, speed, params = params[0:3], params[3], params[4:]
102 1
            self.point = {
103
                'type': RoutePointTypes.get_by_value(type_code),
104
                'pos': Point3D(*pos),
105
                'speed': float(speed),
106
            }
107 1
            self._parse_extra(params)
108
109 1
    def _parse_options(self, params):
110 1
        try:
111 1
            cycles, timeout, angle, side_size, altitude_difference = params
112 1
            self.point.update({
113
                'patrol_cycles': int(cycles),
114
                'patrol_timeout': int(timeout),
115
                'pattern_angle': int(angle),
116
                'pattern_side_size': int(side_size),
117
                'pattern_altitude_difference': int(altitude_difference),
118
            })
119 1
            self.point_class = FlightRoutePatrolPoint
120 1
        except ValueError:
121 1
            delay, spacing = params[1:3]
122 1
            self.point.update({
123
                'delay': int(delay),
124
                'spacing': int(spacing),
125
            })
126 1
            self.point_class = FlightRouteTakeoffPoint
127
128 1
    def _parse_extra(self, params):
129 1
        if FlightRouteSectionParser._is_new_game_version(params):
130 1
            radio_silence, formation, params = FlightRouteSectionParser._parse_new_version_extra(params)
131 1
            if params:
132 1
                self._parse_target(params)
133
        else:
134 1
            radio_silence = False
135 1
            formation = None
136
137 1
        self.point.update({
138
            'radio_silence': radio_silence,
139
            'formation': formation,
140
        })
141
142 1
    @staticmethod
143
    def _is_new_game_version(params):
144 1
        return (
145
            ROUTE_POINT_RADIO_SILENCE_ON in params
146
            or ROUTE_POINT_RADIO_SILENCE_OFF in params
147
        )
148
149 1
    @staticmethod
150
    def _parse_new_version_extra(params):
151 1
        try:
152 1
            index = params.index(ROUTE_POINT_RADIO_SILENCE_ON)
153 1
        except ValueError:
154 1
            index = params.index(ROUTE_POINT_RADIO_SILENCE_OFF)
155
156 1
        params, radio_silence, extra = params[:index], params[index], params[index+1:]
157
158 1
        radio_silence = radio_silence == ROUTE_POINT_RADIO_SILENCE_ON
159 1
        formation = Formations.get_by_value(extra[0]) if extra else None
160
161 1
        return radio_silence, formation, params
162
163 1
    def _parse_target(self, params):
164 1
        target_id, target_route_point = params[:2]
165
166 1
        self.point.update({
167
            'target_id': target_id,
168
            'target_route_point': int(target_route_point),
169
        })
170
171 1
        if self.point['type'] is RoutePointTypes.normal:
172 1
            self.point['type'] = RoutePointTypes.air_attack
173
174 1
        self.point_class = FlightRouteAttackPoint
175
176 1
    def clean(self):
177 1
        self._finalize_current_point()
178 1
        return {self.output_key: self.data}
179
180 1
    def _finalize_current_point(self):
181 1
        if self.point:
182 1
            point_class = getattr(self, 'point_class') or FlightRoutePoint
183 1
            self.data.append(point_class(**self.point))
184 1
            self.point = None
185
            self.point_class = None
186