root/src/pmpdc_config.rs

use gtk::glib;
use serde::{Deserialize, Serialize};
use std::fs;

#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct Server {
    pub address: String,
    pub password: String,
    pub name: Option<String>,
}

impl Server {
    pub fn get_name(&self) -> &String {
        self.name.as_ref().unwrap_or(&self.address)
    }
    pub fn empty() -> Server {
        Server {
            address: "".to_string(),
            password: "".to_string(),
            name: None,
        }
    }
}

#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct ConfigFile {
    active: usize,
    servers: Vec<Server>,
}

impl ConfigFile {
    pub fn new() -> ConfigFile {
        ConfigFile {
            active: 0,
            servers: vec![],
        }
    }
    pub fn add_server(&mut self, server: Server) {
        self.servers.push(server)
    }
    pub fn remove_server(&mut self, server_index: usize) {
        if self.servers.len() > server_index {
            self.servers.remove(server_index);
        }
    }

    pub fn update_server(&mut self, index: usize, server: Server) {
        self.servers.get_mut(index).map(|s| *s = server);
    }

    pub fn active_server(&self) -> Option<Server> {
        self.servers.get(self.active).map(|s| s.clone())
    }
    pub fn move_active(&mut self, delta: i16) {
        if delta < 0 {
            let result = self.active.checked_sub(delta.wrapping_abs() as usize);
            match result {
                None => self.active = self.servers.len() - 1,
                Some(i) => self.active = i,
            }
        } else {
            let result = self.active.checked_add(delta as usize);
            match result {
                None => self.active = 0,
                Some(i) => {
                    if i >= self.servers.len() {
                        self.active = 0;
                    } else {
                        self.active = i;
                    }
                }
            }
        }
    }
    pub fn server_count(&self) -> usize {
        self.servers.len()
    }

    pub fn get_servers(&self) -> &Vec<Server> {
        &self.servers
    }

    pub fn write(&self) -> Option<()> {
        let mut path = glib::user_config_dir();
        path.push("pmpdc");
        std::fs::create_dir_all(&path).ok();
        path.push("config.toml");
        let config_str = toml::to_string(&self).ok()?;
        fs::write(path, config_str).ok()?;
        Some(())
    }
}

pub fn read_config() -> Option<ConfigFile> {
    match read_v2() {
        Some(v2) => Some(v2),
        None => read_v1(),
    }
}

fn read_v2() -> Option<ConfigFile> {
    let mut path = glib::user_config_dir();
    path.push("pmpdc/config.toml");
    let config: ConfigFile = toml::from_str(&fs::read_to_string(path).ok()?).ok()?;
    Some(config)
}

#[derive(Deserialize)]
struct ConfigFileV1 {
    server: String,
    password: String,
}

fn read_v1() -> Option<ConfigFile> {
    let mut path = glib::user_config_dir();
    path.push("pmpdc/settings.toml");
    let config_v1: ConfigFileV1 = toml::from_str(&fs::read_to_string(path.clone()).ok()?).ok()?;
    let mut config = ConfigFile::new();
    config.add_server(Server {
        address: config_v1.server,
        password: config_v1.password,
        name: None,
    });
    // delete old
    config.write();
    fs::remove_file(path).ok()?;
    Some(config)
}