#
# Copyright (c) 2008-2021 the Urho3D project.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#

task default: :build

desc 'Show info for the specified target platform'
task :info, [:kind] => [:init] do |_, args|
  case args[:kind]
  when 'build_tree'
    print build_tree
  when 'install_dir'
    print install_dir
  else
    abort %q{Please specify the type of info requested: 'build_tree', 'install_dir'}
  end
end

desc 'Invoke CMake to configure and generate a build tree'
task :cmake => [:init] do
  if ENV['CI']
    system 'cmake --version' or abort 'Failed to find CMake'
    if ENV['USE_CCACHE'] && ENV['GITHUB_EVENT_NAME'] != 'repository_dispatch' && /\[cache clear\]/ =~ `git log --format=%B -n1 2>/dev/null`
      system 'bash', '-c', 'rm -rf ~/.{ccache,gradle}' or abort 'Failed to clear the build cache'
    end
  end
  next if ENV['PLATFORM'] == 'android' || (Dir.exists?(build_tree) and not ARGV.include?('cmake'))
  ['CMAKE_INSTALL_PREFIX', 'URHO3D_HOME'].each { |var|
    if ENV[var] == 'system'
      ENV.delete(var)
    elsif !ENV[var]
      ENV[var] = install_dir if var == 'CMAKE_INSTALL_PREFIX' || Dir.exists?(install_dir)
    end
  }
  script = "script/cmake_#{ENV['GENERATOR']}#{ENV['OS'] ? '.bat' : '.sh'}"
  build_options = /linux|macOS|win/ =~ ENV['PLATFORM'] ? '' : "-D #{ENV['PLATFORM'].upcase}=1"
  File.readlines('script/.build-options').each { |var|
    var.chomp!
    build_options = "#{build_options} -D #{var}=#{ENV[var]}" if ENV[var]
  }
  system %Q{#{script} "#{build_tree}" #{build_options}} or abort
end

desc 'Clean the build tree'
task :clean => [:init] do
  if ENV['PLATFORM'] == 'android'
    Rake::Task[:gradle].invoke('clean')
    next
  end
  system build_target('clean') or abort
end

desc 'Build the software'
task :build, [:target] => [:cmake] do |_, args|
  system "ccache -z" if ENV['USE_CCACHE']
  if ENV['PLATFORM'] == 'android'
    Rake::Task[:gradle].invoke('build -x test')
    system "ccache -s" if ENV['USE_CCACHE']
    next
  end
  filter = ''
  case ENV['GENERATOR']
  when 'xcode'
    concurrent = '' # Assume xcodebuild will do the right things without the '-jobs'
    filter = '|xcpretty -c && exit ${PIPESTATUS[0]}' if system('xcpretty -v >/dev/null 2>&1')
  when 'vs'
    concurrent = '/maxCpuCount'
  else
    concurrent = "-j #{$max_jobs}"
    filter = "2>#{lint_err_file}" if ENV['URHO3D_LINT']
  end
  system "#{build_target(args[:target])} -- #{concurrent} #{ENV['BUILD_PARAMS']} #{filter}" or abort
  system "ccache -s" if ENV['USE_CCACHE']
end

desc 'Test the software'
task :test => [:init] do
  if ENV['PLATFORM'] == 'android'
    Rake::Task[:gradle].invoke('test')
    next
  elsif ENV['URHO3D_LINT'] == '1'
    Rake::Task[:lint].invoke
    next
  elsif ENV['URHO3D_STYLE'] == '1'
    Rake::Task[:style].invoke
    next
  end
  wrapper = ENV['CI'] && ENV['PLATFORM'] == 'linux' ? 'xvfb-run' : ''
  test = /xcode|vs/ =~ ENV['GENERATOR'] ? 'RUN_TESTS' : 'test'
  system build_target(test, wrapper) or abort
end

desc 'Generate documentation'
task :doc => [:init] do
  if ENV['PLATFORM'] == 'android'
    Rake::Task[:gradle].invoke('documentationZip')
    next
  end
  system build_target('doc') or abort
end

desc 'Install the software'
task :install, [:dest_dir] => [:init] do |_, args|
  if ENV['PLATFORM'] == 'android'
    Rake::Task[:gradle].invoke('publishToMavenLocal')
    next
  end
  wrapper = args[:dest_dir] && !ENV['OS'] ? "DESTDIR=#{verify_path(args[:dest_dir], true)}" : ''
  system build_target('install', wrapper) or abort
end

desc 'Package build artifact'
task :package => [:init] do
  next if ENV['PLATFORM'] == 'android'
  wrapper = /linux|rpi|arm/ =~ ENV['PLATFORM'] && ENV['URHO3D_64BIT'] == '0' ? 'setarch i686' : ''
  system build_target('package', wrapper) or abort
end

desc 'Publish build artifact'
task :publish => [:init] do
  if ENV['PLATFORM'] == 'android'
    Rake::Task[:gradle].invoke("publish #{/refs\/tags\// =~ ENV['GITHUB_REF'] ? 'bintrayUpload' : ''}")
    next
  end
  Rake::Task[$publish_task.to_sym].invoke if $publish_task
end

desc 'Create a new project'
task :new, [:name, :parent_dir, :use_copy] => [:init] do |_, args|
  abort 'The "new" task can only be invoked in the Urho3D project root!' unless first_match(/^# (Urho3D)$/, 'README.md')
  args.with_defaults(:name => 'UrhoApp', :parent_dir => '~/projects', :use_copy => false)
  name = args[:name]
  parent_dir = verify_path(args[:parent_dir])
  dir = "#{parent_dir}/#{name}"
  use_copy = args[:use_copy] || dockerized?
  abort "The directory '#{dir}' already exists!" if Dir.exists?(dir)
  puts "Creating a new project in #{dir}..."
  func = FileUtils.method(use_copy ? :cp_r : :ln_s)
  source_tree(name).split("\n").each do |it|
    dirname, basename = /\// =~ it.split(/\s*<-\s*/).first ? it.match(/([^\s<]+)\/(.+)/).captures : ['.', it]
    FileUtils.mkdir_p("#{dir}/#{dirname}")
    if (matched = basename.match(/(?<basename>\S+)\s*<-\s*:(?<symbol>\S+)/))
      File.write("#{dir}/#{dirname}/#{matched[:basename]}", method(matched[:symbol].to_sym).call(name))
    elsif (matched = basename.match(/(?<basename>\S+)\s*<-\s*(?<dirname>\S+)/))
      func.call(verify_path("#{matched[:dirname]}/#{matched[:basename]}"), "#{dir}/#{dirname}")
    else
      func.call(verify_path(it), "#{dir}/#{dirname}")
    end
  end
  puts "Done!"
end


### Internal tasks ###

task :check_license do
  commit = 0
  # Automatically bump copyright when crossing a new year
  if /2008-([0-9]{4}) the Urho3D project/.match(File.read('rakefile'))[1].to_i != Time.now.year
    system %Q{
      git config user.name #{ENV['PUBLISHER_NAME']} && \\
      git config user.email #{ENV['PUBLISHER_EMAIL']} && \\
      git add #{bump_copyright_year.join ' '} && \\
      git commit -qm 'GH Actions: Bump copyright year to #{Time.now.year}.\n[cache clear]'
    } or abort "Failed to commit copyright year update"
    commit = 1
  end
  # TODO: Check and merge any new 3rd-party license into 'Source/ThirdParty/LICENSES'
  puts "::set-output name=commit::#{commit}"
end

task :ci do
  ENV['URHO3D_PCH'] = '0' if ENV['PLATFORM'] == 'linux-gcc' # TODO - PCH causes cache miss on initial build for Linux/GCC, why?
  platform_modifier = /(.+?)-(.+)/.match(ENV['PLATFORM'])
  if platform_modifier
    ENV['PLATFORM'] = platform_modifier[1]
    ENV['MODIFIER'] = platform_modifier[2]
  end
  case ENV['HOST']
  when 'linux'
    ENV['URHO3D_DEPLOYMENT_TARGET'] = 'generic' if /linux|mingw/ =~ ENV['PLATFORM']
    if ENV['MODIFIER'] == 'clang'
      ENV['CC'] = 'clang'
      ENV['CXX'] = 'clang++'
    end
  when 'windows'
    if ENV['MODIFIER'] == 'gcc'
      ENV['URHO3D_DEPLOYMENT_TARGET'] = 'generic'
      ENV['GENERATOR'] = 'mingw'
    end
  else
    # Do nothing
  end
  ENV['BUILD_TREE'] = 'build/ci'
  ENV['CMAKE_BUILD_TYPE'] = ENV['BUILD_TYPE'] == 'dbg' ? 'Debug' : 'Release' if /dbg|rel/ =~ ENV['BUILD_TYPE']
  case ENV['GRAPHICS_API']
  when 'DX11'
    ENV['URHO3D_D3D11'] = '1'
  when 'DX9'
    ENV['URHO3D_OPENGL'] = '0' # Need to make this explicit because 'MINGW' default to use OpenGL otherwise
  when 'OpenGL'
    ENV['URHO3D_OPENGL'] = '1'
  else
    # Do nothing
  end
  case ENV['PLATFORM']
  when 'web'
    ENV['EMSCRIPTEN_SHARE_DATA'] = '1'
    $max_jobs = 1 if ENV['BUILD_TYPE'] == 'dbg'
    $publish_task = 'ci_publish_web'
  else
    # Do nothing
  end
  ENV['URHO3D_LIB_TYPE'] = ENV['LIB_TYPE'].upcase if /static|shared/ =~ ENV['LIB_TYPE']
  ENV['URHO3D_TESTING'] = '1' if /linux|macOS|win/ =~ ENV['PLATFORM']
  ENV['URHO3D_LINT'] = '1' if ENV['MODIFIER'] == 'clang-tidy'
  ENV['URHO3D_STYLE'] = '1' if ENV['MODIFIER'] == 'clang-format'
  # Enable all the bells and whistles
  %w[URHO3D_DATABASE_SQLITE URHO3D_EXTRAS].each { |it| ENV[it] = '1' }
end

task :ci_publish_web do
  require 'json'
  system 'git clone --depth 1 -q https://github.com/urho3d/urho3d.github.io.git build/urho3d.github.io' or abort 'Failed to clone urho3d/urho3d.github.io'
  system "rsync -a --delete --exclude tool --exclude *.pak --exclude index.md build/ci/bin/ build/urho3d.github.io/samples" or abort 'Failed to rsync Web samples'
  Dir.chdir('build/urho3d.github.io/samples') {
    next unless system 'git diff --quiet Urho3D.js.data'
    uuid = `git diff --color=never --word-diff-regex='\\w+' --word-diff=porcelain Urho3D.js`.split.grep(/^[+-]\w+-/).map { |it| it[0] = ''; it }
    system %Q(ruby -i.bak -pe "gsub '#{uuid.last}', '#{uuid.first}'" Urho3D.js) or abort 'Failed to substitute UUID'
    if system 'git diff --quiet Urho3D.js'
      File.unlink 'Urho3D.js.bak'
      Dir['*.js'].each { |file| system %Q(ruby -i -pe "gsub '#{uuid.last}', '#{uuid.first}'" #{file}) }
    else
      File.rename 'Urho3D.js.bak', 'Urho3D.js'
    end
  }
  web = {'samples' => {}}
  Dir.chdir('build/urho3d.github.io/samples') { web['samples']['Native'] = Dir['*.html'].sort }
  web['player'] = web['samples']['Native'].pop # Assume the last sample after sorting is the Urho3DPlayer.html
  {'AngelScript' => 'Scripts', 'Lua' => 'LuaScripts'}.each { |lang, subdir|
    Dir.chdir("bin/Data/#{subdir}") {
      script_samples = Dir['[0-9]*'].sort
      deleted_samples = [] # Delete samples that do not have their native counterpart
      script_samples.each { |sample| deleted_samples.push sample unless web['samples']['Native'].include? "#{sample.split('.').first}.html" }
      web['samples'][lang] = (script_samples - deleted_samples).map { |sample| "#{subdir}/#{sample}" }
    }
  }
  File.open('build/urho3d.github.io/_data/web.json', 'w') { |file| file.puts web.to_json }
  system %Q{
    cd build/urho3d.github.io && \\
    git config user.name #{ENV['PUBLISHER_NAME']} && \\
    git config user.email #{ENV['PUBLISHER_EMAIL']} && \\
    git remote set-url --push origin https://#{ENV['PUBLISHER_TOKEN']}@github.com/urho3d/urho3d.github.io.git && \\
    git add -A . && \\
    ( git commit -qm "GH Actions: Web samples update at #{Time.now.utc}.\n\nCommit: https://github.com/#{ENV['GITHUB_REPOSITORY']}/commit/#{ENV['GITHUB_SHA']}\n\nMessage: #{`git log --format=%B -n 1`}" || true) && \\
    git push -q >/dev/null 2>&1
  } or abort 'Failed to update Web samples'
end

task :gradle, [:task] do |_, args|
  system "#{ENV['OS'] ? 'gradlew.bat' : './gradlew'} #{args[:task]} #{ENV['CI'] ? '--console plain' : ''}" or abort
end

task :init do
  next if $max_jobs
  Rake::Task[:ci].invoke if ENV['CI']
  case build_host
  when /linux/
    $max_jobs = `grep -c processor /proc/cpuinfo`.chomp unless $max_jobs
    ENV['GENERATOR'] = 'generic' unless ENV['GENERATOR']
    unless ENV['PLATFORM']
      if /x86/ =~ `uname -m`
        ENV['PLATFORM'] = 'linux'
      elsif Dir.exists?('/opt/vc')
        ENV['PLATFORM'] = 'rpi'
      else
        ENV['PLATFORM'] = 'arm'
      end
    end
  when /darwin|macOS/
    $max_jobs = `sysctl -n hw.logicalcpu`.chomp unless $max_jobs
    ENV['GENERATOR'] = 'xcode' unless ENV['GENERATOR']
    ENV['PLATFORM'] = 'macOS' unless ENV['PLATFORM']
  when /win32|mingw|mswin|windows/
    unless $max_jobs
      require 'win32ole'
      WIN32OLE.connect('winmgmts://').ExecQuery("select NumberOfLogicalProcessors from Win32_ComputerSystem").each { |it|
        $max_jobs = it.NumberOfLogicalProcessors
      }
    end
    ENV['GENERATOR'] = 'vs' unless ENV['GENERATOR']
    ENV['PLATFORM'] = 'win' unless ENV['PLATFORM']
  else
    abort "Unsupported host system: #{build_host}"
  end
  # The 'ARCH' env-var, when set, has higher precedence than the 'URHO3D_64BIT' env-var
  ENV['URHO3D_64BIT'] = ENV['ARCH'] == '32' ? '0' : '1' if /32|64/ =~ ENV['ARCH']
end

task :lint do
  lint_err = File.read(lint_err_file)
  puts lint_err
  # TODO: Tighten the check by failing the job later
  # abort 'Failed to pass linter checks' unless lint_err.empty?
  # puts 'Passed the linter checks'
end

task :style do
  system 'bash', '-c', %q{
    git diff --name-only HEAD~ -- Source \
      |grep -v ThirdParty \
      |grep -P '\.(?:c|cpp|h|hpp)' \
      |xargs clang-format -n -Werror 2>&1 \
      |tee build/clang-format.out \
      && exit ${PIPESTATUS[3]}
  } or abort 'Failed to pass style checks'
  puts 'Passed the style checks'
end

task :source_checksum do
  require 'digest'
  sha256_final = Digest::SHA256.new
  sha256_iter = Digest::SHA256
  Dir['Source/**/*.{c,h}*'].each { |it| sha256_final << sha256_iter.file(it).hexdigest }
  puts "::set-output name=hexdigest::#{sha256_final.hexdigest}"
end

task :update_dot_files do
  system 'bash', '-c', %q{
    perl -ne 'undef $/; print $1 if /(Build Option.*?(?=\n\n))/s' Docs/GettingStarted.dox \
      |tail -n +3 |cut -d'|' -f2 |tr -d [:blank:] >script/.build-options && \
    echo URHO3D_LINT >>script/.build-options && \
    cat script/.build-options <(perl -ne 'while (/([A-Z_]+):.+?/g) {print "$1\n"}' .github/workflows/main.yml) \
      <(perl -ne 'while (/ENV\[\x27(\w+)\x27\]/g) {print "$1\n"}' rakefile) \
      <(perl -ne 'while (/System.getenv\\("(\w+)"\\)/g) {print "$1\n"}' android/urho3d-lib/build.gradle.kts) \
      |sort |uniq |grep -Ev '^(HOME|PATH)$' >script/.env-file
  } or abort 'Failed to update dot files'
  if /schedule|workflow_dispatch/ =~ ENV['GITHUB_EVENT_NAME']
    system %Q{
      git config user.name #{ENV['PUBLISHER_NAME']} && \\
      git config user.email #{ENV['PUBLISHER_EMAIL']} && \\
      git add script/.build-options script/.env-file && \\
      commit=0 && \\
      if git commit -qm 'GH Actions: Update dot files for DBE.'; then commit=1; fi && \\
      echo ::set-output name=commit::$commit
    } or abort "Failed to commit dot files update"
  end
end


### Internal methods ###

def build_host
  ENV['HOST'] || RUBY_PLATFORM
end

def build_tree
  ENV['BUILD_TREE'] || "build/#{dockerized? ? 'dockerized-' : ''}#{default_path}"
end

def build_config
  /xcode|vs/ =~ ENV['GENERATOR'] ? "--config #{ENV.fetch('CONFIG', 'Release')}" : ''
end

def build_target(tgt, wrapper = '')
  %Q{#{wrapper} cmake --build "#{build_tree}" #{build_config} #{tgt ? "--target #{tgt}" : ''}}
end

def bump_copyright_year(regex = '2008-[0-9]{4} the Urho3D project')
  begin
    copyrighted = `git grep -El '#{regex}'`.split
    copyrighted.each { |filename|
      replaced_content = File.read(filename).gsub(/#{regex}/, regex.gsub('[0-9]{4}', Time.now.year.to_s))
      File.open(filename, 'w') { |file| file.puts replaced_content }
    }
    return copyrighted
  rescue
    abort 'Failed to bump copyright year'
  end
end

def default_path
  "#{ENV['PLATFORM'].downcase}" \
  "#{ENV['CC'] ? "-#{ENV['CC']}" : ''}" \
  "#{ENV['GENERATOR'] && /generic|xcode|vs/ =~ ENV['GENERATOR'] ? '' : "-#{ENV['GENERATOR']}"}"
end

def dockerized?
  File.exists?('/entrypoint.sh')
end

def install_dir
  "#{Dir.home}/.urho3d/install/#{default_path}"
end

def lint_err_file
  'build/clang-tidy.out'
end

def verify_path(path, auto_create = false)
  require 'pathname'
  begin
    expanded_path = File.expand_path(path)
    FileUtils.mkdir_p(expanded_path) if (auto_create && !Dir.exists?(expanded_path))
    Pathname.new(expanded_path).realdirpath.to_s
  rescue
    abort "The specified path '#{path}' is invalid!"
  end
end

def first_match(regex, from)
  begin
    if from.instance_of?(Array)
      array = from
    else
      array = File.exists?(from) ? File.readlines(from) : from.split("\n")
    end
    array.grep(regex).first.match(regex).captures.first
  rescue
    nil
  end
end

def source_tree(name)
  <<-EOF
bin/CoreData
bin/Data/Materials/Mushroom.xml
bin/Data/Models/Mushroom.mdl
bin/Data/Music/Ninja Gods.ogg
bin/Data/Textures/Mushroom.dds
bin/Data/Textures/UrhoIcon.icns
bin/Data/Textures/UrhoIcon.png
cmake
gradle
script
app/src/main/cpp/#{name}.cpp <- :urho_app_cpp
app/src/main/cpp/#{name}.h <- :urho_app_h
app/src/main/java/io/urho3d/#{name.downcase}/MainActivity.kt <- :main_activity_kt
#{Dir.chdir('android/launcher-app') { Dir['src/main/res/{drawable,mipmap}*'].map { |it| "app/#{it} <- android/launcher-app/src/main/res" }.join("\n") }}
app/src/main/res/values/strings.xml <- :strings_xml
app/src/main/AndroidManifest.xml <- :android_manifest_xml
app/build.gradle.kts <- :app_build_gradle_kts
app/CMakeLists.txt <- :app_cmake_lists_txt
app/proguard-rules.pro <- android/launcher-app
build.gradle.kts <- :root_build_gradle_kts
CMakeLists.txt <- :root_cmake_lists_txt
gradle.properties
gradlew
gradlew.bat
rakefile
settings.gradle.kts <- :settings_gradle_kts
.clang-format
.clang-tidy
.gitattributes <- :gitattributes
.gitignore <- :gitignore
  EOF
end

def settings_gradle_kts(name)
  <<-EOF
rootProject.name = "#{name}"
include(":app")
  EOF
end

def app_build_gradle_kts(name)
  template = File.readlines('android/launcher-app/build.gradle.kts')
  sdk_version = first_match(/compileSdkVersion\((\d+)\)/, template)
  min_sdk_version = first_match(/minSdkVersion\((\d+)\)/, template)
  aar_version = ENV['CI'] && ENV['PLATFORM'] != 'android' ? 'unknown' : # Skip using gradle all together when on CI, unless for Android build
                    first_match(/AAR version: (.+)/, `#{ENV['OS'] ? 'gradlew.bat' : './gradlew'} aarVersion 2>#{ENV['OS'] ? 'null' : '/dev/null'}`)
  type = ENV.fetch('URHO3D_LIB_TYPE', 'STATIC').downcase
  <<-EOF
plugins {
    id("com.android.application")
    kotlin("android")
    kotlin("android.extensions")
}

val kotlinVersion: String by ext
val ndkSideBySideVersion: String by ext
val cmakeVersion: String by ext
val buildStagingDir: String by ext

android {
    ndkVersion = ndkSideBySideVersion
    compileSdkVersion(#{sdk_version})
    defaultConfig {
        minSdkVersion(#{min_sdk_version})
        targetSdkVersion(#{sdk_version})
        applicationId = "io.urho3d.#{name}"
        versionCode = 1
        versionName = "1.0"
        testInstrumentationRunner = "android.support.test.runner.AndroidJUnitRunner"
        externalNativeBuild {
            cmake {
                arguments.apply {
                    System.getenv("ANDROID_CCACHE")?.let { add("-D ANDROID_CCACHE=$it") }
                    add("-D JNI_DIR=${project.file(buildStagingDir)}")
                    // Pass along matching env-vars as CMake build options
                    addAll(project.file("../script/.build-options")
                        .readLines()
                        .mapNotNull { variable -> System.getenv(variable)?.let { "-D $variable=$it" } }
                    )
                }
            }
        }
        splits {
            abi {
                isEnable = project.hasProperty("ANDROID_ABI")
                reset()
                include(
                    *(project.findProperty("ANDROID_ABI") as String? ?: "")
                        .split(',')
                        .toTypedArray()
                )
            }
        }
    }
    buildTypes {
        named("release") {
            isMinifyEnabled = false
            proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
        }
    }
    lintOptions {
        isAbortOnError = false
    }
    externalNativeBuild {
        cmake {
            version = cmakeVersion
            path = project.file("../CMakeLists.txt")
            setBuildStagingDirectory(buildStagingDir)
        }
    }
    sourceSets {
        named("main") {
            assets.srcDir(project.file("../bin"))
        }
    }
}

val urhoReleaseImpl by configurations.creating { isCanBeResolved = true }
configurations.releaseImplementation.get().extendsFrom(urhoReleaseImpl)

val urhoDebugImpl by configurations.creating { isCanBeResolved = true }
configurations.debugImplementation.get().extendsFrom(urhoDebugImpl)

dependencies {
    urhoReleaseImpl("io.urho3d:urho3d-lib-#{type}:#{aar_version}")
    urhoDebugImpl("io.urho3d:urho3d-lib-#{type}-debug:#{aar_version}")
    implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar", "*.aar"))))
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion")
    implementation("androidx.core:core-ktx:#{first_match(/"androidx.core:core-ktx:(.+)"/, template)}")
    implementation("androidx.appcompat:appcompat:#{first_match(/"androidx.appcompat:appcompat:(.+)"/, template)}")
    implementation("androidx.constraintlayout:constraintlayout:#{first_match(/"androidx.constraintlayout:constraintlayout:(.+)"/, template)}")
    testImplementation("junit:junit:#{first_match(/"junit:junit:(.+)"/, template)}")
    androidTestImplementation("androidx.test:runner:#{first_match(/"androidx.test:runner:(.+)"/, template)}")
    androidTestImplementation("androidx.test.espresso:espresso-core:#{first_match(/"androidx.test.espresso:espresso-core:(.+)"/, template)}")
}

afterEvaluate {
    android.buildTypes.forEach { buildType ->
        val config = buildType.name.capitalize()
        val unzipTaskName = "unzipJni$config"
        tasks {
            "generateJsonModel$config" {
                dependsOn(unzipTaskName)
            }
            register<Copy>(unzipTaskName) {
                val aar = configurations["urho${config}Impl"].resolve().first { it.name.startsWith("urho3d-lib") }
                from(zipTree(aar))
                include("urho3d/**")
                into(android.externalNativeBuild.cmake.buildStagingDirectory)
            }
        }
    }
}

tasks {
    register<Delete>("cleanAll") {
        dependsOn("clean")
        delete = setOf(android.externalNativeBuild.cmake.buildStagingDirectory)
    }
}
  EOF
end

def root_build_gradle_kts(_)
  template = File.readlines('build.gradle.kts')
  <<-EOF
buildscript {
    extra["kotlinVersion"] = "#{first_match(/extra\["kotlinVersion"\] = "(.+)"/, template)}"
    val kotlinVersion: String by extra
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath("com.android.tools.build:gradle:#{first_match(/"com.android.tools.build:gradle:(.+)"/, template)}")
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion")
    }
}

val kotlinVersion: String by ext

allprojects {
    repositories {
        google()
        jcenter()
        // Remove below two repos if you are only using released AAR from JCenter
        mavenLocal()
        if (System.getenv("GITHUB_ACTOR") != null && System.getenv("GITHUB_TOKEN") != null) {
            maven {
                name = "GitHubPackages"
                url = uri("https://maven.pkg.github.com/urho3d/Urho3D")
                credentials {
                    username = System.getenv("GITHUB_ACTOR")
                    password = System.getenv("GITHUB_TOKEN")
                }
            }
        }
    }
    buildscript {
        ext {
            set("kotlinVersion", kotlinVersion)
            set("ndkSideBySideVersion", "#{first_match(/set\("ndkSideBySideVersion", "(.+)"\)/, template)}")
            set("cmakeVersion", "#{first_match(/set\("cmakeVersion", "(.+)"\)/, template)}")
            set("buildStagingDir", "#{first_match(/set\("buildStagingDir", "(.+)"\)/, template)}")
        }
    }
}

tasks {
    wrapper {
        distributionType = Wrapper.DistributionType.ALL
    }
    "prepareKotlinBuildScriptModel" {
        listOf("Debug", "Release").forEach {
          dependsOn(":app:unzipJni$it")
        }
    }
    register<Delete>("clean") {
        // Clean the build artifacts generated by the Gradle build system only, but keep the buildDir
        rootProject.buildDir.listFiles { _, name -> name == "intermediates" || name == "kotlin" }?.let {
            delete = it.toSet()
        }
    }
    register<Delete>("cleanAll") {
        dependsOn("clean")
    }
}
  EOF
end

def strings_xml(name)
  <<-EOF
<resources>
    <string name="app_name">#{name}</string>
</resources>
  EOF
end

def android_manifest_xml(name)
  <<-EOF
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="io.urho3d.#{name.downcase}">

    <application
        android:allowBackup="true"
        android:hardwareAccelerated="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true">
        <activity
            android:name=".MainActivity"
            android:configChanges="keyboardHidden|orientation|screenSize"
            android:screenOrientation="landscape"
            android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>

</manifest>
  EOF
end

def main_activity_kt(name)
  <<-EOF
package io.urho3d.#{name.downcase}

import io.urho3d.UrhoActivity

class MainActivity : UrhoActivity()
  EOF
end

def app_cmake_lists_txt(name)
  <<-EOF
set(TARGET_NAME #{name})
define_source_files(GLOB_CPP_PATTERNS src/main/cpp/*.cpp GLOB_H_PATTERNS src/main/cpp/*.h RECURSE GROUP)
setup_main_executable()
setup_test()
  EOF
end

def root_cmake_lists_txt(name)
  <<-EOF
cmake_minimum_required(VERSION #{first_match(/cmake_minimum_required\s*\(VERSION (.+)\)/, 'CMakeLists.txt')})
project(#{name})

set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules)
include(UrhoCommon)

add_subdirectory(app)
  EOF
end

def urho_app_h(name)
  <<-EOF
#pragma once

#include <Urho3D/Urho3DAll.h>

class #{name} : public Application
{
    URHO3D_OBJECT(#{name}, Application);

public:
    explicit #{name}(Context* context);
    void Start() override;

private:
    SharedPtr<Scene> scene_;
};
  EOF
end

def urho_app_cpp(name)
  <<-EOF
#include "#{name}.h"

URHO3D_DEFINE_APPLICATION_MAIN(#{name})

#{name}::#{name}(Context* context) : Application(context) {}

void #{name}::Start()
{
    auto* cache = GetSubsystem<ResourceCache>();
    auto* graphics = GetSubsystem<Graphics>();
    graphics->SetWindowIcon(cache->GetResource<Image>("Textures/UrhoIcon.png"));
    graphics->SetWindowTitle("#{name}");

    scene_ = new Scene(context_);
    scene_->CreateComponent<Octree>();

    Node* objectNode = scene_->CreateChild();
    auto* object = objectNode->CreateComponent<StaticModel>();
    object->SetModel(cache->GetResource<Model>("Models/Mushroom.mdl"));
    object->SetMaterial(cache->GetResource<Material>("Materials/Mushroom.xml"));

    auto* sound = scene_->CreateComponent<SoundSource>();
    sound->SetSoundType(SOUND_MUSIC);
    auto* music = cache->GetResource<Sound>("Music/Ninja Gods.ogg");
    music->SetLooped(true);
    sound->Play(music);

    Node* lightNode = scene_->CreateChild();
    auto* light = lightNode->CreateComponent<Light>();
    light->SetLightType(LIGHT_DIRECTIONAL);
    lightNode->SetDirection(Vector3(0.6f, -1.f, 0.8f));

    Node* cameraNode = scene_->CreateChild();
    auto* camera = cameraNode->CreateComponent<Camera>();
    cameraNode->SetPosition(Vector3(0.f, 0.3f, -3.f));

    GetSubsystem<Renderer>()->SetViewport(0, new Viewport(context_, scene_, camera));

    SubscribeToEvent(E_KEYUP, [&](StringHash, VariantMap&) { engine_->Exit(); });
    SubscribeToEvent(E_UPDATE, [=](StringHash, VariantMap& eventData) {
        objectNode->Yaw(eventData[Update::P_TIMESTEP].GetFloat());
    });
}
  EOF
end

def gitattributes(_)
  <<-EOF
*.h linguist-language=C++
  EOF
end

def gitignore(_)
  <<-EOF
# Code::Blocks project settings
/*.cbp

# Codelite project settings
/*.project
/*.workspace

# Gradle project settings
/local.properties
.gradle/
build/
.cxx/

# JetBrains IDE project settings
/.idea/
/cmake-build-*/
*.iml

# KDevelop project settings
/*.kdev?

# Qt Creator project settings
/CMakeLists.txt.user

# Visual Studio project settings
/CMakeSettings.json
/.vs/
/out/

# Misc.
*~
*.swp
.DS_Store
*.log
*.bak
Thumbs.db
.directory
  EOF
end


# Load custom rake scripts
Dir['.rake/*.rake'].each { |r| load r }

# vi: set ts=2 sw=2 expandtab: