/*
 * Copyright 2013 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.gradle.nativebinaries.toolchain.internal.msvcpp;

import org.gradle.api.specs.Spec;
import org.gradle.internal.os.OperatingSystem;

import java.io.File;

public class VisualStudioLocator {
    private final OperatingSystem os;

    public VisualStudioLocator() {
        this(OperatingSystem.current());
    }

    public VisualStudioLocator(OperatingSystem os) {
        this.os = os;
    }

    public File locateVisualStudio(File candidate) {
        return locateInHierarchy(candidate, isVisualStudio());
    }

    public File locateDefaultVisualStudio() {
        Spec<File> isVisualStudio = isVisualStudio();
        // If cl.exe is on the path, assume it is contained within a visual studio install
        File compilerInPath = os.findInPath("cl.exe");
        if (compilerInPath != null) {
            return locateInHierarchy(compilerInPath, isVisualStudio);
        }

        // TODO:DAZ Use %PROGRAMFILES% environment variable
        return locateInCandidates(isVisualStudio,
                "C:/Program Files (x86)/Microsoft Visual Studio 10.0",
                "C:/Program Files/Microsoft Visual Studio 10.0");
    }

    private Spec<File> isVisualStudio() {
        return new Spec<File>() {
            public boolean isSatisfiedBy(File element) {
                return new File(element, "VC/bin/cl.exe").isFile();
            }
        };
    }

    public File locateDefaultWindowsSdk() {
        // If rc.exe is on the path, assume it is contained within a Windows SDK
        File resourceCompilerInPath = os.findInPath("rc.exe");
        if (resourceCompilerInPath != null) {
            return locateInHierarchy(resourceCompilerInPath, isWindowsSdk());
        }

        // TODO:DAZ Use %PROGRAMFILES% environment variable
        return locateInCandidates(isWindowsSdk(),
                "C:/Program Files (x86)/Microsoft SDKs/Windows/v7.1",
                "C:/Program Files/Microsoft SDKs/Windows/v7.1",
                "C:/Program Files (x86)/Microsoft SDKs/Windows/v7.0A",
                "C:/Program Files/Microsoft SDKs/Windows/v7.0A");
    }

    private Spec<File> isWindowsSdk() {
        return new Spec<File>() {
            public boolean isSatisfiedBy(File element) {
                return isWindowsSdk(element);
            }
        };
    }

    private boolean isWindowsSdk(File candidate) {
        return new File(candidate, "bin/rc.exe").isFile() && new File(candidate, "lib/kernel32.lib").isFile();
    }

    private File locateInCandidates(Spec<File> condition, String... candidateLocations) {
        for (String candidateLocation : candidateLocations) {
            File candidate = new File(candidateLocation);
            if (condition.isSatisfiedBy(candidate)) {
                return candidate;
            }
        }
        return null;
    }

    private File locateInHierarchy(File candidate, Spec<File> condition) {
        while (candidate != null) {
            if (condition.isSatisfiedBy(candidate)) {
                return candidate;
            }
            candidate = candidate.getParentFile();
        }
        return null;
    }
}

@@ -774,16 +774,67 @@
 io.File;
+%0Aimport java.util.ArrayList;%0Aimport java.util.List;
 %0A%0Apublic
@@ -1566,214 +1566,53 @@
     
-// TODO:DAZ Use %25PROGRAMFILES%25 environment variable%0A        return locateInCandidates(isVisualStudio,%0A                %22C:/
+return locateIn
 Program
- 
 Files
- (x86)/Microsoft 
+(is
 Visual
- 
 Studio
- 10.0%22,%0A                %22C:/Program Files
+, %22
 /Mic
@@ -2215,284 +2215,69 @@
     
-// TODO:DAZ Use %25PROGRAMFILES%25 environment variable%0A        return locateInCandidates(isWindowsSdk(),%0A                %22C:/
+return locateIn
 Program
- 
 Files
- (x86)/Microsoft SDKs/Windows/v7.1%22,%0A                %22C:/Program Files/Microsoft SDKs/Windows/v7.1%22,%0A                %22C:/Program Files (x86)/
+(isWindowsSdk(),%0A                %22
 Micr
@@ -2298,18 +2298,17 @@
 dows/v7.
-0A
+1
 %22,%0A     
@@ -2323,25 +2323,8 @@
    %22
-C:/Program Files/
 Micr
@@ -2765,16 +2765,18 @@
 teIn
-Candidat
+ProgramFil
 es(S
@@ -2845,73 +2845,425 @@
 or (
-String candidateLocation : candidateLocations) %7B%0A            
+File candidate : programFileCandidates(candidateLocations)) %7B%0A            if (condition.isSatisfiedBy(candidate)) %7B%0A                return candidate;%0A            %7D%0A        %7D%0A        return null;%0A    %7D%0A%0A    private List%3CFile%3E programFileCandidates(String... candidateDirectory) %7B%0A        String programFiles = System.getenv(%22PROGRAMFILES%22);%0A        String programFilesX86 = programFiles + %22 (x86)%22;%0A%0A        List%3C
 File
+%3E
  can
@@ -3272,19 +3272,31 @@
 date
+s
  = new 
+ArrayList%3C
 File
+%3E
 (can
@@ -3301,24 +3301,36 @@
 andidate
-Location
+Directory.length * 2
 );%0A     
@@ -3336,101 +3336,206 @@
     
-  
-  if (condition.isSatisfiedBy(candidate)) %7B%0A                return candidate;%0A            %7D
+for (String candidateLocation : candidateDirectory) %7B%0A            candidates.add(new File(programFilesX86, candidateLocation));%0A            candidates.add(new File(programFiles, candidateLocation));
 %0A   
@@ -3548,36 +3548,42 @@
 %0A        return 
-null
+candidates
 ;%0A    %7D%0A%0A    pri

Use ProgramFiles environment variable to locate visual studio install