package com.urbancode.air.plugin.scm.changelog;

import java.text.SimpleDateFormat

public class ChangeSetFilter {

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

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

    def userExcludes = []
    def fileIncludes = []
    def fileExcludes = []

    public void setUserExcludes(String userExcludesString) {
        userExcludes = userExcludesString ? userExcludesString.readLines().collect{it.trim()}.findAll{it} : [];
    }

    public void setFileFilters(String fileFiltersString) {

        def includeFiles = []
        def excludeFiles = []
        if (fileFiltersString) {
            fileFiltersString.readLines().collect{it.trim()}.findAll{it}.each{filter ->
                def pattern = convertToPattern(filter.substring(1))
                if (filter.startsWith('+')) {
                    includeFiles << pattern
                }
                else if (filter.startsWith('-')) {
                    excludeFiles << pattern
                }
                else {
                    // not a valid expression
                }
            }
        }

        fileIncludes = includeFiles
        fileExcludes = excludeFiles
    }

    /**
     * Converts an Ant-style wild-mat string into an equivalent java.util.regex.Pattern
     *   ? is a single char wildcard
     *   * is a wildcard matches any string (but does not cross directories)
     *   ** is a wildcard which matches any string and can cross any number of directories
     */
    protected def convertToPattern( def antWildMat) {
        // trim leading / character from pattern
        def pattern = antWildMat.startsWith('/') ? antWildMat : '/'+antWildMat

        // deal with special regex-characters that should be interpreted as literals
        '\\.+[]^${}|()'.toCharArray().each{ c ->
            pattern = pattern.replace(''+c, '\\'+c)
        }
        pattern = pattern.replace('?', '.') // ? is a single-char wildcard

        // deal with ant-style wildcards
        StringBuffer result = new StringBuffer()
        def m = (pattern =~ '\\*\\*/|\\*\\*|\\*')
        while (m) {
            def token = m.group()
            def replacement;
            if (token == '**/') {
                replacement = '.*(?<=/)'
            }
            else if (token == '**') {
                replacement = '.*'
            }
            else {
                replacement = '[^/]*'
            }
            m.appendReplacement(result, java.util.regex.Matcher.quoteReplacement(replacement))
        }
        m.appendTail(result)
        return ~(result.toString())
    }

    /**
     * determine if the given path is a non-excluded path belonging to the desired set
     *
     * @param path the file path to be tested
     * @param includeFiles the file path includes
     * @param excludeFiles the file path excludes
     */
    public boolean pathIsIncluded(String path){
        boolean included = true;

        // check that it matches source being logged

        // now check the path (as relative to the basePath) against include/exclude patterns
        def relativePath = path // relative path will start with '/'

        if (fileIncludes.find{relativePath ==~ it} != null) {
            return true
        }

        if (fileExcludes.find{relativePath ==~ it} != null) {
            return false
        }
        return true;
    }

    public boolean authorIsIncluded(String author) {
        return !userExcludes.contains(author)
    }
}