# Custom backup script

function backup_aragorn {

    param(
        [switch]$diskoverride,
        [switch]$skipappdir)
    
    
    . (Join-Path $PSScriptRoot handle_exclude_lists.ps1)
    $myName = $env:COMPUTERNAME

    # Identify the backup disk
    ($backupDisk, $partial) = check_disk $diskoverride

    # Backup folder
    $backup_dir = "$HOME\Local"
    if (!(Test-Path $backup_dir) ) { mkdir $backup_dir }

    # Setup to use 7zip
    if (! (Test-Path 'C:\Program Files\7-Zip\7z.exe')) {
        Write-Error "Unable to locate 7-zip program file"
        exit 1
    }
    Set-Alias sz 'C:\Program Files\7-Zip\7z.exe'
    

    # Start the log file
    $logger = customLogger $backupDisk $myName
    $logger.StartLog()
    

    # Create a compressed version of the App Dir
    if (!($skipappdir)) {

        # Create the main backup file
        $backup_file = "$backup_dir\appdir.7z"

        # Make sure we start in the home folder
        Set-Location $HOME

        # Remove the previous file (start clean each time)
        if (Test-Path $backup_file) { Remove-Item $backup_file }

        # Load the exclude list
        $exclude = parse_appdata_exclude

        # Generate the compressed backup
        Invoke-Command -ScriptBlock { sz a -bb0 -t7z $args[0] $args[1] "$HOME\AppData"
            } -ArgumentList @($exclude, $backup_file)
    }

    ##
    ## Copy Everything to the disk
    ##

    # Define Options
    $basicOptions = "/MIR /COPY:DT /SL /XJ /DST /NDL /NP /TEE /R:1 /W:2 /LOG+:{0} /XF Thumbs.db" -f ($logger.logfile)
    $homeOptions = getRobocopyOptions $logger.logfile
    
    # Exclude Videos on smaller disks
    if ($partial) {
        $basicOptions += " /XD D:\david\Videos"
    }

    # Backup Home Directory
    backupDir $backupDisk $myName $HOME          "David"    $homeOptions

    # Backup the Data disk
    backupDir $backupDisk $myName "D:\david\"    "dDavid"   $basicOptions
    backupDir $backupDisk $myName "D:\public\"   "dPublic"  $basicOptions

    # Wrap up and update the log
    $logger.EndLog()
}

# Get the age of the backup to make sure we are using the right disk
function check_disk($diskoverride) {

    $backupDisk = Get-WmiObject -Class Win32_LogicalDisk | Where-Object {$_.VolumeName -match "Backup"}
    $partialBackup = $false

    # Test the age of the backup on the disk
    $last_updated = Get-Date (Get-Content (Join-Path $backupDisk.DeviceID "Aragorn\updated.txt"))
    if ($last_updated.AddDays(20) -lt (Get-Date)) {
        if (!($diskoverride)) {
            Write-Host -ForegroundColor DarkRed "This disk was last used less than 3 weeks ago. Override with -diskoverride."
            exit(1)
        }
    }

    
    # How much free space is there?
    if ($backupDisk.FreeSpace / 1gb -lt 20) {
        Write-Host -ForegroundColor DarkRed "There is less than 20gb free on the disk."
        exit(1)
    }


    # If it is a big disk, backup the videos as well
    if ($backupDisk.Size / 1gb -lt 1200) {
        Write-Host "Disk is small enough to do a partial backup"
        $partialBackup = $true
    }

    # Return the disk letter and whether to do the full backup
    return ($backupDisk.DeviceID, $partialBackup)
}



function customLogger($backupDisk, $myName) {
    $logger = [PSCustomObject]@{
        startTime = Get-Date
        logfile   = "$HOME\backuplog_{0}.txt" -f (Get-Date -UFormat %Y%m%d-%H%M)
        endTime   = $null
        updateFile = ("{0}\{1}\updated.txt" -f ($backupDisk, $myName))
    }
    
    $StartLogScript = {
        Set-Content $this.logfile ( "`nStart Time: {0}`n`n" -f ($this.startTime) )
    }
    $memberParam = @{
        MemberType = "ScriptMethod"
        InputObject = $logger
        Name = "StartLog"
        Value = $StartLogScript
    }
    Add-Member @memberParam


    $EndLogScript = {
        Set-Content -Value (Get-Date) -Path $this.updateFile
        
        $this.endTime = Get-Date
        $start = "Start Time: {0}" -f $this.startTime
        $end = "Finish Time: {0}" -f $this.endTime
        Add-Content $this.logfile "`n`n$start`n$end"

        $ts = New-TimeSpan $this.startTime $this.endTime
        Write-Host ("The backup took {0:N1} minutes to complete" -f $ts.TotalMinutes)

        notepad $this.logfile
    }
    $memberParam = @{
        MemberType = "ScriptMethod"
        InputObject = $logger
        Name = "EndLog"
        Value = $EndLogScript
    }
    Add-Member @memberParam
    
    return $logger
}



# Backup the specified directory
function backupDir($diskID, $myName, $src, $dstDir, $options, $basedir="")
{
    $dst = "{0}\{1}\{2}" -f ($diskID, $myName, $dstDir)
    
    # If we are working with a special base directory, set it here
    if ($basedir) {
        $dst = "{0}\{1}\{2}" -f ($diskID, $basedir, $dstDir)
    }

    # Make sure it exists and start the backup
    if (!(Test-Path $dst)) { mkdir $dst }
    & robocopy $src $dst $options.Split()
}



# Robocopy options
function getRobocopyOptions($log)
{
    $excludeList = @"
AppData
Application Data
MicrosoftEdgeBackups
Cookies
.cache
.vagrant.d
"@

    # Build the exclude rules
    $xd = "/XD"
    foreach ($line in $excludeList.Split("`n")) {
        $xd += ' "' + "$HOME\" + $line.Trim() + '"'
    }

    # Return the exclude options
    return "/MIR /COPY:DT /SL /XJ /DST /NDL /NP /TEE /R:0 /W:2 /LOG+:$log /XF NTUSER.* UsrClass.* Thumbs.db $xd"
}


Export-ModuleMember backup_aragorn