ommui_data 0.12.3

OMMUI data structures
extern crate serde;
extern crate serde_json;

use crate::annalisa::LoadableDevice as _;
use crate::samplic::LoadableDevice as _;
use crate::{
    file_load_json, CalibrationDescription, DeviceDescription,
    LoadPathPattern, LoadableDevice, Result, Sampling,
};
use indexmap::IndexSet;
use std::path::{Path, PathBuf};

#[derive(Debug)]
pub struct Device<P: AsRef<Path>> {
    pub system_path: P,
    pub config_path: P,
    pub data_path: P,
    pub product_id: String,
}

impl<P: AsRef<Path>> Device<P> {
    pub fn samplic(&self) -> crate::samplic::filesystem::Device<P> {
        crate::samplic::filesystem::Device::new(self)
    }

    pub fn ommui(&self) -> crate::ommui::filesystem::Device<P> {
        crate::ommui::filesystem::Device::new(self)
    }

    pub fn annalisa(&self) -> crate::annalisa::filesystem::Device<P> {
        crate::annalisa::filesystem::Device::new(self)
    }

    pub fn system_dir(&self) -> PathBuf {
        self.system_path.as_ref().to_path_buf()
    }

    pub fn config_dir(&self) -> PathBuf {
        self.config_path.as_ref().to_path_buf()
    }

    pub fn data_dir(&self) -> PathBuf {
        self.data_path.as_ref().to_path_buf()
    }

    pub fn samplic_dir(&self) -> PathBuf {
        self.system_dir().join("samplic")
    }

    pub fn description_dir(&self) -> PathBuf {
        self.system_dir().join("description")
    }

    pub fn description_calibrations_dir(&self) -> PathBuf {
        self.description_dir().join("calibration")
    }

    pub fn samplings_dir(&self) -> PathBuf {
        self.description_dir().join("sampling")
    }

    pub fn sampling_dir(&self, sampling_id: &str) -> PathBuf {
        self.samplings_dir().join(sampling_id)
    }

    pub fn description_calibration_dir(
        &self,
        calibration_id: &str,
    ) -> PathBuf {
        self.description_calibrations_dir().join(calibration_id)
    }

    pub fn device_dir(&self) -> PathBuf {
        self.description_dir().join("device")
    }
}

impl<P: AsRef<Path>> LoadableDevice for Device<P> {
    fn load_calibration_description_index(
        &self,
    ) -> Result<IndexSet<String>> {
        IndexSet::load_path_pattern_from_dir(
            self.description_calibrations_dir(),
            "*",
        )
    }

    fn load_calibration_description(
        &self,
        calibration_id: &str,
    ) -> Result<CalibrationDescription> {
        use crate::ommui::LoadableDevice;
        Ok(CalibrationDescription {
            ommui: self
                .ommui()
                .load_calibration_description(calibration_id)?,
        })
    }

    fn load_sampling_index(&self) -> Result<IndexSet<String>> {
        IndexSet::load_path_pattern_from_dir(self.samplings_dir(), "*")
    }

    fn load_sampling(&self, sampling_id: &str) -> Result<Sampling> {
        Ok(Sampling {
            samplic: self.samplic().load_sampling(sampling_id)?,
            annalisa: self.annalisa().load_sampling(sampling_id)?,
        })
    }

    fn load_device_description(&self) -> Result<DeviceDescription> {
        Ok(DeviceDescription {
            samplic: self.samplic().load_device_description()?,
        })
    }

    fn load_device(&self) -> Result<crate::Device> {
        Ok(crate::Device {
            description: self.load_device_description()?,
            calibrations: self.load_calibration_descriptions()?,
            system_profiles: self.samplic().load_system_profiles()?,
            user_profiles: self.samplic().load_user_profiles()?,
            samplings: self.load_samplings()?,
            icons: self.samplic().load_icons()?,
            translations: self.samplic().load_translations()?,
        })
    }
}

pub struct DeviceBuilder {
    system_path: PathBuf,
    base_config_path: PathBuf,
    base_data_path: PathBuf,
    product_id: String,
}

const DEFAULT_COMPANY_ID: &str = "ommui";

fn default_system_path_for_company_id(company_id: &str) -> PathBuf {
    Path::new("/").join("etc").join(company_id).join("device")
}

impl DeviceBuilder {
    pub fn new(product_id: &str) -> Self {
        let dirs =
            directories::ProjectDirs::from(product_id, "OMMUI", "OMMUI")
                .expect("Could not determine project directory");
        DeviceBuilder {
            system_path: default_system_path_for_company_id(
                DEFAULT_COMPANY_ID,
            ),
            base_config_path: dirs.config_dir().to_path_buf(),
            base_data_path: dirs.data_dir().to_path_buf(),
            product_id: product_id.to_string(),
        }
    }

    pub fn system_path_for_company_id(mut self, company_id: &str) -> Self {
        self.system_path = default_system_path_for_company_id(company_id);
        self
    }

    pub fn base_config_path<P: AsRef<Path>>(mut self, p: P) -> Self {
        self.base_config_path = p.as_ref().to_path_buf();
        self
    }

    pub fn base_data_path<P: AsRef<Path>>(mut self, p: P) -> Self {
        self.base_data_path = p.as_ref().to_path_buf();
        self
    }

    pub fn build(self) -> Result<Device<PathBuf>> {
        let description =
            file_load_json::<crate::samplic::DeviceDescription, _>(
                self.system_path
                    .join("description")
                    .join("device")
                    .join("samplic")
                    .join("device.json"),
            )?;
        let device_id = description.uuid.to_hyphenated().to_string();
        let config_path = self.base_config_path.join(&device_id);
        let data_path = self.base_data_path.join(&device_id);

        Ok(Device {
            system_path: self.system_path,
            config_path,
            data_path,
            product_id: self.product_id,
        })
    }
}