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
use super::{errors, persistent, project_path, Project};

use std::{
    fs::OpenOptions,
    io::Write,
    ops::{Deref, DerefMut},
    path::PathBuf,
};

// Some RAII sugar
pub struct ProjectFrame {
    project: Project,
}

impl Deref for ProjectFrame {
    type Target = Project;

    fn deref(&self) -> &Self::Target {
        &self.project
    }
}

impl DerefMut for ProjectFrame {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.project
    }
}

impl Drop for ProjectFrame {
    fn drop(&mut self) {
        // TODO v0.2.0 -> Dirty flag, to prevent the saving of an unchanged project
        if let Err(e) = self.save() {
            eprintln!("Error while saving! {:?}", e);
        }
    }
}

impl ProjectFrame {
    pub fn load_or_create_from_name(name: &str) -> errors::CtResult<ProjectFrame> {
        let path = project_path(name)?;
        if path.exists() {
            return ProjectFrame::load(&path);
        }
        let frame = ProjectFrame {
            project: Project::create(name)?,
        };
        frame.save()?;
        Ok(frame)
    }

    fn load_persistent_and_stop() -> errors::CtResult<()> {
        if let Some(name) = persistent::has_project()? {
            let path = project_path(name.as_str())?;
            // has_project makes sure that the peoject returned exists, so we can simply unwrap
            let mut proj = ProjectFrame::load(&path)?;
            // Should also deregister from store -> project.stop() doesn't do that
            proj.stop()?;
        }
        Ok(())
    }

    pub fn load_from_name(name: &str) -> errors::CtResult<ProjectFrame> {
        let path = project_path(name)?;
        ProjectFrame::load(&path)
    }

    pub(crate) fn load(path: &PathBuf) -> errors::CtResult<ProjectFrame> {
        if path.exists() {
            assert!(path.is_file());
            // Project already exists: Try to load it and return a new frame
            let json = std::fs::read_to_string(&path)?;

            Ok(ProjectFrame {
                project: Project::from_json(json.as_str())?,
            })
        } else {
            Err(errors::CtError::Own("Project does not exist!"))
        }
    }

    fn save(&self) -> errors::CtResult<()> {
        let file = project_path(self.name())?;
        let mut file = OpenOptions::new()
            .create(true)
            .write(true)
            .truncate(true)
            .open(&file)?;
        file.write_all(self.project.json(true)?.as_bytes())?;
        Ok(())
    }

    pub fn start(&mut self) -> errors::CtResult<()> {
        ProjectFrame::load_persistent_and_stop()?;
        self.project.start();
        persistent::register(self.project.name().as_str())?;
        Ok(())
    }

    pub fn stop(&mut self) -> errors::CtResult<()> {
        // Maybe assert that this project is the running one
        persistent::deregister(Some(self.project.name().as_str()))?;
        self.project.stop();
        Ok(())
    }
}