# frozen_string_literal: true

module GirFFI
  module Builders
    # Abstract parent class of the argument building classes. These
    # classes are used by FunctionBuilder to create the code that
    # processes each argument before and after the actual function call.
    class BaseArgumentBuilder
      KEYWORDS = %w(
        alias and begin break case class def do
        else elsif end ensure false for if in
        module next nil not or redo rescue retry
        return self super then true undef unless
        until when while yield
      ).freeze

      attr_reader :arginfo
      attr_accessor :length_arg, :array_arg

      def initialize(var_gen, arginfo)
        @var_gen = var_gen
        @arginfo = arginfo
        @length_arg = nil
        @array_arg = nil
        @is_closure = false
        @destroy_notifier = false
      end

      def name
        @name ||= safe(arginfo.name)
      end

      def direction
        @direction ||= arginfo.direction
      end

      def type_info
        @type_info ||= arginfo.argument_type
      end

      def specialized_type_tag
        type_info.flattened_tag
      end

      # TODO: Use class rather than class name
      def argument_class_name
        type_info.argument_class_name
      end

      def array_length_idx
        type_info.array_length
      end

      def closure_idx
        arginfo.closure
      end

      def destroy_idx
        arginfo.destroy
      end

      # TODO: closure unfortunately means two things in GLib: a closure
      # argument (user_data), and the Closure class (a callable object). Make
      # the distinction more explicit in GirFFI.
      def closure=(arg)
        @is_closure = arg
      end

      # TODO: Unify relationship set-up methods and improve naming. We
      # currently have length_arg=, array_arg=, closure= and
      # mark_as_destroy_notifier.
      def mark_as_destroy_notifier(callback)
        @destroy_notifier = callback
      end

      def array_length_parameter?
        @array_arg
      end

      def closure?
        @is_closure
      end

      def destroy_notifier?
        @destroy_notifier
      end

      def helper_argument?
        array_length_parameter? || closure? || destroy_notifier?
      end

      def ownership_transfer
        arginfo.ownership_transfer
      end

      def safe(name)
        if KEYWORDS.include? name
          "#{name}_"
        else
          name
        end
      end

      def call_argument_name
        @call_argument_name ||= new_variable
      end

      def new_variable
        @var_gen.new_var
      end
    end
  end
end
