1 module hunt.markdown.node.Node;
2 
3 import hunt.markdown.node.Visitor;
4 
5 abstract class Node {
6 
7     private Node parent = null;
8     private Node firstChild = null;
9     private Node lastChild = null;
10     private Node prev = null;
11     private Node next = null;
12 
13     public abstract void accept(Visitor visitor);
14 
15     public Node getNext() {
16         return next;
17     }
18 
19     public Node getPrevious() {
20         return prev;
21     }
22 
23     public Node getFirstChild() {
24         return firstChild;
25     }
26 
27     public Node getLastChild() {
28         return lastChild;
29     }
30 
31     public Node getParent() {
32         return parent;
33     }
34 
35     protected void setParent(Node parent) {
36         this.parent = parent;
37     }
38 
39     public void appendChild(Node child) {
40         child.unlink();
41         child.setParent(this);
42         if (this.lastChild !is null) {
43             this.lastChild.next = child;
44             child.prev = this.lastChild;
45             this.lastChild = child;
46         } else {
47             this.firstChild = child;
48             this.lastChild = child;
49         }
50     }
51 
52     public void prependChild(Node child) {
53         child.unlink();
54         child.setParent(this);
55         if (this.firstChild !is null) {
56             this.firstChild.prev = child;
57             child.next = this.firstChild;
58             this.firstChild = child;
59         } else {
60             this.firstChild = child;
61             this.lastChild = child;
62         }
63     }
64 
65     public void unlink() {
66         if (this.prev !is null) {
67             this.prev.next = this.next;
68         } else if (this.parent !is null) {
69             this.parent.firstChild = this.next;
70         }
71         if (this.next !is null) {
72             this.next.prev = this.prev;
73         } else if (this.parent !is null) {
74             this.parent.lastChild = this.prev;
75         }
76         this.parent = null;
77         this.next = null;
78         this.prev = null;
79     }
80 
81     public void insertAfter(Node sibling) {
82         sibling.unlink();
83         sibling.next = this.next;
84         if (sibling.next !is null) {
85             sibling.next.prev = sibling;
86         }
87         sibling.prev = this;
88         this.next = sibling;
89         sibling.parent = this.parent;
90         if (sibling.next is null) {
91             sibling.parent.lastChild = sibling;
92         }
93     }
94 
95     public void insertBefore(Node sibling) {
96         sibling.unlink();
97         sibling.prev = this.prev;
98         if (sibling.prev !is null) {
99             sibling.prev.next = sibling;
100         }
101         sibling.next = this;
102         this.prev = sibling;
103         sibling.parent = this.parent;
104         if (sibling.prev is null) {
105             sibling.parent.firstChild = sibling;
106         }
107     }
108 
109     override public string toString() {
110         return typeid(this).name ~ "{" ~ toStringAttributes() ~ "}";
111     }
112 
113     protected string toStringAttributes() {
114         return "";
115     }
116 }