import CoreGraphics
import Foundation
-let VERTEX_PATTERN = "([^\\(]+?)[\\s]*\\([\\s]*([0-9]+.?[0-9]*)[\\s]*,[\\s]*([0-9]+.?[0-9]*)[\\s]*\\)"
-let EDGE_PATTERN = "(.+?)[\\s]*->[\\s]*(.+)"
+let vertexPattern =
+ "([^\\(]+?)[\\s]*\\([\\s]*([0-9]+.?[0-9]*)[\\s]*,[\\s]*([0-9]+.?[0-9]*)[\\s]*\\)"
+let edgePattern = "(.+?)[\\s]*-([->])[\\s]*(.+)"
+let blockerPattern = "\\[Blocker\\][\\s]*(.+)"
+let opportunityPattern = "\\[Opportunity\\][\\s]*(.+)[\\s]+([-+])[\\s]*([0-9]+.?[0-9]*)"
+let stagePattern = "\\[(I{1,3})\\][\\s]*([0-9]+.?[0-9]*)"
struct ParsedMap {
- let vertices: [Vertex]
- let edges: [MapEdge]
+ let vertices: [Vertex]
+ let edges: [MapEdge]
+ let blockers: [Blocker]
+ let opportunities: [Opportunity]
+ let stages: [CGFloat]
}
struct Vertex {
- let id: Int
- let label: String
- let position: CGPoint
+ let id: Int
+ let label: String
+ let position: CGPoint
}
struct MapEdge {
- let id: Int
- let origin: CGPoint
- let destination: CGPoint
+ let id: Int
+ let origin: CGPoint
+ let destination: CGPoint
+ let arrowhead: Bool
}
+struct Blocker {
+ let id: Int
+ let position: CGPoint
+}
+
+struct Opportunity {
+ let id: Int
+ let origin: CGPoint
+ let destination: CGPoint
+}
+
+let defaultDimensions: [CGFloat] = [
+ 25.0,
+ 50.0,
+ 75.0,
+]
+
// Extracts the vertices from the text
func parseVertices(_ text: String) -> [String: CGPoint] {
-
- var result: [String: CGPoint] = [:]
- let regex = try! NSRegularExpression(pattern: VERTEX_PATTERN, options: .caseInsensitive)
-
- let lines = text.split(whereSeparator: \.isNewline)
-
- for line in lines {
- let range = NSRange(location: 0, length: line.utf16.count)
- let matches = regex.matches(in: String(line), options: [], range: range)
-
- if matches.count > 0 && matches[0].numberOfRanges == 4{
-
- let match = matches[0];
- let key = String(line[Range(match.range(at: 1), in: line)!])
- let xString = String(line[Range(match.range(at: 2), in: line)!])
- let yString = String(line[Range(match.range(at: 3), in: line)!])
- let x = CGFloat(truncating: NumberFormatter().number(from:xString) ?? 0.0)
- let y = CGFloat(truncating: NumberFormatter().number(from:yString) ?? 0.0)
- let point = CGPoint(x: x, y: y)
-
- result[key] = point
- }
+
+ var result: [String: CGPoint] = [:]
+ let regex = try! NSRegularExpression(pattern: vertexPattern, options: .caseInsensitive)
+
+ let lines = text.split(whereSeparator: \.isNewline)
+
+ for line in lines {
+ let range = NSRange(location: 0, length: line.utf16.count)
+ let matches = regex.matches(in: String(line), options: [], range: range)
+
+ if matches.count > 0 && matches[0].numberOfRanges == 4 {
+
+ let match = matches[0]
+ let key = String(line[Range(match.range(at: 1), in: line)!])
+ let xString = String(line[Range(match.range(at: 2), in: line)!])
+ let yString = String(line[Range(match.range(at: 3), in: line)!])
+ let x = CGFloat(truncating: NumberFormatter().number(from: xString) ?? 0.0)
+ let y = CGFloat(truncating: NumberFormatter().number(from: yString) ?? 0.0)
+ let point = CGPoint(x: x, y: y)
+
+ result[key] = point
}
-
- return result
-}
+ }
-// Extracts the edges from the text
+ return result
+}
func parseEdges(_ text: String, vertices: [String: CGPoint]) -> [MapEdge] {
-
- var result: [MapEdge] = []
- let regex = try! NSRegularExpression(pattern: EDGE_PATTERN, options: .caseInsensitive)
-
- let lines = text.split(whereSeparator: \.isNewline)
-
- for (index, line) in lines.enumerated() {
- let range = NSRange(location: 0, length: line.utf16.count)
- let matches = regex.matches(in: String(line), options: [], range: range)
-
- if matches.count > 0 && matches[0].numberOfRanges == 3 {
-
- let match = matches[0];
- let vertexA = String(line[Range(match.range(at: 1), in: line)!])
- let vertexB = String(line[Range(match.range(at: 2), in: line)!])
-
- if let origin = vertices[vertexA] {
- if let destination = vertices[vertexB] {
- result.append(MapEdge(id: index, origin: origin, destination: destination))
- }
- }
+
+ var result: [MapEdge] = []
+ let regex = try! NSRegularExpression(pattern: edgePattern, options: .caseInsensitive)
+
+ let lines = text.split(whereSeparator: \.isNewline)
+
+ for (index, line) in lines.enumerated() {
+ let range = NSRange(location: 0, length: line.utf16.count)
+ let matches = regex.matches(in: String(line), options: [], range: range)
+
+ if matches.count > 0 && matches[0].numberOfRanges == 4 {
+
+ let match = matches[0]
+ let arrowhead = String(line[Range(match.range(at: 2), in: line)!]) == ">"
+ let vertexA = String(line[Range(match.range(at: 1), in: line)!])
+ let vertexB = String(line[Range(match.range(at: 3), in: line)!])
+
+ if let origin = vertices[vertexA] {
+ if let destination = vertices[vertexB] {
+ result.append(
+ MapEdge(id: index, origin: origin, destination: destination, arrowhead: arrowhead))
}
+ }
}
-
- return result
+ }
+
+ return result
+}
+
+func parseOpportunities(_ text: String, vertices: [String: CGPoint]) -> [Opportunity] {
+
+ var result: [Opportunity] = []
+ let regex = try! NSRegularExpression(pattern: opportunityPattern, options: .caseInsensitive)
+
+ let lines = text.split(whereSeparator: \.isNewline)
+
+ for (index, line) in lines.enumerated() {
+ let range = NSRange(location: 0, length: line.utf16.count)
+ let matches = regex.matches(in: String(line), options: [], range: range)
+
+ if matches.count > 0 && matches[0].numberOfRanges == 4 {
+
+ let match = matches[0]
+ let multiplier = CGFloat(
+ String(line[Range(match.range(at: 2), in: line)!]) == "-" ? -1.0 : 1.0)
+ let vertex = String(line[Range(match.range(at: 1), in: line)!])
+ let opportunityString = String(line[Range(match.range(at: 3), in: line)!])
+ let opportunity = CGFloat(
+ truncating: NumberFormatter().number(from: opportunityString) ?? 0.0)
+
+ if let origin = vertices[vertex] {
+ let destination = CGPoint(x: origin.x + opportunity * multiplier, y: origin.y)
+ result.append(Opportunity(id: index, origin: origin, destination: destination))
+ }
+ }
+ }
+
+ return result
+}
+
+func parseBlockers(_ text: String, vertices: [String: CGPoint]) -> [Blocker] {
+
+ var result: [Blocker] = []
+ let regex = try! NSRegularExpression(pattern: blockerPattern, options: .caseInsensitive)
+
+ let lines = text.split(whereSeparator: \.isNewline)
+
+ for (index, line) in lines.enumerated() {
+ let range = NSRange(location: 0, length: line.utf16.count)
+ let matches = regex.matches(in: String(line), options: [], range: range)
+
+ if matches.count > 0 && matches[0].numberOfRanges == 2 {
+
+ let match = matches[0]
+ let vertexA = String(line[Range(match.range(at: 1), in: line)!])
+
+ if let position = vertices[vertexA] {
+ result.append(Blocker(id: index, position: position))
+ }
+ }
+ }
+
+ return result
+}
+
+func parseStages(_ text: String) -> [CGFloat] {
+
+ var result = defaultDimensions
+ let regex = try! NSRegularExpression(pattern: stagePattern, options: .caseInsensitive)
+
+ let lines = text.split(whereSeparator: \.isNewline)
+
+ for line in lines {
+ let range = NSRange(location: 0, length: line.utf16.count)
+ let matches = regex.matches(in: String(line), options: [], range: range)
+
+ if matches.count > 0 && matches[0].numberOfRanges == 3 {
+
+ let match = matches[0]
+ let stage = String(line[Range(match.range(at: 1), in: line)!])
+ let dimensionsString = String(line[Range(match.range(at: 2), in: line)!])
+ let dimensions = CGFloat(truncating: NumberFormatter().number(from: dimensionsString) ?? 0.0)
+
+ result[stage.count - 1] = dimensions
+ }
+ }
+
+ return result
}
// Converts vetex dictionary to array
func mapVertices(_ vertices: [String: CGPoint]) -> [Vertex] {
- var i = 0
- return vertices.map { label, position in
- i += 1;
- return Vertex(id: i, label: label, position: position)
- }
+ var i = 0
+ return vertices.map { label, position in
+ i += 1
+ return Vertex(id: i, label: label, position: position)
+ }
}
extension Map {
- func parse() -> ParsedMap {
-
- let text = self.content ?? ""
- let vertices = parseVertices(text)
- let mappedVertices = mapVertices(vertices)
- let edges = parseEdges(text, vertices: vertices)
- print(mappedVertices)
- print(edges)
-
- return ParsedMap(vertices: mappedVertices, edges: edges)
- }
+ func parse() -> ParsedMap {
+
+ let text = self.content ?? ""
+ let vertices = parseVertices(text)
+ let mappedVertices = mapVertices(vertices)
+ let edges = parseEdges(text, vertices: vertices)
+ let blockers = parseBlockers(text, vertices: vertices)
+ let opportunities = parseOpportunities(text, vertices: vertices)
+ let stages = parseStages(text)
+
+ return ParsedMap(
+ vertices: mappedVertices, edges: edges, blockers: blockers, opportunities: opportunities,
+ stages: stages)
+ }
}