1use std::collections::HashMap ;
2use std::str::SplitAsciiWhitespace;
3use Common::fixture;
4use Common::fixture::{Fixture, FixtureType};
5use Common::fixture::ChannelError::{ChannelOutOfRange, ChannelAlreadyInUse, UniverseOutOfRange};
6use Common::fixture::FixtureError::{InvalidPropertyType, MultipleColorOutputTypes, MissingProperty, FixtureTypeNameAlreadyInUse, ChannelError, InvalidFixtureType, FixtureNameAlreadyInUse, InvalidFixture};
7
8
9pub(crate) fn parse_command(line: String) {
12
13 let mut line_iter = line.split_ascii_whitespace();
14 let arg_count = line_iter.clone().count().saturating_sub(1);
16 match line_iter.next() {
17
18 Some("help") => {
19 const HELP_TEXT: &str = include_str!("../help.txt");
20 println!("{}", HELP_TEXT);
21 }
22
23 Some("new") if arg_count % 2 == 1 && arg_count > 1 => {
24 new_fixture_type(line_iter);
25 }
26
27 Some("new") => {
28 println!("Error: \"new\"-Command needs a name for the new Fixture-Type, and then a list of properties with \
29 their channels.");
30 }
31
32 Some("add") if arg_count == 4 => {
33 new_fixture(line_iter);
34 }
35
36 Some("add") => {
37 println!("Error: \"add\" needs a name, a fixture-type, a start-channel and a universe as arguments")
38 }
39
40 Some("set") if arg_count == 3 => {
41 set_value(line_iter);
42 }
43
44 Some("set") => {
45 println!("Error: \"set\" needs a fixture, a property, and a value as arguments")
46 }
47
48 Some("type") if arg_count == 1 => {
49 get_type(line_iter);
50 }
51
52 Some("type") => {
53 print!("Error: \"type\" needs a fixture as argument");
54 }
55
56 Some("create_debug") => {
57 let args = "rgb red 0 green 1 blue 2".split_ascii_whitespace();
58 new_fixture_type(args);
59 for i in 0..50 {
60 let name = i.to_string();
61 let start_channel = (i * 3).to_string();
62 let args = format!("{} rgb 0 {}", name.clone(), start_channel.clone());
63 let args = args.split_ascii_whitespace();
64 new_fixture(args);
65 }
66 }
67
68 Some("set_all") if arg_count == 2 => {
69 let property_type = line_iter.next().unwrap().to_string();
70 let value = line_iter.next().unwrap().to_string();
71
72 for i in 0..50 {
73 let name = i.to_string();
74 let args = format!("{} {} {}", name, property_type.clone(), value.clone());
75 let args = args.split_ascii_whitespace();
76 set_value(args);
77
78 }
79 }
80
81 Some("break") => {
82 let _dmx_config = fixture::DMX_CONFIGURATION.read().unwrap();
83 let _universes = fixture::calculate_dmx_values();
84 println!("Add a breakpoint at this point in the code to check the datastructures");
85 }
86
87 _ => {
88 println!("Unknown command. Please enter help, to get a list of commands.");
89 }
90 }
91}
92
93fn new_fixture_type(mut args: SplitAsciiWhitespace) {
94 let name = args.next().unwrap().to_string();
95 let mut properties: HashMap<String, (u16, Option<u16>)> = HashMap::new();
96
97 while let Some(property) = args.next() {
101
102 let channel = args.next().unwrap();
104 if let Err(_) = channel.parse::<u16>() {
105 eprintln!("Error: \"{channel}\" is not a valid channel-number");
106 return;
107 } else {
108 let channel = channel.parse::<u16>().unwrap();
109
110 if property.ends_with("_f") {
111 let property = &property[..(property.len() - 2)];
115 if let Some((_, opt)) = properties.get_mut(property) {
116 if opt.is_none() {
117 *opt = Some(channel);
118 } else {
119 eprintln!("{property} can only have one Fine-Channel");
120 return;
121 }
122 } else {
123 eprintln!("{property} needs to define a normal Channel, before defining an fine-Channel");
124 return;
125 }
126 } else {
127 if !properties.contains_key(property) {
130 properties.insert(property.to_string(), (channel, None));
131 } else {
132 eprintln!("{property} can only have one non-fine Channel");
133 return;
134 }
135 }
136 }
137
138 }
139
140 let fixture_type = FixtureType::new(name.clone(), properties);
144 match fixture_type {
145 Err(ChannelError(ChannelAlreadyInUse(channel_type))) => {
146 eprintln!("Error: The channel {channel_type} overlaps with another channel.");
147 },
148
149 Err(ChannelError(ChannelOutOfRange)) => {
150 eprintln!("Error: A Channel is higher than the size of the Universe. This is not yet supported");
151 }
152
153 Err(FixtureTypeNameAlreadyInUse(name)) => {
154 eprintln!("Error: The Fixture type name {name} is already used.");
155 }
156
157 Err(InvalidPropertyType(property_type)) => {
158 eprintln!("Error: \"{property_type}\" is not a valid PropertyType");
159 }
160
161 Err(MultipleColorOutputTypes(error_message)) => {
162 eprintln!("{error_message}");
163 }
164
165 Err(_) => {
166 eprintln!("Error: new_fixture_type() threw an Error it shouldn't");
167 None::<Fixture>.unwrap();
168 }
171
172 Ok(()) => { println!("{} created successfully", name); }
173 }
174}
175
176fn new_fixture(mut args: SplitAsciiWhitespace) {
177 let name = args.next().unwrap().to_string();
178 let fixture_type_name = args.next().unwrap().to_string();
179 let universe = args.next().unwrap().to_string();
180 let channel = args.next().unwrap().to_string();
181
182 if let Err(_) = channel.parse::<u16>() {
186 eprintln!("Error: \"{fixture_type_name}\" is not a valid channel-number");
187 return;
188 }
189 let channel = channel.parse::<u16>().unwrap();
190
191 if let Err(_) = universe.parse::<usize>() {
192 eprintln!("Error: \"{fixture_type_name}\" is not a valid universe-number");
193 return;
194 }
195 let universe = universe.parse().unwrap();
196
197 let fixture = Fixture::new(fixture_type_name,channel,universe, name.clone());
201 match fixture {
202 Err(ChannelError(ChannelOutOfRange)) => {
203 eprintln!("Error: fixture overflowes out of this remaining universe");
204 }
205
206 Err(ChannelError(UniverseOutOfRange)) => {
207 panic!("Fatal Error: Fixture created in Universe that does not exist. Normally, the programm should \
208 automatically create an universe, but somehow, this hasn't happened");
209 }
210
211 Err(ChannelError(ChannelAlreadyInUse(overlapping_fixture))) => {
212 eprintln!("Error: At least one Channel of this fixture is overlapping with {}.\
213 Fixture has not been created.", overlapping_fixture);
214 }
215
216 Err(InvalidFixtureType(fixture_type_name)) => {
217 eprintln!("Error: There is no fixture-type named \"{fixture_type_name}\".");
218 }
219
220 Err(FixtureNameAlreadyInUse(name)) => {
221 eprintln!("Error: The Fixture name {name} is already used.");
222 }
223
224 Err(_) => {
225 eprintln!("Error: new_fixture_type() threw an Error it shouldn't");
226 None::<Fixture>.unwrap();
227 }
230
231 Ok(_) => { println!("{} created successfully", name); }
232 }
233}
234
235fn set_value(mut args: SplitAsciiWhitespace) {
236 let fixture_name = args.next().unwrap().to_string();
237 let property_name = args.next().unwrap().to_string();
238 let value = args.next().unwrap().to_string();
239
240 if let Err(_) = value.parse::<u16>() {
244 eprintln!("Error: \"{value}\" is not a valid value.");
245 return;
246 }
247 let value = value.parse::<u16>().unwrap();
248
249 let result = Fixture::set(fixture_name.clone(), &*property_name, value);
253 match result {
254 Err(InvalidPropertyType(property_type)) => {
255 eprintln!("Error: \"{property_type}\" is not a valid PropertyType");
256 }
257
258 Err(MissingProperty(_)) => {
259 eprintln!("Error: \"{fixture_name}\" has no property \"{property_name}\"")
260 }
261
262 Err(InvalidFixture(name)) => {
263 eprintln!("Error: \"{name}\" is not a valid Fixture");
264 }
265
266 Err(_) => {
267 eprintln!("Error: new_fixture_type() threw an Error it shouldn't");
268 None::<Fixture>.unwrap();
269 }
273
274 Ok(_) => { println!("Value changed successfully"); }
275 }
276}
277
278
279fn get_type(mut args: SplitAsciiWhitespace) {
280 let fixture_name = args.next().unwrap().to_string();
281
282 match Fixture::get_fixture_type_from_string(fixture_name.clone()) {
283 Ok(fixture_type) => println!("\"{fixture_name}\" is a fixture of the type \"{fixture_type}\""),
284 Err(InvalidFixture(fixture)) => eprintln!("Error: \"{fixture}\" is not a valid Fixture"),
285 Err(_) => panic!("Error: get_fixture_type_from_string() threw an Error it shouldn't"),
286 }
287}
288