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
//! An error that occurs in working with timelogs
use thiserror::Error;

use crate::date;

/// Errors encountered accessing files and directories.
#[derive(Error, Debug, PartialEq)]
pub enum PathError {
    /// Error accessing a file when reading. File is first string, error message is second.
    #[error("Error accessing file '{0}': {1}")]
    FileAccess(String, String),

    /// Error writing to a file. File is first string, error message is second.
    #[error("Error writing to file '{0}': {1}")]
    FileWrite(String, String),

    /// Required filename not supplied.
    #[error("Required filename not supplied")]
    FilenameMissing,

    /// Attempt to access a file in directory that is not available. Directory is first string,
    /// error message is second.
    #[error("Missing directory '{0}': {1}")]
    InvalidPath(String, String),

    /// Invalid path for the logfiles.
    #[error("Logfiles path contains invalid characters")]
    InvalidTimelogPath,

    /// Invalid path for the logfiles.
    #[error("Config path contains invalid characters")]
    InvalidConfigPath,

    /// The filename references an existing file.
    #[error("Cannot overwrite, '{0}' already exists")]
    AlreadyExists(String),

    /// The filename references an existing file. File is first string, error message is second.
    #[error("Cannot rename '{0}': {1}")]
    RenameFailure(String, String),

    /// Cannot create path. Path is first string, error message is second.
    #[error("Cannot create path '{0}': {1}")]
    CantCreatePath(String, String),

    /// Cannot read timelog
    #[error("Cannot read timelog")]
    CantReadTimelog,

    /// Cannot write to report file
    #[error("Cannot write report file")]
    CantWriteReport,
}

/// Enumeration of errors that can happen processing timelogs
#[derive(Error, Debug, PartialEq)]
pub enum Error {
    /// Not a validly formatted entry line.
    #[error(transparent)]
    InvalidEntryLine {
        #[from]
        source: crate::entry::EntryError,
    },

    /// Entry line is missing the required stamp.
    #[error("Missing required stamp.")]
    MissingDate,

    /// Invalid starting date in a date pair.
    #[error("Invalid starting date.")]
    StartDateFormat,

    /// Invalid ending date in a date pair.
    #[error("Invalid ending date.")]
    EndDateFormat,

    /// Start date after end date.
    #[error("Start date after end date.")]
    WrongDateOrder,

    /// Unable to pop stack item.
    #[error("Unable to pop stack item")]
    StackPop,

    /// Invalid drop argument
    #[error("Invalid drop argument '{0}'")]
    InvalidDrop(String),

    /// Invalid drop argument
    #[error("Invalid pos integer argument '{0}'")]
    InvalidInt(String),

    /// Project descriptors invalid
    #[error("Bad project filters")]
    BadProjectFilter,

    /// Not a valid timelog command
    #[error("'{0}' is not a valid command")]
    InvalidCommand(String),

    /// Deprecated command
    #[error("Deprecated! Use '{0}' instead.")]
    DeprecatedCommand(&'static str),

    /// Failed to execute editor on logfile. File is first string, error message is second.
    #[error("Editor '{0}' failed to execute: {1}")]
    EditorFailed(String, String),

    /// Unexpected argument
    #[error("Argument '{0}' is unexpected")]
    UnexpectedArgument(String),

    /// Errors in path/file handling
    #[error(transparent)]
    DateError {
        #[from]
        source: date::Error,
    },

    /// Errors in path/file handling
    #[error(transparent)]
    PathError {
        #[from]
        source: PathError,
    },
}

impl From<xml::writer::Error> for Error {
    /// Conversion from an [`xml::writer::Error`] to a timelog [`enum@Error`].
    fn from(_e: xml::writer::Error) -> Error { PathError::CantWriteReport.into() }
}