package com.mebigfatguy.vcsversion;

import java.io.BufferedReader;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;

public class VcsVersionTask extends Task {

    private enum VcsType {SVN, GIT, HG};
    
    private String vcs;
    private String revisionProp;
    private String branchProp;
    private String dateProp;
    
    public void setVcs(String versionControlSystem) {
        vcs = versionControlSystem;
    }
    
    public void setRevisionProperty(String revisionProperty) {
        revisionProp = revisionProperty;
    }
    
    public void setBranchProperty(String branchProperty) {
        branchProp = branchProperty;
    }
    
    public void setDateProperty(String dateProperty) {
        dateProp = dateProperty;
    }
    
    
    public void execute() {
        if (vcs == null) {
            throw new BuildException("Failed to provide ant property 'vcs'");
        }
        
        VcsType type = VcsType.valueOf(vcs.toUpperCase());
        
        switch (type) {
                
            case SVN:
                getSVNInfo();
                break;
                
            case GIT:
                getGITInfo();
                break;
                
            case HG:
                getHGInfo();
                break;
                
            default:
                throw new BuildException("Unknown vcs type: " + vcs);
        }        
    }
    
    private void getSVNInfo() {

        Pattern commitPattern = Pattern.compile("([^\\s]*)\\s+\\|.*", Pattern.CASE_INSENSITIVE);
        Pattern datePattern = Pattern.compile("[^\\|]+\\|[^\\|]+\\|\\s*([\\|]*).*", Pattern.CASE_INSENSITIVE);
        Pattern branchPattern = Pattern.compile("url:?.*/(.*)", Pattern.CASE_INSENSITIVE);

        BufferedReader br = null;
        try {
            Map<Pattern, String> vcsProps = new HashMap<Pattern, String>();
            if (revisionProp != null)
                vcsProps.put(commitPattern, revisionProp);
            if (dateProp != null)
                vcsProps.put(datePattern, dateProp);
            
            fetchInfo(vcsProps, "svn", "log", "-l", "1");
            
            vcsProps.clear();
            vcsProps.put(branchPattern, branchProp);
            
            fetchInfo(vcsProps, "svn", "info");
            
        } catch (Exception e) {
            throw new BuildException("Failed getting svn log info", e);
        } finally {
            closeQuietly(br);
        }
    }
    
    private void getGITInfo() {

        Pattern commitPattern = Pattern.compile("commit:?\\s*(.*)", Pattern.CASE_INSENSITIVE);
        Pattern datePattern = Pattern.compile("date:?\\s*(.*)", Pattern.CASE_INSENSITIVE);
        Pattern branchPattern = Pattern.compile("\\*\\s*(.*)", Pattern.CASE_INSENSITIVE);

        BufferedReader br = null;
        try {
            Map<Pattern, String> vcsProps = new HashMap<Pattern, String>();
            if (revisionProp != null)
                vcsProps.put(commitPattern, revisionProp);
            if (dateProp != null)
                vcsProps.put(datePattern, dateProp);
            
            fetchInfo(vcsProps, "git", "log", "-n", "1");
            
            vcsProps.clear();
            vcsProps.put(branchPattern, branchProp);
            
            fetchInfo(vcsProps, "git", "branch");
            
        } catch (Exception e) {
            throw new BuildException("Failed getting git log info", e);
        } finally {
            closeQuietly(br);
        }
    }

    private void getHGInfo() {
        
        Pattern changesetPattern = Pattern.compile("changeset:?\\s*(.*)", Pattern.CASE_INSENSITIVE);
        Pattern datePattern = Pattern.compile("date:?\\s*(.*)", Pattern.CASE_INSENSITIVE);
        Pattern branchPattern = Pattern.compile("(.*)", Pattern.CASE_INSENSITIVE);

        BufferedReader br = null;
        try {
            Map<Pattern, String> vcsProps = new HashMap<Pattern, String>();
            if (revisionProp != null)
                vcsProps.put(changesetPattern, revisionProp);
            if (dateProp != null)
                vcsProps.put(datePattern, dateProp);
            
            fetchInfo(vcsProps, "hg", "log", "-l", "1");
            
            vcsProps.clear();
            vcsProps.put(branchPattern, branchProp);
            
            fetchInfo(vcsProps, "hg", "branch");
            
        } catch (Exception e) {
            throw new BuildException("Failed getting hg log info", e);
        } finally {
            closeQuietly(br);
        }

    }
    
    private void fetchInfo(Map<Pattern, String> vcsProps, String... commandLine) throws IOException, InterruptedException {
        
        ProcessBuilder builder = new ProcessBuilder(commandLine);
        builder.directory(getProject().getBaseDir());
        Process p = builder.start();
        p.waitFor();
        
        BufferedReader br = null;
        try {
            br = new BufferedReader(new InputStreamReader(p.getInputStream(), "UTF-8"));
            String line = br.readLine();
            while (line != null) {
                for (Map.Entry<Pattern, String> entry : vcsProps.entrySet()) {
                    Matcher m = entry.getKey().matcher(line);
                    if (m.matches()) {
                        getProject().setProperty(entry.getValue(), m.group(1).trim());
                    }
                }

                line = br.readLine();
            }
        } finally {
            closeQuietly(br);
        }
    }
    
    private void closeQuietly(Closeable c) {
        try {
            if (c != null) {
                c.close();
            }
        } catch (Exception e) { 
        }
    }
}

@@ -1972,42 +1972,8 @@
 );%0A%0A
-        BufferedReader br = null;%0A
     
@@ -1974,32 +1974,32 @@
 %0A%0A        try %7B%0A
+
             Map%3C
@@ -2591,58 +2591,8 @@
 e);%0A
-        %7D finally %7B%0A            closeQuietly(br);%0A
     
@@ -2922,42 +2922,8 @@
 );%0A%0A
-        BufferedReader br = null;%0A
     
@@ -3543,58 +3543,8 @@
 e);%0A
-        %7D finally %7B%0A            closeQuietly(br);%0A
     
@@ -3876,42 +3876,8 @@
 );%0A%0A
-        BufferedReader br = null;%0A
     
@@ -4485,32 +4485,32 @@
  log info%22, e);%0A
+
         %7D finall
@@ -4506,59 +4506,8 @@
    %7D
- finally %7B%0A            closeQuietly(br);%0A        %7D%0A
 %0A   

remove unused vars