module Pod

  # Model class which describes a Pods target.
  #
  # The Target class stores and provides the information necessary for
  # working with a target in the Podfile and it's dependent libraries.
  # This class is used to represent both the targets and their libraries.
  #
  class AbstractTarget

    # @return [PBXNativeTarget] the target definition of the Podfile that
    #         generated this target.
    #
    attr_reader :target_definition

    # @return [Sandbox] The sandbox where the Pods should be installed.
    #
    attr_reader :sandbox

    # @return [String] the name of the library.
    #
    def name
      label
    end

    # @return [String] the name of the library.
    #
    def product_name
      "lib#{label}.a"
    end

    # @return [String] the XCConfig namespaced prefix.
    #
    def xcconfig_prefix
      label.upcase.gsub(/[^A-Z]/, '_') + '_'
    end

    # @return [String] A string suitable for debugging.
    #
    def inspect
      "<#{self.class} name=#{name} platform=#{platform}>"
    end

    #-------------------------------------------------------------------------#

    # @!group Information storage

    # @return [Platform] the platform for this library.
    #
    def platform
      @platform ||= target_definition.platform
    end

    # @return [Hash{String=>Symbol}] A hash representing the user build
    #         configurations where each key corresponds to the name of a
    #         configuration and its value to its type (`:debug` or `:release`).
    #
    attr_accessor :user_build_configurations

    #-------------------------------------------------------------------------#

    # @!group Support files

    # @return [Pathname] the folder where to store the support files of this
    #         library.
    #
    def support_files_root
      @sandbox.library_support_files_dir(name)
    end

    # @return [Pathname] the absolute path of the xcconfig file.
    #
    def xcconfig_path
      support_files_root + "#{label}.xcconfig"
    end

    # @return [Pathname] the absolute path of the private xcconfig file.
    #
    def xcconfig_private_path
      support_files_root + "#{label}-Private.xcconfig"
    end

    # @return [Pathname] the absolute path of the header file which contains
    #         the information about the installed pods.
    #
    def target_environment_header_path
      support_files_root + "#{target_definition.label.to_s}-environment.h"
    end

    # @return [Pathname] the absolute path of the prefix header file.
    #
    def prefix_header_path
      support_files_root + "#{label}-prefix.pch"
    end

    # @return [Pathname] the absolute path of the bridge support file.
    #
    def bridge_support_path
      support_files_root + "#{label}.bridgesupport"
    end

    # @return [Pathname] the path of the dummy source generated by CocoaPods
    #
    def dummy_source_path
      support_files_root + "#{label}-dummy.m"
    end

  end

  #---------------------------------------------------------------------------#

  class PodTarget < AbstractTarget

    # @param [TargetDefinition] target_definition @see target_definition
    # @param [Sandbox] sandbox @see sandbox
    #
    def initialize(target_definition, sandbox)
      @target_definition = target_definition
      @sandbox = sandbox
      @libraries = []
      @file_accessors = []
    end

    # @return [String] the label for the library.
    #
    def label
      target_definition.label.to_s
    end

    # @return [Pathname] the folder where the client is stored used for
    #         computing the relative paths. If integrating it should be the
    #         folder where the user project is stored, otherwise it should
    #         be the installation root.
    #
    attr_accessor :client_root

    # @return [Pathname] the path of the user project that this library will
    #         integrate as identified by the analyzer.
    #
    # @note   The project instance is not stored to prevent editing different
    #         instances.
    #
    attr_accessor :user_project_path

    # @return [String] the list of the UUIDs of the user targets that will be
    #         integrated by this library as identified by the analizer.
    #
    # @note   The target instances are not stored to prevent editing different
    #         instances.
    #
    attr_accessor :user_target_uuids

    # @return [Xcodeproj::Config] the configuration file of the library
    #
    # @note   The configuration is generated by the {TargetInstaller} and
    #         used by {UserProjectIntegrator} to check for any overridden
    #         values.
    #
    attr_accessor :xcconfig

    # @return [Array<SpecTarget>] the dependencies for this target (or library).
    #
    attr_accessor :libraries

    # @return [Pathname] the absolute path of acknowledgements file.
    #
    # @note   The acknowledgements generators add the extension according to
    #         the file type.
    #
    def acknowledgements_basepath
      support_files_root + "#{label}-acknowledgements"
    end

    # @return [Pathname] the absolute path of the copy resources script.
    #
    def copy_resources_script_path
      support_files_root + "#{label}-resources.sh"
    end

    # @return [String] The xcconfig path of the root from the `$(SRCROOT)`
    #         variable of the user's project.
    #
    def relative_pods_root
      "${SRCROOT}/#{support_files_root.relative_path_from(client_root)}"
    end

    # @return [String] the path of the xcconfig file relative to the root of
    #         the user project.
    #
    def xcconfig_relative_path
      relative_to_srcroot(xcconfig_path).to_s
    end

    # @return [String] the path of the copy resources script relative to the
    #         root of the user project.
    #
    def copy_resources_script_relative_path
      "${SRCROOT}/#{relative_to_srcroot(copy_resources_script_path)}"
    end

    #-------------------------------------------------------------------------#

    # @!group Private Helpers

    private

    # Computes the relative path of a sandboxed file from the `$(SRCROOT)`
    # variable of the user's project.
    #
    # @param  [Pathname] path
    #         A relative path from the root of the sandbox.
    #
    # @return [String] the computed path.
    #
    def relative_to_srcroot(path)
      path.relative_path_from(client_root).to_s
    end

  end

  #---------------------------------------------------------------------------#

  class SpecTarget < AbstractTarget

    # @return [Specification] the spec for the target.
    #
    attr_reader :spec

    # @return [HeadersStore] the header directory for the library.
    #
    attr_reader :build_headers

    # @param [Specification] spec @see spec
    # @param [TargetDefinition] target_definition @see target_definition
    # @param [Sandbox] sandbox @see sandbox
    #
    def initialize(spec, target_definition, sandbox)
      @spec = spec
      @target_definition = target_definition
      @sandbox = sandbox
      @build_headers  = Sandbox::HeadersStore.new(sandbox, "BuildHeaders")
      @file_accessors = []
    end

    # @return [String] the label for the library.
    #
    def label
      "#{target_definition.label.to_s}-#{spec.name.gsub('/', '-')}"
    end

    # @return [Specification] the specification for this library.
    #
    attr_accessor :spec

    # @return [Array<Sandbox::FileAccessor>] the file accessors for the
    #         specifications of this library.
    #
    attr_accessor :file_accessors

    #--------------------------------------#

    # @return [Specification::Consumer] the specification consumer for the
    #         library.
    #
    def consumer
      spec.consumer(platform)
    end

  end

  #---------------------------------------------------------------------------#

end
