import groovy.io.FileType import org.apache.tools.ant.taskdefs.condition.Os import org.gradle.api.tasks.Exec

buildscript {

repositories {
    mavenCentral()
            jcenter()
}
dependencies {
    classpath 'com.eriwen:gradle-js-plugin:1.8.0'
            classpath 'com.moowork.gradle:gradle-grunt-plugin:0.2'
}

}

apply plugin: ‘js’ apply plugin: ‘grunt’

repositories {

mavenCentral()

}

configurations {

rhino

}

dependencies {

rhino 'org.mozilla:rhino:1.7R4'

}

project.ext {

packageProps = new groovy.json.JsonSlurper().parseText(new File("package.json").toURL().text)
failures = 0;
rhinoTestSrc = "out/rhino-test-${packageProps.version}.js"
testSrc = 'test/less'
testOut = 'out/test'

}

task runGruntRhino(type: GruntTask) {

gruntArgs = "rhino"

}

combineJs {

    dependsOn runGruntRhino
source = ["dist/less-rhino-${packageProps.version}.js", "test/rhino/test-header.js","dist/lessc-rhino-${packageProps.version}.js"]
dest = file(rhinoTestSrc)

}

task testRhino(type: AllRhinoTests) { // dependsOn ‘testRhinoBase’

dependsOn 'testRhinoBase', 'testRhinoErrors', 'testRhinoLegacy', 'testRhinoStaticUrls', 'testRhinoCompression', 'testRhinoDebugAll', 'testRhinoDebugComments', 'testRhinoDebugMediaquery', 'testRhinoNoJsError', 'testRhinoSourceMap'

}

task testRhinoBase(type: RhinoTest) {

options = [ '--strict-math=true', '--relative-urls' ]

}

task testRhinoDebugAll(type: DebugRhinoTest) {

options = [ '--strict-math=true', '--line-numbers=all' ]
testDir = 'debug' + fs
suffix = "-all"

}

task testRhinoDebugComments(type: DebugRhinoTest) {

options = [ '--strict-math=true', '--line-numbers=comments' ]
testDir = 'debug' + fs
suffix = "-comments"

}

task testRhinoDebugMediaquery(type: DebugRhinoTest) {

options = [ '--strict-math=true', '--line-numbers=mediaquery' ]
testDir = 'debug' + fs
suffix = "-mediaquery"

}

task testRhinoErrors(type: RhinoTest) {

options = [ '--strict-math=true', '--strict-units=true' ]
testDir = 'errors/'
expectErrors = true

}

task testRhinoChyby(type: RhinoTest) {

 options = [ '--strict-math=true', '--strict-units=true' ]
 testDir = 'chyby/'
// expectErrors = true

}

task testRhinoNoJsError(type: RhinoTest) {

options = [ '--strict-math=true', '--strict-units=true', '--no-js' ]
testDir = 'no-js-errors/'
expectErrors = true

}

task testRhinoLegacy(type: RhinoTest) {

testDir = 'legacy/'

}

task testRhinoStaticUrls(type: RhinoTest) {

options = [ '--strict-math=true', '--rootpath=folder (1)/' ]
testDir = 'static-urls/'

}

task testRhinoCompression(type: RhinoTest) {

options = [ '--compress=true' ]
testDir = 'compression/'

}

task testRhinoSourceMap(type: SourceMapRhinoTest) {

options = [ '--strict-math=true', '--strict-units=true']
testDir = 'sourcemaps/'

}

task setupTest {

    dependsOn combineJs
doLast {
    file(testOut).deleteDir()
}

}

task clean << {

file(rhinoTestSrc).delete()
file(testOut).deleteDir()

}

class SourceMapRhinoTest extends RhinoTest {

// helper to get the output map file
def getOutputMap(lessFile) {
        def outFile = project.file(lessFile.path.replace('test/less', project.testOut).replace('.less', '.css'))
        return project.file(outFile.path + ".map");
}

// callback to add SourceMap options to the options list
def postProcessOptions(options, lessFile) {
        def outFile = getOutputMap(lessFile)
        project.file(outFile.parent).mkdirs()
        options << "--source-map=${testDir}${lessFile.name.replace('.less','.css')}"
        options << "--source-map-basepath=${lessRootDir}"
        options << "--source-map-rootpath=testweb/"
        options << "--source-map-output-map-file=${outFile}"

        options
}

// Callback to validate output
def handleResult(exec, out, lessFile) {
        def actualFile = getOutputMap(lessFile)
        def expectedFile = project.file(projectDir + fs + "test" + fs + testDir + fs + lessFile.name.replace(".less", ".json"))         
        assert actualFile.text == expectedFile.text
}

}

class DebugRhinoTest extends RhinoTest {

def escapeIt(it) {
  return it.replaceAll("\\\\", "\\\\\\\\").replaceAll("/", "\\\\/").replaceAll(":", "\\\\:").replaceAll("\\.", "\\\\.");
}

def globalReplacements(input, directory) {
  def pDirectory = toPlatformFs(directory)
  def p = lessRootDir + fs + pDirectory 
  def pathimport = p + toPlatformFs("import/")
  def pathesc = escapeIt(p)
  def pathimportesc = escapeIt(pathimport)

  def result = input.replace("{path}", p).replace("{pathesc}", pathesc).replace("{pathimport}", pathimport)
  return result.replace("{pathimportesc}", pathimportesc).replace("\r\n", "\n")
}

}

