#Requires -Modules VagrantMessages
#-------------------------------------------------------------------------
# Copyright (c) Microsoft Open Technologies, Inc.
# All Rights Reserved. Licensed under the MIT License.
#--------------------------------------------------------------------------

param (
    [parameter (Mandatory=$true)]
    [string]$vm_id,
    [parameter (Mandatory=$true)]
    [string]$guest_ip,
    [parameter (Mandatory=$true)]
    [string]$username,
    [parameter (Mandatory=$true)]
    [string]$password,
    [parameter (Mandatory=$true)]
    [string]$host_path,
    [parameter (Mandatory=$true)]
    [string]$guest_path
)

function Get-file-hash($source_path, $delimiter) {
    $source_files = @()
    (Get-ChildItem $source_path -rec | ForEach-Object -Process {
      Get-FileHash -Path $_.FullName -Algorithm MD5 } ) |
        ForEach-Object -Process {
          $source_files += $_.Path.Replace($source_path, "") + $delimiter + $_.Hash
        }
    $source_files
}

function Get-Remote-Session($guest_ip, $username, $password) {
    $secstr = convertto-securestring -AsPlainText -Force -String $password
    $cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $username, $secstr
    New-PSSession -ComputerName $guest_ip -Credential $cred
}

function Get-remote-file-hash($source_path, $delimiter, $session) {
    Invoke-Command -Session $session -ScriptBlock ${function:Get-file-hash} -ArgumentList $source_path, $delimiter
    # TODO:
    # Check if remote PS Scripting errors
}

function Sync-Remote-Machine($machine, $remove_files, $copy_files, $host_path, $guest_path) {
    ForEach ($item in $copy_files) {
      $from = $host_path + $item
      $to = $guest_path + $item
      # Copy VM can also take a VM object
      Hyper-V\Copy-VMFile  -VM $machine -SourcePath $from -DestinationPath $to -CreateFullPath -FileSource Host -Force
    }
}

function Create-Remote-Folders($empty_source_folders, $guest_path) {
    ForEach ($item in $empty_source_folders) {
        $new_name =  $guest_path + $item
        New-Item "$new_name" -type directory -Force
    }
}

function Get-Empty-folders-From-Source($host_path) {
  Get-ChildItem $host_path -recurse |
        Where-Object {$_.PSIsContainer -eq $True} |
            Where-Object {$_.GetFiles().Count -eq 0} |
                Select-Object FullName | ForEach-Object -Process {
                    $empty_source_folders += ($_.FullName.Replace($host_path, ""))
                }
}

$delimiter = " || "

$machine = Hyper-V\Get-VM -Id $vm_id

# FIXME: PowerShell guys please fix this.
# The below script checks for all VMIntegrationService which are not enabled
# and will enable this.
# When when all the services are enabled this throws an error.
# Enable VMIntegrationService to true
try {
  Hyper-V\Get-VM -Id $vm_id | Hyper-V\Get-VMIntegrationService -Name "Guest Service Interface" | Hyper-V\Enable-VMIntegrationService -Passthru
  }
  catch { }

$session = Get-Remote-Session $guest_ip $username $password

$source_files = Get-file-hash $host_path $delimiter
$destination_files = Get-remote-file-hash $guest_path $delimiter $session

if (!$destination_files) {
  $destination_files = @()
}
if (!$source_files) {
  $source_files = @()
}

# Compare source and destination files
$remove_files = @()
$copy_files = @()


Compare-Object -ReferenceObject $source_files -DifferenceObject $destination_files | ForEach-Object {
  if ($_.SideIndicator -eq '=>') {
      $remove_files += $_.InputObject.Split($delimiter)[0]
  } else {
      $copy_files += $_.InputObject.Split($delimiter)[0]
  }
}

# Update the files to remote machine
Sync-Remote-Machine $machine $remove_files $copy_files $host_path $guest_path

# Create any empty folders which missed to sync to remote machine
$empty_source_folders = @()
$directories = Get-Empty-folders-From-Source $host_path

$result = Invoke-Command -Session $session -ScriptBlock ${function:Create-Remote-Folders} -ArgumentList $empty_source_folders, $guest_path
# Always remove the connection after Use
Remove-PSSession -Id $session.Id

$resultHash = @{
  message = "OK"
}
$result = ConvertTo-Json $resultHash
Write-OutputMessage $result
