1
use serde::{Deserialize, Serialize};
2

            
3
use crate::{
4
    commands::{CommandRequest, RequestParserError, empty_command_response},
5
    filter::Filter,
6
    request_tokenizer::RequestTokenizer,
7
    types::{SongPosition, Sort, WindowRange},
8
};
9

            
10
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11
pub struct FindAddRequest {
12
    filter: Filter,
13
    sort: Option<Sort>,
14
    window: Option<WindowRange>,
15
    position: Option<SongPosition>,
16
}
17

            
18
impl FindAddRequest {
19
    pub fn new(
20
        filter: Filter,
21
        sort: Option<Sort>,
22
        window: Option<WindowRange>,
23
        position: Option<SongPosition>,
24
    ) -> Self {
25
        Self {
26
            filter,
27
            sort,
28
            window,
29
            position,
30
        }
31
    }
32
}
33

            
34
impl CommandRequest for FindAddRequest {
35
    type Response = FindAddResponse;
36

            
37
    const COMMAND: &'static str = "findadd";
38
    const MIN_ARGS: u32 = 1;
39
    const MAX_ARGS: Option<u32> = Some(4);
40

            
41
    fn serialize(&self) -> String {
42
        let mut cmd = format!("{} {}", Self::COMMAND, self.filter);
43
        if let Some(sort) = &self.sort {
44
            cmd.push_str(&format!(" sort {}", sort));
45
        }
46
        if let Some(window) = &self.window {
47
            cmd.push_str(&format!(" window {}", window));
48
        }
49
        if let Some(position) = &self.position {
50
            cmd.push_str(&format!(" position {}", position));
51
        }
52
        cmd.push('\n');
53
        cmd
54
    }
55

            
56
    fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
57
        let filter = match parts.next() {
58
            Some(f) => {
59
                Filter::parse(f).map_err(|_| RequestParserError::SyntaxError(1, f.to_owned()))?
60
            }
61
            None => return Err(Self::missing_arguments_error(0)),
62
        };
63

            
64
        let mut argument_index_counter = 0;
65
        let mut sort_or_window_or_position = parts.next();
66
        let mut sort = None;
67
        if let Some("sort") = sort_or_window_or_position {
68
            argument_index_counter += 1;
69
            let s = parts
70
                .next()
71
                .ok_or(RequestParserError::MissingKeywordValue {
72
                    keyword: "sort",
73
                    argument_index: argument_index_counter,
74
                })?;
75
            sort = Some(
76
                s.parse()
77
                    .map_err(|_| RequestParserError::SubtypeParserError {
78
                        argument_index: argument_index_counter,
79
                        expected_type: "Sort",
80
                        raw_input: s.to_string(),
81
                    })?,
82
            );
83
            sort_or_window_or_position = parts.next();
84
        }
85

            
86
        let mut window = None;
87
        if let Some("window") = sort_or_window_or_position {
88
            argument_index_counter += 1;
89
            let w = parts
90
                .next()
91
                .ok_or(RequestParserError::MissingKeywordValue {
92
                    keyword: "window",
93
                    argument_index: argument_index_counter,
94
                })?;
95
            window = Some(
96
                w.parse()
97
                    .map_err(|_| RequestParserError::SubtypeParserError {
98
                        argument_index: argument_index_counter,
99
                        expected_type: "WindowRange",
100
                        raw_input: w.to_string(),
101
                    })?,
102
            );
103
            sort_or_window_or_position = parts.next();
104
        }
105

            
106
        let mut position = None;
107
        if let Some("position") = sort_or_window_or_position {
108
            argument_index_counter += 1;
109
            let p = parts
110
                .next()
111
                .ok_or(RequestParserError::MissingKeywordValue {
112
                    keyword: "position",
113
                    argument_index: argument_index_counter,
114
                })?;
115
            position = Some(
116
                p.parse()
117
                    .map_err(|_| RequestParserError::SubtypeParserError {
118
                        argument_index: argument_index_counter,
119
                        expected_type: "SongPosition",
120
                        raw_input: p.to_string(),
121
                    })?,
122
            );
123
        }
124

            
125
        Self::throw_if_too_many_arguments(parts)?;
126

            
127
        Ok(FindAddRequest {
128
            filter,
129
            sort,
130
            window,
131
            position,
132
        })
133
    }
134
}
135

            
136
empty_command_response!(FindAdd);