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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
//! This module helps move and set the cursor position.

use std::fmt::{Display, Formatter};
use crate::control::ControlSequence;


/// # CPR - Active position report
///
/// If the DEVICE COMPONENT SELECT MODE (DCSM) is set to PRESENTATION, CPR is used to
/// report the active presentation position of the sending device as residing in the presentation component at
/// the `l`-th line position according to the line progression and at the `c`-th character.
///
/// If the DEVICE COMPONENT SELECT MODE (DCSM) is set to DATA, CPR is used to report the
/// active data position of the sending device as residing in the data component at the `l`-th line position
/// according to the line progression and at the `c`-th character position according to the character
/// progression.
///
/// CPR may be solicited by a DEVICE STATUS REPORT (DSR) or be sent unsolicited.
pub fn position_report(l: usize, c: usize) -> ControlSequence {
    ControlSequence::new(&[&l.to_string(), &c.to_string()], "H")
}

/// # CUP - Cursor position
///
/// CUP causes the active presentation position to be moved in the presentation component to the n-th line
/// position according to the line progression and to the m-th character position according to the character
/// path, where n equals the value of `l` and m equals the value of `c`.
pub fn set_position(l: usize, c: usize) -> ControlSequence {
    ControlSequence::new(&[&l.to_string(), &c.to_string()], "H")
}

/// A struct representing the cursor directions.
///
/// To use with the function [move_cursor].
pub enum Direction {
    /// # CUU - Cursor up
    ///
    /// CUU causes the active presentation position to be moved upwards in the presentation component by n
    /// line positions if the character path is horizontal, or by n character positions if the character path is vertical.
    Up,

    /// # CUD - Cursor down
    ///
    /// CUD causes the active presentation position to be moved downwards in the presentation component by n
    /// line positions if the character path is horizontal, or by n character positions if the character path is  vertical.
    Down,

    /// # CUF - Cursor forward
    ///
    /// CUF causes the active presentation position to be moved rightwards in the presentation component by n
    /// character positions if the character path is horizontal, or by n line positions if the character path is  vertical.
    Forward,

    /// # CUB - Cursor backward
    ///
    /// CUB causes the active presentation position to be moved leftwards in the presentation component by n
    /// character positions if the character path is horizontal, or by n line positions if the character path is vertical.
    Backward,

    /// # CNL - Cursor next line
    ///
    /// CNL causes the active presentation position to be moved to the first character position of the n-th following line in the presentation component.
    NextLine,

    /// # CPL - Cursor preceding line
    ///
    /// CPL causes the active presentation position to be moved to the first character position of the n-th preceding line in the presentation component.
    PreviousLine,
}

impl Display for Direction {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", match self {
            Direction::Up => "A",
            Direction::Down => "B",
            Direction::Forward => "C",
            Direction::Backward => "D",
            Direction::NextLine => "E",
            Direction::PreviousLine => "F",
        })
    }
}

/// # Move cursor
/// Moves the cursor in a direction relative to its current position.
///
/// This function can perform the following cursor control functions :
///
/// - CUU - Cursor up with [Direction::Up],
/// - CUD - Cursor down with [Direction::Down],
/// - CUF - Cursor forward with [Direction::Forward],
/// - CUB - Cursor backward with [Direction::Backward],
/// - CNL - Cursor next line with [Direction::NextLine],
/// - CPL - Cursor preceding line with [Direction::PreviousLine],
pub fn move_cursor(direction: Direction, n: usize) -> ControlSequence {
    ControlSequence::new(&[&n.to_string()], &direction.to_string())
}


/// # HPA - Character position absolute
///
/// HPA causes the active data position to be moved to character position `n` in the active line (the line in the
/// data component that contains the active data position).
pub fn character_absolute(n: usize) -> ControlSequence {
    ControlSequence::new(&[&n.to_string()], "`")
}

/// # HPB - Character position backward
///
/// HPB causes the active data position to be moved by `n` character positions in the data component in the
/// direction opposite to that of the character progression.
pub fn character_backward(n: usize) -> ControlSequence {
    ControlSequence::new(&[&n.to_string()], "j")
}

/// # HPR - Character position forward
///
/// HPR causes the active data position to be moved by `n` character positions in the data component in the
/// direction of the character progression.
pub fn character_forward(n: usize) -> ControlSequence {
    ControlSequence::new(&[&n.to_string()], "a")
}

/// # HVP - Character and line position
///
/// HVP causes the active data position to be moved in the data component to the `l`-th line position
/// according to the line progression and to the `c`-th character position according to the character
/// progression.
pub fn character_and_line_position(l: usize, c: usize) -> ControlSequence {
    ControlSequence::new(&[&l.to_string(), &c.to_string()], "f")
}

/// # PPA - Page position absolute
///
/// PPA causes the active data position to be moved in the data component to the corresponding character
/// position on the `n`-th page.
pub fn page_position(n: usize) -> ControlSequence {
    ControlSequence::new(&[&n.to_string()], " P")
}

/// # PPB - Page position backward
///
/// PPB causes the active data position to be moved in the data component to the corresponding character
/// position on the `n`-th preceding page.
pub fn page_backward(n: usize) -> ControlSequence {
    ControlSequence::new(&[&n.to_string()], " R")
}

/// # PPR - Page position forward
///
/// PPR causes the active data position to be moved in the data component to the corresponding character
/// position on the `n`-th following page.
pub fn page_forward(n: usize) -> ControlSequence {
    ControlSequence::new(&[&n.to_string()], " Q")
}

pub enum MovementDirection {
    Same,
    Opposite,
}

impl Display for MovementDirection {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", match self {
            MovementDirection::Same => "0",
            MovementDirection::Opposite => "1",
        })
    }
}

/// # SIMD - Select implicit movement direction
/// 
/// SIMD is used to select the direction of implicit movement of the data position relative to the character
/// progression. The direction selected remains in effect until the next occurrence of SIMD.
pub fn select_implicit(movement_direction: MovementDirection) -> ControlSequence {
    ControlSequence::new(&[&movement_direction.to_string()], "^")
}

/// # VPA - Line position absolute
/// 
/// VPA causes the active data position to be moved to line position n in the data component in a direction
/// parallel to the line progression.
pub fn line_position(n: usize) -> ControlSequence { ControlSequence::new(&[&n.to_string()], "d") }

/// # VPB - Line position backward
/// 
/// VPB causes the active data position to be moved by n line positions in the data component in a direction
/// opposite to that of the line progression.
pub fn line_backward(n: usize) -> ControlSequence { ControlSequence::new(&[&n.to_string()], "k") }

/// # VPR - Line position forward
/// 
/// VPR causes the active data position to be moved by n line positions in the data component in a direction
/// parallel to the line progression.
pub fn line_forward(n: usize) -> ControlSequence { ControlSequence::new(&[&n.to_string()], "e") }