1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
use model::{Movie,SearchMovie,SearchResult,FindResult};
use reqwest;

const BASE_URL: &'static str = "https://api.themoviedb.org/3";
// const BASE_IMG_URL: &'static str = "https://image.tmdb.org/t/p/w500";
// "https://image.tmdb.org/t/p/w700_and_h392_bestv2/gq4Z1pfOWHn3FKFNutlDCySps9C.jpg"

pub trait Executable<T> {
    fn execute(&self) -> Result<T, reqwest::Error>;
}

pub trait Search<'a> {
    fn title(&mut self, title: &'a str) -> &mut SearchData<'a>;
    fn year(&mut self, year: u64) -> &mut SearchData<'a>;
}

#[derive(Debug)]
pub struct SearchData<'a> {
    pub tmdb: TMDb,
    pub title: Option<&'a str>,
    pub year: Option<u64>,
}

impl<'a> Search<'a> for SearchData<'a> {
    
    fn title(&mut self, title: &'a str) -> &mut SearchData<'a> {
        self.title = Some(title);
        return self;
    }

    fn year(&mut self, year: u64) -> &mut SearchData<'a> {
        self.year = Some(year);
        return self;
    }
}

impl<'a> Executable<SearchResult> for SearchData<'a> {
    
    fn execute(&self) -> Result<SearchResult, reqwest::Error> {
        let url: String = match self.year {
            None => format!("{}/search/movie?api_key={}&language={}&query={}&append_to_response=images",
                            BASE_URL, self.tmdb.api_key, self.tmdb.language, self.title.unwrap()),
            Some(year) => format!("{}/search/movie?api_key={}&language={}&query={}&year={}&append_to_response=images",
                            BASE_URL, self.tmdb.api_key, self.tmdb.language, self.title.unwrap(), year),
        };

        return reqwest::get(&url)?.json();
    }
}

pub enum Appendable {
    Videos,
    Credits,
}

pub trait Fetch {
    fn id(&mut self, id: u64) -> &mut FetchData;
    fn append_videos(&mut self) -> &mut FetchData;
    fn append_credits(&mut self) -> &mut FetchData;
}

pub struct FetchData {
    pub tmdb: TMDb,
    pub id: Option<u64>,
    pub append_to_response: Vec<Appendable>,
}

impl Fetch for FetchData {
    fn id(&mut self, id: u64) -> &mut FetchData {
        self.id = Some(id);
        return self;
    }

    fn append_videos(&mut self) -> &mut FetchData {
        self.append_to_response.push(Appendable::Videos);
        return self;
    }

    fn append_credits(&mut self) -> &mut FetchData {
        self.append_to_response.push(Appendable::Credits);
        return self;
    }
}

impl Executable<Movie> for FetchData {
    fn execute(&self) -> Result<Movie, reqwest::Error> {
        let mut url: String = format!("{}/movie/{}?api_key={}&language={}",
                                  BASE_URL, self.id.unwrap(), self.tmdb.api_key, self.tmdb.language);


        if self.append_to_response.len() != 0 {
            url.push_str("&append_to_response=");
            for appendable in &self.append_to_response {
                match appendable {
                    Appendable::Videos => url.push_str("videos,"),
                    Appendable::Credits => url.push_str("credits,"),
                }
            }
        }

        return reqwest::get(&url)?.json();
    }
}

pub trait Find<'a> {
    fn imdb_id(&mut self, imdb_id: &'a str) -> &mut FindData<'a>;
}

pub struct FindData<'a> {
    pub tmdb: TMDb,
    pub imdb_id: Option<&'a str>,
}

impl<'a> Find<'a> for FindData<'a> {

    fn imdb_id(&mut self, imdb_id: &'a str) -> &mut FindData<'a> {
        self.imdb_id = Some(imdb_id);
        return self;
    }
}

impl<'a> Executable<FindResult> for FindData<'a> {
    fn execute(&self) -> Result<FindResult, reqwest::Error> {
        let url = format!("{}/find/{}?api_key={}&external_source=imdb_id&language={}&append_to_response=images", BASE_URL, self.imdb_id.unwrap(), self.tmdb.api_key, self.tmdb.language);
        return reqwest::get(&url)?.json();
    }
}

pub trait TMDbApi {
    fn search(&self) -> SearchData;
    fn fetch(&self) -> FetchData;
    fn find(&self) -> FindData;
}

#[derive(Debug,Clone)]
pub struct TMDb { 
    pub api_key: &'static str,
    pub language: &'static str,
}

impl TMDbApi for TMDb {

    fn search(&self) -> SearchData {
        let tmdb = self.clone();
        return SearchData {tmdb: tmdb, title: None, year: None};
    }

    fn fetch(&self) -> FetchData {
        let tmdb = self.clone();
        return FetchData {tmdb: tmdb, id: None, append_to_response: vec![]};
    }

    fn find(&self) -> FindData {
        let tmdb = self.clone();
        return FindData {tmdb: tmdb, imdb_id: None};
    }
    
}

pub trait Fetchable {
    fn fetch(&self, tmdb: &TMDb) -> Result<Movie, reqwest::Error>;
}

impl Fetchable for SearchMovie {
    fn fetch(&self, tmdb: &TMDb) -> Result<Movie, reqwest::Error> {
        return tmdb.fetch()
            .id(self.id)
            .execute();
    }
}