]>
Commit | Line | Data |
---|---|---|
1 | import CoreGraphics | |
2 | import Foundation | |
3 | ||
4 | // MARK: - Types | |
5 | ||
6 | struct MapParsingPatterns { | |
7 | static let vertex = try! NSRegularExpression( | |
8 | pattern: | |
9 | "([^\\(]+?)[\\s]*\\([\\s]*([0-9]+.?[0-9]*)[\\s]*,[\\s]*([0-9]+.?[0-9]*)[\\s]*\\)[\\s]*(?:\\[(.*?)\\])?", | |
10 | options: .caseInsensitive) | |
11 | static let edge = try! NSRegularExpression( | |
12 | pattern: "(.+?)[\\s]*-([->])[\\s]*(.+)", options: .caseInsensitive) | |
13 | static let blocker = try! NSRegularExpression( | |
14 | pattern: "\\[(Blocker)\\][\\s]*(.+)", options: .caseInsensitive) | |
15 | static let opportunity = try! NSRegularExpression( | |
16 | pattern: "\\[(Opportunity)\\][\\s]*(.+)[\\s]+([-+])[\\s]*([0-9]+.?[0-9]*)", | |
17 | options: .caseInsensitive) | |
18 | static let stage = try! NSRegularExpression( | |
19 | pattern: "\\[(I{1,3})\\][\\s]*([0-9]+.?[0-9]*)", options: .caseInsensitive) | |
20 | } | |
21 | ||
22 | struct ParsedMap { | |
23 | let vertices: [Vertex] | |
24 | let edges: [MapEdge] | |
25 | let blockers: [Blocker] | |
26 | let opportunities: [Opportunity] | |
27 | let stages: [CGFloat] | |
28 | ||
29 | static let empty: ParsedMap = ParsedMap( | |
30 | vertices: [], edges: [], blockers: [], opportunities: [], stages: defaultDimensions) | |
31 | } | |
32 | ||
33 | struct Vertex { | |
34 | let id: Int | |
35 | let label: String | |
36 | let position: CGPoint | |
37 | var shape: VertexShape = .circle | |
38 | } | |
39 | ||
40 | enum VertexShape: String { | |
41 | case circle | |
42 | case square | |
43 | case triangle | |
44 | case x | |
45 | } | |
46 | ||
47 | struct MapEdge { | |
48 | let id: Int | |
49 | let origin: CGPoint | |
50 | let destination: CGPoint | |
51 | let arrowhead: Bool | |
52 | } | |
53 | ||
54 | struct Blocker { | |
55 | let id: Int | |
56 | let position: CGPoint | |
57 | } | |
58 | ||
59 | struct Opportunity { | |
60 | let id: Int | |
61 | let origin: CGPoint | |
62 | let destination: CGPoint | |
63 | } | |
64 | ||
65 | struct StageDimensions { | |
66 | let index: Int | |
67 | let dimensions: CGFloat | |
68 | } | |
69 | ||
70 | private let defaultDimensions: [CGFloat] = [ | |
71 | 25.0, | |
72 | 50.0, | |
73 | 75.0, | |
74 | ] | |
75 | ||
76 | // MARK: - MapParserStrategy protocol | |
77 | ||
78 | protocol MapParserStrategy { | |
79 | func canHandle(line: String) -> Bool | |
80 | func handle(index: Int, line: String, vertices: [String: Vertex]) -> (Any.Type, Any) | |
81 | } | |
82 | ||
83 | struct AnyMapParserStrategy: MapParserStrategy { | |
84 | ||
85 | private let base: MapParserStrategy | |
86 | ||
87 | init<T: MapParserStrategy>(_ base: T) { | |
88 | self.base = base | |
89 | } | |
90 | ||
91 | func canHandle(line: String) -> Bool { | |
92 | return base.canHandle(line: line) | |
93 | } | |
94 | func handle(index: Int, line: String, vertices: [String: Vertex]) -> (Any.Type, Any) { | |
95 | return base.handle(index: index, line: line, vertices: vertices) | |
96 | } | |
97 | } | |
98 | ||
99 | // MARK: - Map Builder | |
100 | ||
101 | class MapBuilder { | |
102 | var vertices: [String: Vertex] = [:] | |
103 | private var edges: [MapEdge] = [] | |
104 | private var blockers: [Blocker] = [] | |
105 | private var opportunities: [Opportunity] = [] | |
106 | private var stages: [CGFloat] = defaultDimensions | |
107 | ||
108 | func addObjectToMap(type: Any.Type, object: Any) { | |
109 | if type == Vertex.self { | |
110 | let vertex = object as! Vertex | |
111 | vertices[vertex.label] = vertex | |
112 | } | |
113 | ||
114 | if type == MapEdge.self { | |
115 | let edge = object as! MapEdge | |
116 | edges.append(edge) | |
117 | } | |
118 | ||
119 | if type == Blocker.self { | |
120 | let blocker = object as! Blocker | |
121 | blockers.append(blocker) | |
122 | } | |
123 | ||
124 | if type == Opportunity.self { | |
125 | let opportunity = object as! Opportunity | |
126 | opportunities.append(opportunity) | |
127 | } | |
128 | ||
129 | if type == StageDimensions.self { | |
130 | let stageDimensions = object as! StageDimensions | |
131 | stages[stageDimensions.index] = stageDimensions.dimensions | |
132 | ||
133 | } | |
134 | } | |
135 | ||
136 | func build() -> ParsedMap { | |
137 | let mappedVertices = vertices.map { label, vertex in return vertex } | |
138 | return ParsedMap( | |
139 | vertices: mappedVertices, edges: edges, blockers: blockers, opportunities: opportunities, | |
140 | stages: stages) | |
141 | } | |
142 | } |