]> git.r.bdr.sh - rbdr/map/blobdiff - Map/Extensions/Map+parse.swift
Release 1.1.0
[rbdr/map] / Map / Extensions / Map+parse.swift
index d82ba99173f534750026aacbb4f01362d00a84f2..904f492cb49a063b0726b144b39c9caf305c375e 100644 (file)
-import CoreGraphics
-import Foundation
-
-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 blockers: [Blocker]
-  let opportunities: [Opportunity]
-  let stages: [CGFloat]
-}
-
-struct Vertex {
-  let id: Int
-  let label: String
-  let position: CGPoint
-}
-
-struct MapEdge {
-  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: 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
-}
-
-func parseEdges(_ text: String, vertices: [String: CGPoint]) -> [MapEdge] {
-
-  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))
+extension Map {
+  static func parse(content: String) -> ParsedMap {
+
+    let parsers = [
+      AnyMapParserStrategy(VertexParserStrategy()),
+      AnyMapParserStrategy(EdgeParserStrategy()),
+      AnyMapParserStrategy(BlockerParserStrategy()),
+      AnyMapParserStrategy(OpportunityParserStrategy()),
+      AnyMapParserStrategy(StageParserStrategy()),
+    ]
+    let builder = MapBuilder()
+
+    let lines = content.split(whereSeparator: \.isNewline)
+
+    for (index, line) in lines.enumerated() {
+      for parser in parsers {
+        if parser.canHandle(line: String(line)) {
+          let (type, object) = parser.handle(
+            index: index, line: String(line), vertices: builder.vertices)
+          builder.addObjectToMap(type: type, object: object)
+          break
         }
       }
     }
-  }
-
-  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)
-  }
-}
-
-extension Map {
-  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)
+    return builder.build()
   }
 }