# 删除存在的文件
function del-file ($f) {
    if(Test-Path $f)  { 
        Write-Host "del $f"
        del $f 
    }
}

# 进入子目录，如果不存在先创建
function make-cd-path ($i){
    if(!(Test-Path $i)){ mkdir $i }
    cd $i;
}

# 递归删除存在的目录
function del-dir ($f) {
    if(Test-Path $f)  { 
        Write-Host "Remove-Item -Force -Recurse " $f
        Remove-Item -Force -Recurse $f 
    }
}

function del-any ($Path) {
    if (Test-Path $Path) {
        $item = Get-Item $Path -Force
        if($item -is [System.IO.DirectoryInfo]){
            Write-Host "删除目录：$Path"
            Remove-Item -Path $Path -Recurse -Force
        }else{
            Write-Host "删除文件或链接：$Path"
            Remove-Item -Path $Path -Force
        }
    } else {
        Write-Host "路径不存在，跳过删除：$Path"
    }
}

# 复制文件，如果目标文件存在且大小、日期相同则跳过。
# 用途：
# 1. 复制第三方dll到Debug/Release运行目录。
# 2. 发布编译好的exe/dll/lib、或头文件到指定目录

function _copy-file-ne($SrcPath, $DstPath) {
    # 判断目标文件是否存在
    if (Test-Path $DstPath -PathType Leaf) {
        $srcFile = Get-Item $SrcPath
        $dstFile = Get-Item $DstPath

        # 比较文件大小和创建时间
        if (($srcFile.Length -eq $dstFile.Length) -and ($srcFile.LastWriteTimeUtc -eq $dstFile.LastWriteTimeUtc)) {
            Write-Host "跳过：$SrcPath -> $DstPath"
            return
        } else {
            Write-Host "覆盖：$SrcPath -> $DstPath"
            Copy-Item -Path $SrcPath -Destination $DstPath -Force
        }
    } else {
        Write-Host "复制：$SrcPath -> $DstPath"
        Copy-Item -Path $SrcPath -Destination $DstPath
    }
}

function copy-file-ne($SrcPath, $DstPath) {
    # 判断源文件是否存在
    if (!(Test-Path $SrcPath -PathType Leaf)) {
        Write-Host "源文件不存在：$SrcPath"
        return
    }

    # 判断目标路径是否为目录
    if (Test-Path $DstPath -PathType Container) {
        $DstPath = Join-Path $DstPath (Split-Path $SrcPath -Leaf)
    }else{
        # 检查$DstPath的上一级目录是否存在
        $parentDir = Split-Path $DstPath -Parent
        if (!(Test-Path $parentDir -PathType Container)) {
            Write-Host "目标路径的上一级目录不存在：$parentDir"
            return
        }
     }
     _copy-file-ne $SrcPath $DstPath
}

function copy-files-ne($SrcPaths, $DstDir) {
    # 判断目标目录是否存在
    if (!(Test-Path $DstDir -PathType Container)) {
        Write-Host "目标目录不存在：$DstDir"
        return
    }

    # 遍历源文件数组并调用copy-file-ne函数复制文件
    foreach ($SrcPath in $SrcPaths) {
        if (!(Test-Path $SrcPath -PathType Leaf)) {
            Write-Host "源文件不存在：$SrcPath"
            # return
        }

        $DstPath = Join-Path $DstDir (Split-Path $SrcPath -Leaf)

        _copy-file-ne $SrcPath $DstPath
    }
}

function copy-dir-ne($SrcDir, $DstDir) {
    # 判断源目录和目标目录是否存在
    if (!(Test-Path $SrcDir -PathType Container)) {
        Write-Host "源目录不存在：$SrcDir"
        return
    }
    if (!(Test-Path $DstDir -PathType Container)) {
        Write-Host "目标目录不存在：$DstDir"
        return
    }

    # 递归遍历源目录中的子目录和文件
    $items = Get-ChildItem $SrcDir -Recurse

    foreach ($item in $items) {
        $relativePath = $item.FullName.Substring($SrcDir.Length)
        $destinationPath = Join-Path $DstDir $relativePath

        if ($item -is [System.IO.DirectoryInfo]) {
            # 如果是目录，则在目标目录中创建相同的目录结构
            if (!(Test-Path $destinationPath -PathType Container)) {
                New-Item -ItemType Directory -Path $destinationPath -Force
            }
        } else {
            # 如果是文件，则调用copy-file-ne函数复制文件
            _copy-file-ne $item.FullName $destinationPath
        }
    }
}

