solid-process/solid-result

View on GitHub
lib/solid/result/event_logs/tree.rb

Summary

Maintainability
A
0 mins
Test Coverage
# frozen_string_literal: true

class Solid::Result
  module EventLogs
    class Tree
      class Node
        attr_reader :id, :value, :parent, :normalizer, :children

        def initialize(value, parent:, id:, normalizer:)
          @normalizer = normalizer

          @id = id
          @value = normalizer.call(id, value)
          @parent = parent

          @children = []
        end

        def insert(value, id:)
          node = self.class.new(value, parent: self, id: id, normalizer: normalizer)

          @children << node

          node
        end

        def root?
          parent.nil?
        end

        def leaf?
          children.empty?
        end

        def node?
          !leaf?
        end

        def inspect
          "#<#{self.class.name} id=#{id} children.size=#{children.size}>"
        end
      end

      attr_reader :size, :root, :current

      def initialize(value, normalizer: ->(_id, val) { val })
        @size = 0

        @root = Node.new(value, parent: nil, id: size, normalizer: normalizer)

        @current = root
      end

      def root_value
        root.value
      end

      def parent_value
        current.parent&.value || root_value
      end

      def current_value
        current.value
      end

      def insert(value)
        @size += 1

        current.insert(value, id: size)
      end

      def insert!(value)
        move_to! insert(value)
      end

      def move_to!(node)
        tap { @current = node }
      end

      def move_up!(level = 1)
        tap { level.times { move_to!(current.parent || root) } }
      end

      def move_down!(level = 1, index: -1)
        tap { level.times { current.children[index].then { |child| move_to!(child) if child } } }
      end

      def move_to_root!
        move_to!(root)
      end

      Ids = ->(node) { [node.id, node.children.map(&Ids)] }

      def ids
        Ids[root]
      end

      def ids_list
        ids.flatten
      end

      IdsMatrix = ->(tree, row, col, memo, previous) do
        last_row = previous[0]

        tree.each_with_index do |node, index|
          row = [(index + 1), last_row].max

          id, leaf = node

          memo[id] = previous == [row, col] ? [row, col + 1] : [row, col]

          previous = memo[id]

          IdsMatrix[leaf, row, col + 1, memo, previous]
        end
      end

      def ids_matrix
        current = [0, 0]

        memo = { 0 => current }

        IdsMatrix[ids[1], 1, 1, memo, current]

        memo
      end

      IdsLevelParent = ->((id, node), parent = 0, level = 0, memo = {}) do
        memo[id] = [level, parent]

        node.each { |leaf| IdsLevelParent[leaf, id, level + 1, memo] }

        memo
      end

      def ids_level_parent
        IdsLevelParent[ids]
      end
    end
  end
end