package com.urbancode.air.plugin.scm

import com.urbancode.air.*
import com.urbancode.air.plugin.scm.changelog.*;

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

class SCMTag {

    //**************************************************************************
    // CLASS
    //**************************************************************************

    //**************************************************************************
    // INSTANCE
    //**************************************************************************

    def out = System.out;

    String hgCmd = "hg"
    File directory;
    String remoteUrl
    String remoteUser
    String remotePass
    String revision
    String message
    String tagName
    boolean doPush

    /**
     *
     */
    public void execute() {
        final def cmdHelper = new CommandHelper(directory);

        //
        // create tag in local repo
        //
        def tagCommand = [hgCmd, 'tag', '-r', revision, tagName]
        if (message) {
            tagCommand << "-m" << message
        }
        cmdHelper.runCommand('Creating Mercurial Local Tag', tagCommand);

        //
        // Push tag to remote
        //

        if (doPush) {
            
            // Embed username and password credentials on remoteUrl
            if (remoteUser) {
                if (remoteUrl.startsWith('http')) {
                    def userinfo = remoteUser;
                    if (remotePass) {
                        userinfo += ":$remotePass"
                    }
                    remoteUrl = remoteUrl.replaceFirst(~'^https?://', '$0'+Matcher.quoteReplacement(userinfo)+'@')
                }
                else {
                    println "warning: can not use username/password with non-http(s) url"
                }
            }
            
            //
            // Allow for failed pushes during race condition of applying new tag to repository
            //
            def pushCommand = [hgCmd, 'push']
            if (remoteUrl) {
                pushCommand << remoteUrl
            }

            def pullCommand = [hgCmd, "pull"]
            def mergeCommand = [hgCmd, "merge"]
            def commitCommand = [hgCmd, "commit", "-m", 'Merging new tag with repo changes'];

            // push, pull, merge, commit, push retry loop
            cmdHelper.ignoreExitValue = true
            int exitCode = cmdHelper.runCommand('Push tag to repository', pushCommand)
            if (exitCode != 0) {
                for (int i = 0; i < 5; i++) {
                    println("Failed push attempt ${i+1}: retrying")
                    exitCode = cmdHelper.runCommand(null, pullCommand)
                    if (exitCode != 0) {break;} // failed pull - give up
                    exitCode = cmdHelper.runCommand(null, mergeCommand)
                    if (exitCode != 0) {break;} // failed merge - give up
                    exitCode = cmdHelper.runCommand(null, commitCommand)
                    if (exitCode != 0) {break;} // failed commit - give up
                    exitCode = cmdHelper.runCommand('Push tag to repository', pushCommand)
                    if (exitCode == 0) {break;} // Success - done
                }
            }
            if (exitCode == 0) {
                println("Successfully pushed local changes")

                //
                // Restore the workspace back to original revision
                //

                def updateCommand = [hgCmd, 'update', '--rev', revision]
                cmdHelper.ignoreExitValue = false
                cmdHelper.runCommand("Update workspace back to $revision", updateCommand)
            }
            else {
                throw new Exception("Could not push tag to remote repository")
            }
        }
    }
}
