# rubocop:disable all
# frozen_string_literal: true

require_relative 'exception'
require_relative 'file_manager'
require_relative 'stage_manager'

module SheepAst
  # Get next command
  class NextCommand
    include Exception
    include Log

    attr_accessor :command
    attr_accessor :description

    def init
      @command = nil
      @description = nil
    end

    def self.command_array(array)
      arr = []
      array.each do |elem|
        arr << elem.command
      end
      return arr
    end

    def self.desc_array(array)
      arr = []
      array.each do |elem|
        arr << elem.description
      end
      return arr
    end
  end

  # TBD
  class OnOff
    Disable = 0
    Enable = 1

    def self.str(arg)
      case arg
      when OnOff::Disable
        return 'Disable'
      when OnOff::Enable
        return 'Enable'
      end
    end
  end

  # TBD
  class OperateNode
    Top = 0
    Up = 1
    Goto = 2
    Revert = 3
    Commit = 4

    def self.str(arg)
      case arg
      when OperateNode::Top
        return 'Top'
      when OperateNode::Up
        return 'Up'
      when OperateNode::Goto
        return 'Goto'
      when OperateNode::Revert
        return 'Revert'
      when OperateNode::Commit
        return 'Commit'
      end
    end
  end

  # Message struture between components
  #
  # @api private
  #
  class MatchKind
    Any = 0
    Exact = 1
    ExactGroup = 2
    Regex = 3
    Condition = 4
    RegexCondition = 5
    Default = 6
  end

  # Enum for action of matcher
  #
  # @api private
  #
  class MatchResult
    NotFound = 0
    GetNext = 1
    StayNodeGetNext = 2
    Continue = 3
    Finish = 4
    Default = 5

    def self.str(arg)
      case arg
      when MatchResult::NotFound
        return 'NotFound'
      when MatchResult::GetNext
        return 'GetNext'
      when MatchResult::StayNodeGetNext
        return 'StayNodeGetNext'
      when MatchResult::Continue
        return 'Continue'
      when MatchResult::Finish
        return 'Finish'
      when MatchResult::Default
        return 'Default'
      end
    end
  end

  # Enum for action of matcher
  #
  # @api private
  #
  class MatchAction
    Abort = 0
    LazyAbort = 1
    Next = 2
    StayNode = 3
    Continue = 4
    InitContinue = 5
    Finish = 6
    Default = 7

    def self.str(arg)
      case arg
      when MatchAction::Abort
        return 'Abort'
      when MatchAction::LazyAbort
        return 'LazyAbort'
      when MatchAction::Next
        return 'Next'
      when MatchAction::StayNode
        return 'StayNode'
      when MatchAction::Continue
        return 'Continue'
      when MatchAction::InitContinue
        return 'InitContinue'
      when MatchAction::Finish
        return 'Finish'
      when MatchAction::Default
        return 'Default'
      end
    end
  end

  # Enum for status of matcher
  #
  # @api private
  #
  class MatchStatus
    NotFound = 0
    ConditionMatchingStart = 1
    ConditionMatchingProgress = 2
    ConditionMatchingAtEnd = 3
    ConditionEndButMatchingProgress = 4
    MatchingProgress = 5
    AtEnd = 6
    Default = 7

    def self.str(arg)
      case arg
      when MatchStatus::NotFound
        return 'NotFound'
      when MatchStatus::ConditionMatchingStart
        return 'ConditionMatchingStart'
      when MatchStatus::ConditionMatchingProgress
        return 'ConditionMatchingProgress'
      when MatchStatus::ConditionMatchingAtEnd
        return 'ConditionMatchingAtEnd'
      when MatchStatus::ConditionEndButMatchingProgress
        return 'ConditionEndButMatchingProgress'
      when MatchStatus::MatchingProgress
        return 'MatchingProgress'
      when MatchStatus::AtEnd
        return 'AtEnd'
      when MatchStatus::Default
        return 'Default'
      end
    end
  end

  # Enum for action of matcher
  #
  # @api private
  #
  class RequestNextData
    Next = 0
    Again = 1
  end

  # Message to handle node object
  #
  # @api private
  #
  class NodeInfo
    attr_accessor :node_id
    attr_accessor :match_id
    attr_accessor :kind
    attr_accessor :status
    attr_accessor :store_symbol

    def copy(other)
      @node_id = other.node_id.dup
      @match_id = other.match_id.dup
      @kind = other.kind.dup
      @status = other.status.dup
      @store_symbol = other.store_symbol.dup
    end

    def init
      @node_id = 0
      @match_id = nil
      @kind = nil
      @status = MatchStatus::Default
      @store_symbol = nil
    end
  end

  # Structure to hold file info in analyze.
  #
  # @api private
  #
  class FileInfo
    attr_accessor :file
    attr_accessor :filename
    attr_accessor :raw_lines
    attr_accessor :tokenized
    attr_accessor :chunk
    attr_accessor :using_chunk
    attr_accessor :line
    attr_accessor :max_line
    attr_accessor :index
    attr_accessor :namespace_stack
    attr_accessor :meta1_stack
    attr_accessor :meta2_stack
    attr_accessor :meta3_stack
    attr_accessor :ast_include
    attr_accessor :ast_exclude
    attr_accessor :enter_cb
    attr_accessor :exit_cb
    attr_accessor :new_file_validation

    def copy(other)
      @file = other.file.dup
      @filename = other.filename.dup
      @tokenized = other.tokenized.dup
      @chunk = other.chunk.dup
      @using_chunk = other.using_chunk.dup
      @line = other.line.dup
      @max_line = other.max_line.dup
      @index = other.index.dup
      @namespace_stack = other.namespace_stack.dup
      @meta1_stack = other.meta1_stack.dup
      @meta2_stack = other.meta2_stack.dup
      @meta3_stack = other.meta3_stack.dup
      @ast_include = other.ast_include.dup
      @ast_exclude = other.ast_exclude.dup
      @enter_cb = other.enter_cb.dup
      @exit_cb =  other.exit_cb.dup
      @raw_lines = other.raw_lines.dup
      @new_file_validation = other.new_file_validation
      # lprint "#{self.class.name} copy is called. #{inspect}"
    end

    def init
      # lprint "#{self.class.name} init is called. #{inspect}"
      @file = nil
      @filename = nil
      @tokenized = nil
      @chunk = nil
      @using_chunk = nil
      @line = 0
      @max_line = 0
      @index = 0
      @namespace_stack = []
      @meta1_stack = []
      @meta2_stack = []
      @meta3_stack = []
      @ast_include = nil
      @ast_exclude = nil
      @enter_cb = nil
      @exit_cb = nil
      @raw_lines = nil
      @new_file_validation = true
    end

    def inspect
      "<#{self.class.name} object_id = #{object_id}, file = #{@file.inspect}, "\
        "filename = #{@filename.inspect},"\
        " chunk = #{@chunk.inspect}, using_chunk = #{@using_chunk.inspect}"\
        " line = #{@line.inspect}, max_line = #{@max_line.inspect},"\
        " index = #{@index.inspect}, namespace_stack = #{@namespace_stack.inspect},"\
        " ast_include = #{@ast_include.inspect}, ast_exclude = #{@ast_exclude.inspect},"\
        " enter_cb = #{@enter_cb.inspect}, exit_cb = #{@exit_cb.inspect},"\
        " new_file_validation = #{@new_file_validation.inspect}>"
    end
  end

  class SaveRequest
    attr_accessor :file
    attr_accessor :filename
    attr_accessor :chunk
    attr_accessor :ast_include
    attr_accessor :ast_exclude
    attr_accessor :enter_cb
    attr_accessor :exit_cb
    attr_accessor :namespace
    attr_accessor :meta1
    attr_accessor :meta2
    attr_accessor :meta3
  end

  # This structure is passed fro file_manager to Match and Action.
  # Transit elements add informaion to this structure
  #
  # @api private
  #
  class AnalyzeData
    attr_accessor :expr
    attr_accessor :is_eol
    attr_accessor :tokenized_line
    attr_accessor :tokenized_line_prev
    attr_accessor :raw_line
    attr_accessor :file_info
    attr_accessor :file_manager
    attr_accessor :stage_manager
    attr_accessor :stack
    attr_accessor :stack_symbol
    attr_accessor :request_next_data
    attr_accessor :save_request

    def init
      @expr = nil
      @is_eol = nil
      @tokenized_line = nil
      @tokenized_line_prev = nil
      @file_info = nil
      @file_manager = nil
      @stage_manager = nil
      @request_next_data = RequestNextData::Next
      @stack = []
      @stack_symbol = []
      @save_request = nil
      @raw_line = nil
    end

    def inspect
      "<#{self.class.name} object_id = #{object_id},"\
        " expr = '#{expr.inspect}', is_eol = '#{is_eol.inspect}',"\
        " stack = #{stack.inspect}, stack_symbol = #{stack_symbol.inspect},"\
        " request_next_data = #{request_next_data.inspect}, file_info = #{file_info.inspect},"\
        " tokenized_line = #{@tokenized_line.inspect},"\
        " tokenized_line_prev = #{@tokenized_line_prev.inspect}"
    end
  end
end
