# encoding: UTF-8
require_relative 'helper/podfile_options'
require_relative 'tool/tool'

module Pod
    class Podfile
        module DSL
            def set_local_frameworks_cache_path(path)
                DSL.local_frameworks_cache_path = path
            end
            # Enable prebuiding for all pods
            # it has a lower priority to other xlbuild settings
            def use_dynamic_binary!
                DSL.prebuild_all = true
                DSL.static_binary = false
                DSL.dont_remove_source_code = true
            end
            # 设置当前swift版本
            def use_swift_version(version)
                DSL.swift_version = version
            end

            # 设置是否使用静态库
            def use_static_binary!
                DSL.prebuild_all = true
                DSL.static_binary = true
                DSL.dont_remove_source_code = true
            end

            # 设置是否保存源码，默认 true
            def remove_source_code_for_prebuilt_frameworks!
                DSL.dont_remove_source_code = false
            end

            # Enable bitcode for prebuilt frameworks
            def enable_bitcode_for_prebuilt_frameworks!
                DSL.bitcode_enabled = true
            end

            # Add custom xcodebuild option to the prebuilding action
            #
            # You may use this for your special demands. For example: the default archs in dSYMs
            # of prebuilt frameworks is 'arm64 armv7 x86_64', and no 'i386' for 32bit simulator.
            # It may generate a warning when building for a 32bit simulator. You may add following
            # to your podfile
            #
            #  ` set_custom_xcodebuild_options_for_prebuilt_frameworks :simulator => "ARCHS=$(ARCHS_STANDARD)" `
            #
            # Another example to disable the generating of dSYM file:
            #
            #  ` set_custom_xcodebuild_options_for_prebuilt_frameworks "DEBUG_INFORMATION_FORMAT=dwarf"`
            #
            #
            # @param [String or Hash] options
            #
            #   If is a String, it will apply for device and simulator. Use it just like in the commandline.
            #   If is a Hash, it should be like this: { :device => "XXXXX", :simulator => "XXXXX" }
            #
            def set_custom_xcodebuild_options_for_prebuilt_frameworks(options)
                if options.kind_of? Hash
                    DSL.custom_build_options = [ options[:device] ] unless options[:device].nil?
                    DSL.custom_build_options_simulator = [ options[:simulator] ] unless options[:simulator].nil?
                elsif options.kind_of? String
                    DSL.custom_build_options = [options]
                    DSL.custom_build_options_simulator = [options]
                else
                    raise "Wrong type."
                end
            end

            private
            class_attr_accessor :prebuild_all
            prebuild_all = false

            class_attr_accessor :swift_version
            swift_version = "5.0"   # swift版本默认5.0

            class_attr_accessor :static_binary
            static_binary = false

            class_attr_accessor :bitcode_enabled
            bitcode_enabled = false

            class_attr_accessor :dont_remove_source_code
            dont_remove_source_code = true

            class_attr_accessor :custom_build_options
            class_attr_accessor :custom_build_options_simulator

            class_attr_accessor :local_frameworks_cache_path
            local_frameworks_cache_path = nil

            self.custom_build_options = []
            self.custom_build_options_simulator = []
        end
    end

    class Type
        class_attr_accessor :pod_flag_file
        @pod_flag_file = "build.xl"

        def self.frameworks_type
            is_static_binary = Pod::Podfile::DSL.static_binary
            frameworks_type = is_static_binary ? "static" : "dynamic"
            return frameworks_type
        end

        # 动静态库切换时候需要重新build（删除Pod目录重新构建）
        def self.adjust_dynamic_static_change_pod(standard_sandbox)
            # 动|静态库(mach-o type)切换需要重新build（删除Pod/_Prebuild目录）
            _prebuild_sandbox = Pod::PrebuildSandbox.from_standard_sandbox(standard_sandbox)
            _pod_prebuild_root_path = _prebuild_sandbox.root
            is_pod_prebuild_root_path_exist = File.exist?(_pod_prebuild_root_path)

            pod_root_path = standard_sandbox.root
            pod_type_path = pod_root_path+Pod::Type.pod_flag_file
            if not File.exist?(pod_type_path) and is_pod_prebuild_root_path_exist
                FileUtils.remove_dir(_pod_prebuild_root_path)
            else
                frameworks_type = Pod::Type.frameworks_type
                aFile = File.new(pod_type_path, "r")
                if aFile
                    content = aFile.readlines[0]
                    if not frameworks_type.eql?(content) and is_pod_prebuild_root_path_exist
                        FileUtils.remove_dir(_pod_prebuild_root_path)
                    end
                end

            end

        end

        #构建结束 标记当前打包的是动|静态库
        def self.adjust_dynamic_static_change_pod_finish(standard_sandbox)
            # 标记状态
            pod_root_path = standard_sandbox.root
            pod_type_path = pod_root_path+Pod::Type.pod_flag_file
            if File.exist?(pod_type_path)
                File.delete(pod_type_path)
            end

            frameworks_type = Pod::Type.frameworks_type
            File.open(pod_type_path, "w+") { |f|
                f.write(frameworks_type)
            }
        end
    end
