package com.urbancode.air.plugin.scm

import com.urbancode.air.*

import java.util.Date;
import java.util.regex.Matcher

public class SCMCheckout extends SCMStep {
    
    //**************************************************************************
    // CLASS
    //**************************************************************************

    //**************************************************************************
    // INSTANCE
    //**************************************************************************
    
    // Clientspec Creation Variables
    boolean createNewClientSpec
    boolean isUsingTemplate
    String templateName
    String clientspec
    
    // Sync Variables
    boolean forceSync
    boolean preserveUnlabeledFiles
    boolean doNotUpdateHaveList
    String label
    Date date
    
    public def execute() {
        this.login()
        if (createNewClientSpec || isUsingTemplate) {
            createClientSpec()
        }
        getClientspecInfo()
        sync()
        return depotPaths
    }
    
    public void createClientSpec() {
        if (isUsingTemplate) {
            def command = this.createP4BaseCommand()
            command << 'client' << '-o' << '-t' << templateName << client
            ch.runCommand("Getting Clientspec Template", command) { Process proc ->
                proc.out.close() // close stdin
                proc.consumeProcessErrorStream(out)
                clientspec = proc.text
            }
        }
        
        // modify the root in the clientspec config to reflect the directoryOffset if
        // one was specified in the command
        clientspec = modifyClientSpecConfigRoot(clientspec, dirOffset)
        
        println("Creating Clientspec:\n" + clientspec + "\n")
        
        // run the process
        def createClientCommand = createP4BaseCommand()
        createClientCommand << 'client' << '-i'
        ch.runCommand('Create Clientspec', createClientCommand) { Process proc ->
            proc.consumeProcessOutput(out, out)
            proc.withWriter{ it << clientspec } // pipe clientspec to child process stdIn and close the stream afterwards
        }
    }
    
    public void sync() {
        def syncCmd = createP4BaseCommand()
        syncCmd << 'sync'
        if (forceSync) {
            syncCmd << '-f'
        }
        else if (doNotUpdateHaveList) {
            syncCmd << '-p'
        }
        
        if (label) {
            if (preserveUnlabeledFiles) {
                syncCmd << "@$label,@$label"
            }
            else {
                syncCmd << "@$label"
            }
        }
        else if (date != null) {
            // take server date and format it using the p4 server timezone
            def commandDate = date
        
            // adjust date for difference between air-agent and p4-server
            if (timezoneDifference) {
                def p4Cal = Calendar.instance
                p4Cal.time = commandDate
                
                // Timezone Difference is in hours and can be a decimal like 1.5
                p4Cal.add(Calendar.HOUR_OF_DAY, (int)timezoneDifference)
                int minDiff = (int)(timezoneDifference * 60) % 60
                if (minDiff) {
                    p4Cal.add(Calendar.MINUTE, minDiff)
                }
                commandDate = p4Cal.time
            }
        
            syncCmd << "@${PERFORCE_DATE.format(commandDate)}"
        }
        
        ch.runCommand("Performing P4 Sync", syncCmd)
    }
    
    /**
    * replace path in a configspec with given path
    */
    def modifyClientSpecConfigRoot = { String config, String newRoot ->
        if (!config) {
            return config
        }
        else if (!newRoot) {
           return config.replaceAll(/(?mi)Root:.*$/, Matcher.quoteReplacement("Root: ${new File('.').canonicalPath}"))
        }
        return config.replaceAll(/(?mi)Root:.*$/, Matcher.quoteReplacement("Root: ${new File('.', newRoot).canonicalPath}"))
    }
    
    public String getLatestChangelist() {
        def command = createP4BaseCommand()
        command << 'changes' << '-s' << 'submitted' << '-m' << '1'
        if (integrateOption) {
            command << '-i'
        }
        command << "//${client}/..."
        
        def changeListOutput = null
        ch.runCommand('Getting Latest Changelist', command) { proc ->
            proc.out.close()                    // close   the stdIn  of the process
            proc.consumeProcessErrorStream(System.out) // forward the stdErr of the process
            changeListOutput = proc.text                 // capture the stdout of the process
            println changeListOutput                     // echo captured stdout
        }

        def change = changeListOutput.find(/(?m)^Change (\d+)/) { match, change -> return change }
        return change
    }
}