package uk.org.sappho.code.heatmap.scm;

import java.util.List;
import java.util.Map;
import java.util.Vector;

import org.apache.log4j.Logger;
import org.tigris.subversion.javahl.ChangePath;
import org.tigris.subversion.javahl.ClientException;
import org.tigris.subversion.javahl.Info2;
import org.tigris.subversion.javahl.LogMessageCallback;
import org.tigris.subversion.javahl.NodeKind;
import org.tigris.subversion.javahl.Revision;
import org.tigris.subversion.javahl.RevisionRange;
import org.tigris.subversion.javahl.SVNClient;

import com.google.inject.Inject;

import uk.org.sappho.code.heatmap.engine.Change;
import uk.org.sappho.code.heatmap.engine.Filename;
import uk.org.sappho.code.heatmap.engine.HeatMapCollection;
import uk.org.sappho.code.heatmap.scm.SCM;

public class Subversion implements SCM {

    private final String url;
    private final String basePath;
    private final long startRevision;
    private final long endRevision;
    private final SVNClient svnClient = new SVNClient();
    private static final Logger LOG = Logger.getLogger(Subversion.class);

    @Inject
    public Subversion() {

        this.url = System.getProperty("svn.url");
        this.basePath = System.getProperty("svn.path");
        this.startRevision = Long.parseLong(System.getProperty("svn.start.rev"));
        this.endRevision = Long.parseLong(System.getProperty("svn.end.rev"));
    }

    private class SubversionRevision {

        private final ChangePath[] changedPaths;
        private final long revision;
        @SuppressWarnings("unchecked")
        private final Map revprops;

        @SuppressWarnings("unchecked")
        public SubversionRevision(ChangePath[] changedPaths, long revision, Map revprops) {
            this.changedPaths = changedPaths;
            this.revision = revision;
            this.revprops = revprops;
        }

        public ChangePath[] getChangedPaths() {
            return changedPaths;
        }

        public long getRevision() {
            return revision;
        }

        @SuppressWarnings("unchecked")
        public Map getRevprops() {
            return revprops;
        }
    }

    private class LogMessageProcessor implements LogMessageCallback {

        private final List<SubversionRevision> revisions;

        public LogMessageProcessor(List<SubversionRevision> revisions) {

            this.revisions = revisions;
        }

        @SuppressWarnings("unchecked")
        public void singleMessage(ChangePath[] changedPaths, long revision, Map revprops, boolean hasChildren) {

            if (revision != Revision.SVN_INVALID_REVNUM) {
                revisions.add(new SubversionRevision(changedPaths, revision, revprops));
            }
        }
    }

    public HeatMapCollection processChanges() {

        HeatMapCollection heatMapCollection = new HeatMapCollection();
        List<SubversionRevision> revisions = new Vector<SubversionRevision>();
        LOG.debug("Attempting to read Subversion history at " + url + basePath + " from rev. " + startRevision
                + " to rev. " + endRevision);
        RevisionRange[] revisionRange = new RevisionRange[] { new RevisionRange(Revision.getInstance(startRevision),
                Revision.getInstance(endRevision)) };
        String[] revProps = new String[] { "svn:log" };
        try {
            svnClient.logMessages(url + basePath, Revision.getInstance(endRevision), revisionRange,
                    false, true, true, revProps, 0, new LogMessageProcessor(revisions));
        } catch (ClientException e) {
            LOG.error("Unable to read Subversion history at " + url + basePath + " from rev. " + startRevision
                    + " to rev. " + endRevision, e);
        }
        for (SubversionRevision revision : revisions) {
            String comment = (String) revision.getRevprops().get("svn:log");
            LOG.debug("Processing rev. " + revision.getRevision() + " " + comment);
            List<Filename> changedFiles = new Vector<Filename>();
            for (ChangePath changePath : revision.getChangedPaths()) {
                String filename = changePath.getPath();
                try {
                    Revision revisionId = Revision.getInstance(revision.getRevision());
                    Info2[] info = svnClient.info2(url + filename, revisionId, revisionId, false);
                    if (info.length == 1 && info[0].getKind() == NodeKind.file) {
                        LOG.debug("Processing changed file " + filename);
                        changedFiles.add(new Filename(filename));
                    } else {
                        LOG.debug("Presuming " + filename + " is a directory");
                    }
                } catch (ClientException e) {
                    LOG.debug("Unable to determine type of " + filename + " so presuming it deleted");
                }
            }
            heatMapCollection.update(new Change(Long.toString(revision.getRevision()), comment, changedFiles));
        }
        return heatMapCollection;
    }
}

@@ -746,52 +746,8 @@
 on;%0D
-%0Aimport uk.org.sappho.code.heatmap.scm.SCM;%0D
 %0A%0D%0Ap
@@ -1117,21 +1117,16 @@
         
-this.
 url = Sy
@@ -1163,21 +1163,16 @@
         
-this.
 basePath
@@ -1215,21 +1215,16 @@
         
-this.
 startRev
@@ -1293,21 +1293,21 @@
         
-this.
+long 
 endRevis
@@ -1355,25 +1355,793 @@
 svn.end.rev%22
-)
+, %22-1%22));%0D%0A        if (endRevision %3C 0) %7B%0D%0A            try %7B%0D%0A                Info2%5B%5D info = svnClient.info2(url + basePath, Revision.HEAD, Revision.HEAD, false);%0D%0A                endRevision = info%5B0%5D.getLastChangedRev();%0D%0A                LOG.debug(%22Using HEAD revision of %22 + endRevision + %22 for %22 + url + basePath);%0D%0A            %7D catch (ClientException e) %7B%0D%0A                LOG.error(%22Unable to determine head revision of %22 + url + basePath, e);%0D%0A            %7D%0D%0A        %7D%0D%0A        this.endRevision = endRevision;%0D%0A        LOG.debug(%22Using Subversion SCM plugin%22);%0D%0A        LOG.debug(%22url:           %22 + url);%0D%0A        LOG.debug(%22basePath:      %22 + basePath);%0D%0A        LOG.debug(%22startRevision: %22 + startRevision);%0D%0A        LOG.debug(%22endRevision:   %22 + endRevision
 );%0D%0A    %7D%0D%0A%0D
@@ -3747,33 +3747,21 @@
 LOG.
-debug(%22Attempting to read
+info(%22Reading
  Sub
@@ -3768,34 +3768,35 @@
 version history 
-at
+for
  %22 + url + baseP

Work out auto-head revision if required. More debug.