end

Pod::HooksManager.register('cocoapods-xlbuild', :pre_install) do |installer_context|
    require_relative 'helper/feature_switches'
    if Pod.is_prebuild_stage
        next
    end

    # [Check Environment]
    # check user_framework is on
    podfile = installer_context.podfile
    podfile.target_definition_list.each do |target_definition|
        next if target_definition.prebuild_framework_pod_names.empty?
        if not target_definition.uses_frameworks?
            STDERR.puts "[!] cocoapods-xlbuild requires `use_frameworks!`".red
            exit
        end
    end

    # -- step 1: prebuild framework ---
    # Execute a sperated pod install, to generate targets for building framework,
    # then compile them to framework files.
    require_relative 'helper/prebuild_sandbox'

    #Prebuild里面hooke了run_plugins_post_install_hooks方法
    require_relative 'Prebuild'

    # Pod::UI.puts "火速编译中..."

    # Fetch original installer (which is running this pre-install hook) options,
    # then pass them to our installer to perform update if needed
    # Looks like this is the most appropriate way to figure out that something should be updated

    update = nil
    repo_update = nil

    include ObjectSpace
    ObjectSpace.each_object(Pod::Installer) { |installer|
        update = installer.update
        repo_update = installer.repo_update
    }

    # control features
    Pod.is_prebuild_stage = true
    Pod::Podfile::DSL.enable_prebuild_patch true  # enable sikpping for prebuild targets
    Pod::Installer.force_disable_integration true # don't integrate targets
    Pod::Config.force_disable_write_lockfile true # disbale write lock file for perbuild podfile
    Pod::Installer.disable_install_complete_message true # disable install complete message

    # make another custom sandbox
    standard_sandbox = installer_context.sandbox
    #linpeng edit： 修改Pod目录为 Pod/_Prebuild
    prebuild_sandbox = Pod::PrebuildSandbox.from_standard_sandbox(standard_sandbox)

    # 动|静态库(mach-o type)切换需要重新build（删除Pod/_Prebuild目录）
    Pod::Type.adjust_dynamic_static_change_pod standard_sandbox

    # get the podfile for prebuild
    prebuild_podfile = Pod::Podfile.from_ruby(podfile.defined_in_file)

    # install
    lockfile = installer_context.lockfile
    binary_installer = Pod::Installer.new(prebuild_sandbox, prebuild_podfile, lockfile)

    require_relative 'Integration'
    # Prebuild文件里面也扩展了 Pod::Installer类，同时新增扩展了have_exact_prebuild_cache?方法
    if binary_installer.have_exact_prebuild_cache? && !update
        binary_installer.install_when_cache_hit!
    else
        binary_installer.update = update
        binary_installer.repo_update = repo_update
        binary_installer.install!
    end

    ##备注上面的install是同步执行的，工程hook了 pod 的方法使得其会先下载源码然后进行xcodebuild编译 编译晚
    #之后才会往下走

    # reset the environment
    Pod.is_prebuild_stage = false
    Pod::Installer.force_disable_integration false
    Pod::Podfile::DSL.enable_prebuild_patch false
    Pod::Config.force_disable_write_lockfile false
    Pod::Installer.disable_install_complete_message false
    Pod::UserInterface.warnings = [] # clean the warning in the prebuild step, it's duplicated.


    # install完成标记mach-o type
    Pod::Type.adjust_dynamic_static_change_pod_finish standard_sandbox

    # -- step 2: pod install ---
    # install
    Pod::UI.puts "🤖  Pod Install "
    # go on the normal install step ...

end

## pod 安装依赖的时候会执行install，install的时候会执行run_plugins_post_install_hooks（Prebuildhook了该方法）
# 只要有触发install方法就会触发如下的 ，pre hook的时候有重新创建一个Install( binary_installer.install!)因此会触发两次的post_install的hook
Pod::HooksManager.register('cocoapods-xlbuild', :post_install) do |installer_context|
    if Pod::Podfile::DSL.static_binary
        Pod::PrebuildSandbox.replace_tagert_copy_source_sh(installer_context)
    end

    if !Pod.is_prebuild_stage && Pod::Podfile::DSL.dont_remove_source_code
        require_relative 'reference/reference_source_code'
        installer_context.refrence_source_code
        installer_context.adjust_dynamic_framework_dsym
    end
end