# 创建硬件链接
function hard-link ($link, $target) {
    New-Item -Path $link -ItemType HardLink -Value $target -Force
}

function soft-link ($link, $target) {
    New-Item -Path $link -ItemType SymbolicLink -Value $target -Force
}

function make-junction ($link, $target) {
    New-Item -Path $link -ItemType Junction -Value $target -Force
}

# 判断是否有效的目录链接
# 不存在：返回true
# 存在但链接无效：返回true
# 存在但链接有效：返回false
# 存在且目录：返回true
function Not-Valid-Link {
    param (
        [string]$linkName
    )

    $needlink = $false

    # 检查指定的目录是否存在
    if (Test-Path -Path $linkName) {
        $linkedDir = Get-Item -Path $linkName

        # 判断是否为Junction链接
        if ($linkedDir.LinkType -eq "Junction") {
            # 检查链接目标是否存在
            if (Test-Path -Path $linkedDir.Target) {
                Write-Host "$linkName 目录链接指向 $($linkedDir.Target)"
                $needlink = $false  # 不需要重新创建链接
            } else {
                Write-Host "$linkName 目录链接指向的目录不存在: $($linkedDir.Target)"
                $needlink = $true   # 需要重新创建链接
            }
        } else {
            # 如果不是Junction链接，则认为需要处理
            $needlink = $true
        }
    } else {
        # 如果指定的目录不存在，则需要创建链接
        $needlink = $true
    }

    return $needlink
}

# 判断是否有效的目录链接
# 不存在：返回true
# 存在但链接无效：返回true
# 存在但链接有效：返回false
# 存在且目录：返回true
function Not-Valid-Link-Or-Dir {
    param (
        [string]$linkName
    )

    $needlink = $false

    # 检查指定的目录是否存在
    if (Test-Path -Path $linkName) {
        $linkedDir = Get-Item -Path $linkName

        # 判断是否为Junction链接
        if ($linkedDir.LinkType -eq "Junction") {
            # 检查链接目标是否存在
            if (Test-Path -Path $linkedDir.Target) {
                Write-Host "$linkName 目录链接指向 $($linkedDir.Target)"
                $needlink = $false  # 不需要重新创建链接
            } else {
                Write-Host "$linkName 目录链接指向的目录不存在: $($linkedDir.Target)"
                $needlink = $true   # 需要重新创建链接
            }
        } else {
            # 如果不是Junction链接，无需处理
            $needlink = $false
        }
    } else {
        # 如果指定的目录不存在，则需要创建链接
        $needlink = $true
    }

    return $needlink
}

function Link-dir {
    param (
        [string]$linkName,
        [string]$describe,
        [string[]]$requireSub #示例 @("include", "lib", "bin")
    )
    if(-not $describe){
        $describe=$linkName
     }

    if(Not-Valid-Link $linkName){
        del-any $linkName
        $selectedDir = (New-Object -ComObject Shell.Application).BrowseForFolder(0, "Please select the $describe directory", 0, '')
        if($selectedDir){
            $selectedDir = $selectedDir.Self.Path
            # 检查所有指定的子目录是否存在
            $allrequireSubExist = $true
            foreach ($subDir in $requireSub) {
                if (-not (Test-Path (Join-Path $selectedDir $subDir))) {
                    $allrequireSubExist = $false
                    break
                }
            }

            if ($allrequireSubExist) {
                make-junction $linkName $selectedDir
            } else {
                Write-Host "The selected directory should contain the following requireSub: $($requireSub -join ', ')"
                pause
                exit 0
            }
        }
    }
}