class RhinoTest extends DefaultTask {

RhinoTest() {
    dependsOn 'setupTest'
}

def suffix = ""
def testDir = ''
def options = []
def expectErrors = false
def fs = File.separator;
def projectDir = toUpperCaseDriveLetter(System.getProperty("user.dir"));
def lessRootDir = projectDir + fs + "test" + fs + "less"

def toUpperCaseDriveLetter(path) {
  if (path.charAt(1)==':' && path.charAt(2)=='\\') {
      return path.substring(0,1).toUpperCase() + path.substring(1);
  } 
  return path;
}

def toPlatformFs(path) {
  return path.replace('\\', fs).replace('/', fs); 
}

def expectedCssPath(lessFilePath) {
      lessFilePath.replace('.less', "${suffix}.css").replace("${fs}less${fs}", "${fs}css${fs}");
}

def globalReplacements(input, directory) {
  return input;
}

def stylize(str, style) {
    def styles = [
        reset     : [0,   0],
        bold      : [1,  22],
        inverse   : [7,  27],
        underline : [4,  24],
        yellow    : [33, 39],
        green     : [32, 39],
        red       : [31, 39],
        grey      : [90, 39]
    ];
    return '\033[' + styles[style][0] + 'm' + str +
            '\033[' + styles[style][1] + 'm';
}

    // Callback for subclasses to make any changes to the options
    def postProcessOptions(options, lessFile) {
            options
    }

    // Callback to validate output
    def handleResult(exec, out, lessFile) {
            def actual = out.toString().trim()
            def actualResult = project.file(lessFile.path.replace('test/less', project.testOut).replace('.less', '.css'))
            project.file(actualResult.parent).mkdirs()
            actualResult << actual
            def expected
            if (expectErrors) {
                    assert exec.exitValue != 0
                    expected = project.file(lessFile.path.replace('.less', '.txt')).text.trim().
                                    replace('{path}', lessFile.parent + '/').
                                    replace('{pathhref}', '').
                                    replace('{404status}', '')
            } else {
                    assert exec.exitValue == 0
                    def expectedFile = expectedCssPath(lessFile.path)
                    expected = project.file(expectedFile).text.trim()
                    expected = globalReplacements(expected, testDir)
            }
            actual=actual.trim()
            actual = actual.replace('\r\n', '\n')
            expected = expected.replace('\r\n', '\n')
            actual = actual.replace("/","\\")
            expected = expected.replace("/","\\")

// println “* actual *” // println actual // new File(“actual.txt”).write(actual) // println “* expected *” // println expected // new File(“expected.txt”).write(expected)

            assert actual == expected
            actualResult.delete()

    }

@TaskAction
def runTest() {
    int testSuccesses = 0, testFailures = 0, testErrors = 0
    project.file('test/less/' + testDir).eachFileMatch(FileType.FILES, ~/.*\.less/) { lessFile ->
        println "lessfile: $lessFile"
        if (!project.hasProperty('test') || lessFile.name.startsWith(project.test)) {
            def out = new java.io.ByteArrayOutputStream()
            def processedOptions = postProcessOptions([project.rhinoTestSrc, lessFile] + options, lessFile)
            def execOptions = {
                main = 'org.mozilla.javascript.tools.shell.Main'

// main = ‘org.mozilla.javascript.tools.debugger.Main’

                classpath = project.configurations.rhino
                args = processedOptions
                standardOutput = out
                ignoreExitValue = true
            }
            println "rhinoTestSrc: ${project.rhinoTestSrc}" 
            try {
                def exec = project.javaexec(execOptions)
                                    handleResult(exec, out, lessFile)
                                    testSuccesses++
                                    println stylize('   ok', 'green')
            }
            catch (ex) {
                println ex
                println()
                testErrors++;
            }
            catch (AssertionError ae) {
                println stylize('   failed', 'red')
                println ae
                testFailures++
            }
        } else {
            println stylize('   skipped', 'yellow')
        }
    }
    println stylize(testSuccesses + ' ok', 'green')
    println stylize(testFailures + ' assertion failed', testFailures == 0 ? 'green' : 'red')
    println stylize(testErrors + ' errors', testErrors == 0 ? 'green' : 'red')
    if (testFailures != 0 || testErrors != 0) {
        project.failures++;
    }
}

}

class AllRhinoTests extends DefaultTask {

AllRhinoTests() {
}

@TaskAction
def runTest() {
   println stylize(project.failures + ' test suites failed', project.failures == 0 ? 'green' : 'red')
}

def stylize(str, style) {
    def styles = [
        reset     : [0,   0],
        bold      : [1,  22],
        inverse   : [7,  27],
        underline : [4,  24],
        yellow    : [33, 39],
        green     : [32, 39],
        red       : [31, 39],
        grey      : [90, 39]
    ];
    return '\033[' + styles[style][0] + 'm' + str +
            '\033[' + styles[style][1] + 'm';
}

}

class GruntTask extends Exec {

private String gruntExecutable = Os.isFamily(Os.FAMILY_WINDOWS) ? "grunt.cmd" : "grunt"
private String switches = "--no-color"

String gruntArgs = "" 

public GruntTask() {
    super()
    this.setExecutable(gruntExecutable)
}

public void setGruntArgs(String gruntArgs) {
    this.args = "$switches $gruntArgs".trim().split(" ") as List
}

}