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