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
use anyhow::{anyhow, Context, Result};
use std::{
    env,
    fs::File,
    io::{Read, Write},
};

pub mod api_usage;
pub mod cmd_line;
pub mod user_setup;

/// Constants for the information of the program.
pub mod program_info {
    /// The name of the program.
    pub const PROGRAM_NAME: &str = "weather-cli";
    /// The description of the program.
    pub const PROGRAM_DESCRIPTION: &str = "Weather for command-line fans!";
    /// The authors of the program.
    pub const PROGRAM_AUTHORS: &str = "decaplanet";
}

/// Constants related to the API and settings.
mod constants {
    /// The name of the json file for the API key.
    pub const API_JSON_NAME: &str = "api";

    /// The name of the json file for settings.
    pub const SETTINGS_JSON_NAME: &str = "settings";

    /// The URL template for the OpenWeatherMap API.
    ///
    /// This template can be used to retrieve weather data by replacing the following placeholders:
    ///
    /// - `{lat_value}`: Latitude value of the location.
    /// - `{lon_value}`: Longitude value of the location.
    /// - `{api_key}`: Your OpenWeatherMap API key.
    /// - `{unit}`: The desired measurement unit. (ex. `metric` or `imperial`)
    ///
    /// ## Example Usage
    ///
    /// ```
    /// pub const API_URL: &str = "https://api.openweathermap.org/data/2.5/weather?lat={lat_value}&lon={lon_value}&appid={api_key}&units={unit}";
    ///
    /// let url = API_URL
    ///     .replace("{lat_value}", "37.3361663")
    ///     .replace("{lon_value}", "-121.890591")
    ///     .replace("{api_key}", "EXAMPLE_KEY")
    ///     .replace("{unit}", "imperial");
    /// ```
    pub const API_URL: &str = "https://api.openweathermap.org/data/2.5/weather?lat={lat_value}&lon={lon_value}&appid={api_key}&units={unit}";
}

/// Returns the running executable directory.
pub fn get_executable_directory() -> Result<String> {
    let executable_path =
        env::current_exe().context("Couldn't get the executable file directory!")?;
    let executable_directory = executable_path
        .parent()
        .context("Couldn't get the executable directory!")?;

    if let Some(dir_str) = executable_directory.to_str() {
        return Ok(dir_str.to_string());
    }

    Err(anyhow!("Unable to get the executable directory."))
}

/// Formats the given file name with the executable directory.
pub fn get_json_file(name: &str) -> Result<File> {
    let executable_dir = get_executable_directory()?;

    let file = match File::open(format!("{}/weather-cli-{}.json", executable_dir, name)) {
        Ok(f) => f,
        Err(_) => {
            let mut new_file =
                File::create(format!("{}/weather-cli-{}.json", executable_dir, name))
                    .context("Couldn't create a json file.")?;
            new_file
                .write_all("{}".as_bytes())
                .context("Couldn't create a json file.")?;

            File::open(format!("{}/weather-cli-{}.json", executable_dir, name))
                .context("Couldn't get the json file.")?
        }
    };

    Ok(file)
}

/// Reads the given json file and returns the string.
pub fn read_json_file(json_name: &str) -> Result<String> {
    let mut file = get_json_file(json_name)?;
    let mut json_string = String::new();
    file.read_to_string(&mut json_string)?;

    Ok(json_string)
}

/// Returns the emoji for the given icon id.
pub fn get_emoji(icon_id: &str) -> String {
    let return_value = match icon_id {
        "01d" => "☀️",
        "02d" => "⛅️",
        "03d" => "☁️",
        "04d" => "☁️",
        "09d" => "🌧️",
        "10d" => "🌦️",
        "11d" => "⛈️",
        "13d" => "❄️",
        "50d" => "🌨️",
        "01n" => "🌑",
        "02n" => "🌑☁️",
        "03n" => "☁️",
        "04n" => "☁️☁️",
        "09n" => "🌧️",
        "10n" => "☔️",
        "11n" => "⛈️",
        "13n" => "❄️",
        _ => "",
    };

    if !return_value.is_empty() {
        format!("{} ", return_value)
    } else {
        return_value.to_string()
    }
}

/// This module is only used for testing.
#[cfg(test)]
mod tests;