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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
use std::{fmt::Debug, sync::Arc};

use oxinat_derive::uri_builder_alias;

use crate::{UriBuilder, Version};

use super::{
    projects::{ProjectDataUriBuilder, ProjectUriLegacyBuilder},
    resources::ResourcesUriBuilder,
    shared::SharedProjectUriBuilder,
    subjects::{SubjectDataUriBuilder, SubjectUriLegacyBuilder}
};

uri_builder_alias!(ExperimentDataUriBuilder);
ImplExperimentDataUriBuilder! {
    (String),
}
ImplExperimentDataUriBuilder! {
    (ExperimentUriLegacyBuilder<Parent>, Parent),
}

impl<Parent> ExperimentDataUriBuilder for ProjectUriLegacyBuilder<Parent>
where
    Parent: ExperimentDataUriBuilder + ProjectDataUriBuilder,
{}

impl<Parent> ExperimentDataUriBuilder for SubjectUriLegacyBuilder<Parent>
where
    Parent: ExperimentDataUriBuilder + SubjectDataUriBuilder,
{}

/// Represents the URI endpoints available to
/// manage XNAT experiment sessions.
#[derive(Clone, Debug, Default, UriBuilder)]
#[match_path(path = "{parent}/experiments")]
#[match_path(path = "{parent}/experiments/{experiment}")]
pub struct ExperimentUriLegacyBuilder<Parent>
where
    Parent: ExperimentDataUriBuilder,
{
    #[param]
    experiment: Option<String>,
    #[parent]
    parent: Option<Arc<Parent>>
}

macro_rules! parent_has_experiment {
    () => {
        |this: &Self| this.experiment.is_some()
    };
}

/// Represents the URI endpoints available to
/// manage XNAT experiment scans.
#[derive(Clone, Debug, Default, UriBuilder)]
#[match_path(path = "{parent}/scans", requires = "parent_has_experiment!()")]
#[match_path(path = "{parent}/scans/{scan}", requires = "parent_has_experiment!()"  )]
pub struct ExperimentScanUriBuilder<'a, Parent>
where
    Parent: ExperimentDataUriBuilder,
{
    experiment: Option<String>,

    #[param]
    scan: Option<u64>,
    #[parent]
    parent: Option<&'a Parent>
}

#[derive(Clone, Debug, Default, UriBuilder)]
#[match_path(path = "{parent}/assessors", requires = "parent_has_experiment!()")]
#[match_path(path = "{parent}/assessors/{assessor}", requires = "parent_has_experiment!()")]
pub struct AssessorUriBuilder<'a, Parent>
where
    Parent: ExperimentDataUriBuilder,
{
    experiment: Option<String>,

    #[param]
    assessor: Option<String>,
    #[parent]
    parent: Option<&'a Parent>
}

impl<Parent> ExperimentUriLegacyBuilder<Parent>
where
    Parent: ExperimentDataUriBuilder + Default,
{
    /// Continue the builder into a
    /// `AssessorUriBuilder`.
    pub fn assessors(&self) -> AssessorUriBuilder<'_, Self> {
        let mut b = AssessorUriBuilder::from_parent(self);
        b.experiment.clone_from(&self.experiment);
        b
    }

    /// Continue the builder into a
    /// `ResourceUriBuilder`.
    pub fn resources(&self) -> ResourcesUriBuilder<'_, Self> {
        ResourcesUriBuilder::from_parent(&Arc::new(self))
    }

    /// Continue the builder into a
    /// `ExperimentScanUriBuilder`.
    pub fn scans(&self) -> ExperimentScanUriBuilder<'_, Self> {
        let mut b = ExperimentScanUriBuilder::from_parent(self);
        b.experiment.clone_from(&self.experiment);
        b
    }

    /// Continue the builder into a
    /// `SharedProjectUriBuilder`.
    pub fn shared(&self) -> SharedProjectUriBuilder<'_, Self> {
        SharedProjectUriBuilder::from_parent(&Arc::new(self))
    }

    /// Produce the quarantine status URI path.
    pub fn quarantine_status(&self) -> crate::BuildResult {
        self.build_join("status")
    }
}

impl ExperimentUriLegacyBuilder<String> {
    /// Reconstrucct this builder to allow search
    /// by project.
    pub fn by_project(&self, project: &str) -> ExperimentUriLegacyBuilder<ProjectUriLegacyBuilder<String>> {
        let parent = self.parent.as_ref().unwrap().clone();
        let b = ProjectUriLegacyBuilder::from_parent(parent)
            .with_id(project)
            .experiments();
        match self.experiment.as_ref() {
            Some(exp) => b.with_experiment(exp),
            _ => b
        }
    }

    /// Reconstruct this builder to allow search
    /// by subject.
    pub fn by_subject(&self, subject: &str) -> ExperimentUriLegacyBuilder<SubjectUriLegacyBuilder<String>> {
        let parent = self.parent.as_ref().unwrap().clone();
        let b = SubjectUriLegacyBuilder::from_parent(parent)
            .with_subject(subject)
            .experiments();
        match self.experiment.as_ref() {
            Some(exp) => b.with_experiment(exp),
            _ => b
        }
    }
}

/// Represents the URI endpoints available for
/// XNAT experiment management.
pub trait ExperimentUri: Version {
    /// Represents the URI endpoints available for
    /// XNAT experiment management.
    #[inline]
    fn experiment_data(&self) -> ExperimentUriLegacyBuilder<String> {
        ExperimentUriLegacyBuilder::from_parent(self.data_uri().into())
    }
}

/// Represents the URI paths to access archive
/// paths for session data.
pub trait ExperimentUriArchive: Version {
    /// Represents the URI paths to access archive
    /// paths for session data.
    #[inline]
    fn experiment_archive(&self) -> ExperimentUriLegacyBuilder<String> {
        ExperimentUriLegacyBuilder::from_parent("archive".to_string().into())
    }
}