# frozen_string_literal: true

module Infoboxer
  module Tree
    # Base class for all "paragraph-level" nodes: {Paragraph}, {ListItem},
    # {Heading}. It should be convenient to use it in {Navigation::Lookup::Node#_lookup Node#lookup}
    # and similar methods like this:
    #
    # ```ruby
    # page.lookup(:BaseParagraph) # => flat list of paragraph-levels
    # ```
    class BaseParagraph < Compound
      def text
        super.strip + "\n\n"
      end
    end

    # @private
    class EmptyParagraph < Node
      def initialize(text)
        @text = text
      end

      # should never be left in nodes flow
      def empty?
        true
      end

      attr_reader :text
    end

    # @private
    module Mergeable
      def can_merge?(other)
        !closed? && self.class == other.class
      end

      def merge!(other)
        if other.is_a?(EmptyParagraph)
          @closed = true
        else
          [splitter, *other.children].each do |c|
            c.parent = self
            @children << c
          end
          @closed = other.closed?
        end
      end
    end

    # @private
    class MergeableParagraph < BaseParagraph
      include Mergeable

      def can_merge?(other)
        !closed? &&
          (self.class == other.class || other.is_a?(EmptyParagraph))
      end
    end

    # Represents plain text paragraph.
    class Paragraph < MergeableParagraph
      # @private
      # Internal, used by {Parser} for merging
      def splitter
        Text.new(' ')
      end

      # @private
      # Internal, used by {Parser}
      def templates_only?
        children.all? { |c| c.is_a?(Template) || c.is_a?(Text) && c.raw_text.strip.empty? }
      end

      # @private
      # Internal, used by {Parser}
      def to_templates
        children.grep(Template)
      end

      # @private
      # Internal, used by {Parser}
      def to_templates?
        templates_only? ? to_templates : self
      end
    end

    # Represents horisontal ruler splitter. Rarely seen in modern wikis.
    class HR < Node
    end

    # Represents heading.
    #
    # NB: min heading level in MediaWiki is 2, Heading level 1 (page
    # title) is not seen in page flaw.
    class Heading < BaseParagraph
      def initialize(children, level)
        super(children, level: level)
      end

      # @!attribute [r] level
      #   @return [Fixnum] lesser numbers is more important heading
      def_readers :level
    end

    # Represents preformatted text chunk.
    #
    # Paragraph-level thing, can contain many lines of text.
    class Pre < MergeableParagraph
      # @private
      # Internal, used by {Parser}
      def merge!(other)
        if other.is_a?(EmptyParagraph) && !other.text.empty?
          @children.last.raw_text << "\n" << other.text.sub(/^ /, '')
        else
          super
        end
      end

      # @private
      # Internal, used by {Parser} for merging
      def splitter
        Text.new("\n")
      end
    end
  end
end
