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

            
3
use crate::{
4
    commands::{Command, CommandRequest, CommandResponse, RequestParserError, ResponseParserError},
5
    filter::Filter,
6
    request_tokenizer::RequestTokenizer,
7
    response_tokenizer::ResponseAttributes,
8
    types::{DbSongInfo, Priority, SongId, SongPosition, Sort, WindowRange},
9
};
10

            
11
pub struct PlaylistSearch;
12

            
13
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14
pub struct PlaylistSearchRequest {
15
    filter: Filter,
16
    sort: Option<Sort>,
17
    window: Option<WindowRange>,
18
}
19

            
20
impl PlaylistSearchRequest {
21
    pub fn new(filter: Filter, sort: Option<Sort>, window: Option<WindowRange>) -> Self {
22
        Self {
23
            filter,
24
            sort,
25
            window,
26
        }
27
    }
28
}
29

            
30
impl CommandRequest for PlaylistSearchRequest {
31
    const COMMAND: &'static str = "playlistsearch";
32
    const MIN_ARGS: u32 = 1;
33
    const MAX_ARGS: Option<u32> = Some(3);
34

            
35
    fn into_request_enum(self) -> crate::Request {
36
        crate::Request::PlaylistSearch(self.filter, self.sort, self.window)
37
    }
38

            
39
    fn from_request_enum(request: crate::Request) -> Option<Self> {
40
        match request {
41
            crate::Request::PlaylistSearch(filter, sort, window) => Some(PlaylistSearchRequest {
42
                filter,
43
                sort,
44
                window,
45
            }),
46
            _ => None,
47
        }
48
    }
49

            
50
    fn serialize(&self) -> String {
51
        let mut cmd = format!("{} {}", Self::COMMAND, self.filter);
52
        if let Some(sort) = &self.sort {
53
            cmd.push_str(&format!(" sort {}", sort));
54
        }
55
        if let Some(window) = &self.window {
56
            cmd.push_str(&format!(" window {}", window));
57
        }
58
        cmd.push('\n');
59
        cmd
60
    }
61

            
62
    fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
63
        let filter = match parts.next() {
64
            Some(f) => {
65
                Filter::parse(f).map_err(|_| RequestParserError::SyntaxError(1, f.to_owned()))?
66
            }
67
            None => return Err(Self::missing_arguments_error(0)),
68
        };
69

            
70
        let mut argument_index_counter = 0;
71
        let mut sort_or_window = parts.next();
72
        let mut sort = None;
73
        if let Some("sort") = sort_or_window {
74
            argument_index_counter += 1;
75
            let s = parts
76
                .next()
77
                .ok_or(RequestParserError::MissingKeywordValue {
78
                    keyword: "sort",
79
                    argument_index: argument_index_counter,
80
                })?;
81
            sort = Some(
82
                s.parse()
83
                    .map_err(|_| RequestParserError::SubtypeParserError {
84
                        argument_index: argument_index_counter,
85
                        expected_type: "Sort",
86
                        raw_input: s.to_string(),
87
                    })?,
88
            );
89
            sort_or_window = parts.next();
90
        }
91

            
92
        let mut window = None;
93
        if let Some("window") = sort_or_window {
94
            argument_index_counter += 1;
95
            let w = parts
96
                .next()
97
                .ok_or(RequestParserError::MissingKeywordValue {
98
                    keyword: "window",
99
                    argument_index: argument_index_counter,
100
                })?;
101
            window = Some(
102
                w.parse()
103
                    .map_err(|_| RequestParserError::SubtypeParserError {
104
                        argument_index: argument_index_counter,
105
                        expected_type: "WindowRange",
106
                        raw_input: w.to_string(),
107
                    })?,
108
            );
109
        }
110

            
111
        Self::throw_if_too_many_arguments(parts)?;
112

            
113
        Ok(PlaylistSearchRequest {
114
            filter,
115
            sort,
116
            window,
117
        })
118
    }
119
}
120

            
121
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
122
pub struct PlaylistSearchResponse(Vec<PlaylistSearchResponseEntry>);
123

            
124
impl PlaylistSearchResponse {
125
    pub fn new(items: Vec<PlaylistSearchResponseEntry>) -> Self {
126
        PlaylistSearchResponse(items)
127
    }
128
}
129

            
130
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
131
pub struct PlaylistSearchResponseEntry {
132
    pub position: SongPosition,
133
    pub id: SongId,
134
    pub priority: Option<Priority>,
135
    pub song_info: DbSongInfo,
136
}
137

            
138
impl PlaylistSearchResponseEntry {
139
    pub fn new(
140
        position: SongPosition,
141
        id: SongId,
142
        priority: Option<Priority>,
143
        song_info: DbSongInfo,
144
    ) -> Self {
145
        Self {
146
            position,
147
            id,
148
            priority,
149
            song_info,
150
        }
151
    }
152
}
153

            
154
impl CommandResponse for PlaylistSearchResponse {
155
    fn from_response_enum(_response: crate::Response) -> Option<Self> {
156
        todo!()
157
    }
158

            
159
    fn into_response_enum(self) -> crate::Response {
160
        todo!()
161
    }
162

            
163
    fn parse(_parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
164
        unimplemented!()
165
    }
166
}
167

            
168
impl Command for PlaylistSearch {
169
    type Request = PlaylistSearchRequest;
170
    type Response = PlaylistSearchResponse;
171
}