]> git.r.bdr.sh - rbdr/map/blob - Map/MapParser/MapParser.swift
3528eb5d4d26375c2bda7a08b010b679628e8549
[rbdr/map] / Map / 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: "\\[(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
30 struct Vertex {
31 let id: Int
32 let label: String
33 let position: CGPoint
34 var shape: VertexShape = .circle
35 }
36
37 enum VertexShape: String {
38 case circle
39 case square
40 case triangle
41 case x
42 }
43
44 struct MapEdge {
45 let id: Int
46 let origin: CGPoint
47 let destination: CGPoint
48 let arrowhead: Bool
49 }
50
51 struct Blocker {
52 let id: Int
53 let position: CGPoint
54 }
55
56 struct Opportunity {
57 let id: Int
58 let origin: CGPoint
59 let destination: CGPoint
60 }
61
62 struct StageDimensions {
63 let index: Int
64 let dimensions: CGFloat
65 }
66
67 private let defaultDimensions: [CGFloat] = [
68 25.0,
69 50.0,
70 75.0,
71 ]
72
73 // MARK: - MapParserStrategy protocol
74
75 protocol MapParserStrategy {
76 func canHandle(line: String) -> Bool
77 func handle(index: Int, line: String, vertices: [String: Vertex]) -> (Any.Type, Any)
78 }
79
80 struct AnyMapParserStrategy: MapParserStrategy {
81
82 private let base: MapParserStrategy
83
84 init<T: MapParserStrategy>(_ base: T) {
85 self.base = base
86 }
87
88 func canHandle(line: String) -> Bool {
89 return base.canHandle(line: line)
90 }
91 func handle(index: Int, line: String, vertices: [String: Vertex]) -> (Any.Type, Any) {
92 return base.handle(index: index, line: line, vertices: vertices)
93 }
94 }
95
96 // MARK: - Map Builder
97
98 class MapBuilder {
99 var vertices: [String: Vertex] = [:]
100 private var edges: [MapEdge] = []
101 private var blockers: [Blocker] = []
102 private var opportunities: [Opportunity] = []
103 private var stages: [CGFloat] = defaultDimensions
104
105 func addObjectToMap(type: Any.Type, object: Any) {
106 if type == Vertex.self {
107 let vertex = object as! Vertex
108 vertices[vertex.label] = vertex
109 }
110
111 if type == MapEdge.self {
112 let edge = object as! MapEdge
113 edges.append(edge)
114 }
115
116 if type == Blocker.self {
117 let blocker = object as! Blocker
118 blockers.append(blocker)
119 }
120
121 if type == Opportunity.self {
122 let opportunity = object as! Opportunity
123 opportunities.append(opportunity)
124 }
125
126 if type == StageDimensions.self {
127 let stageDimensions = object as! StageDimensions
128 stages[stageDimensions.index] = stageDimensions.dimensions
129
130 }
131 }
132
133 func build() -> ParsedMap {
134 let mappedVertices = vertices.map { label, vertex in return vertex }
135 return ParsedMap(
136 vertices: mappedVertices, edges: edges, blockers: blockers, opportunities: opportunities,
137 stages: stages)
138 }
139 }