 
 
     ##################################
+    # Track
+    ##################################
+    class Track
+      mod = (n, m) -> ((n % m) + m) % m
+
+      constructor: ({@id, @pieces, lanes}) ->
+        @lanes = new Lanes lanes
+
+      normalizedPieceIndex: ({pieceIndex, lap}) => lap * @pieces.length + pieceIndex
+      pieceAt: (normalizedIndex) -> @pieces[mod normalizedIndex, @pieces.length]
+
+      addPiecesLengthsBetween: (initialPosition, piecePosition, carLane) ->
+        indices = [(@normalizedPieceIndex initialPosition)...(@normalizedPieceIndex piecePosition)]
+        indices.reduce ((sum, index) => sum + @pieceLength index, carLane), -initialPosition.inPieceDistance
+
+      pieceLength: (index, carLane) ->
+        {startDistance, endDistance, totalDistance, isSwitch} = @lanes.getDistances carLane.atIndex index
+        piece = @pieceAt(index)
+        if (piece.length?)
+          if isSwitch
+            1.0008 * Math.sqrt totalDistance * totalDistance + piece.length * piece.length
+          else
+            piece.length
+        else
+          lengthOnStartLane = @bendedPieceLength piece, startDistance
+          return lengthOnStartLane unless isSwitch
+          lengthOnEndLane = @bendedPieceLength piece, endDistance
+          innerLength = Math.min(lengthOnEndLane, lengthOnStartLane)
+          outerLength = Math.max(lengthOnEndLane, lengthOnStartLane)
+          ratio = (outerLength / innerLength)
+          factor = 1.023 / Math.pow(ratio, 2.2)
+          innerLength + (outerLength - innerLength) * factor
+
+      bendedPieceLength: ({radius, angle}, distanceFromCenter) ->
+        bended = if angle < 0 then 1 else -1
+        laneRadius = radius + bended * distanceFromCenter
+        laneRadius * Math.PI * Math.abs(angle) / 180
+
+    ##################################
+    # Lanes
+    ##################################
+    class Lanes
+      constructor: (lanes) ->
+        @distanceFromCenter = []
+        for lane in lanes
+          @distanceFromCenter[lane.index] = lane.distanceFromCenter
+
+      getDistances: ({startLaneIndex, endLaneIndex}) ->
+        startDistance = @distanceFromCenter[startLaneIndex]
+        endDistance = @distanceFromCenter[endLaneIndex]
+
+        startDistance: startDistance
+        endDistance: endDistance
+        totalDistance: Math.abs startDistance - endDistance
+        isSwitch: startLaneIndex isnt endLaneIndex
+
+
+    ##################################
     # CarLane
     ##################################
     class CarLane
-      constructor: (@normalizedPieceIndex) ->
+      constructor: () ->
         @laneAtIndex = []
         @lowestIndex = null
 
-      at: (position) -> @atIndex @normalizedPieceIndex position
+      at: (position) -> @atIndex race.normalizedPieceIndex position
       isLowerThanLowestIndex: (index) -> not @lowestIndex? or index < @lowestIndex
 
       atIndex: (index) ->

      for car in @cars
        color = car.id.color
        @carColors.push color
        @carLanes[color] = @createCarLane()
        @carPositions[color] = new CarPositions

    createCarLane: -> new CarLane @track.normalizedPieceIndex

    distance: (piecePosition, initialPosition = createPosition(0, 0), carLane = @createCarLane()) ->
      if not (carLane instanceof CarLane)
        carLane = @getCarLane carLane
      sum = @track.addPiecesLengthsBetween initialPosition, piecePosition, carLane

module.exports = (objects) ->
  ##################################
  # Race
  ##################################
  class Race
    race = null
    constructor: ({track, @cars, @raceSession}) ->
      race = this
      @currentTick = 0
      @track = new Track track
      @carLanes = []
