/*
 * Licensed Materials - Property of IBM Corp.
 * IBM UrbanCode Deploy
 * (c) Copyright IBM Corporation 2014. All Rights Reserved.
 *
 * U.S. Government Users Restricted Rights - Use, duplication or disclosure restricted by
 * GSA ADP Schedule Contract with IBM Corp.
 */

package com.urbancode.air.plugin.artifactory

import java.io.File

import groovy.json.JsonSlurper

import java.security.NoSuchAlgorithmException

import org.apache.commons.lang.ObjectUtils
import org.apache.http.HttpResponse
import org.apache.http.HttpStatus
import org.apache.http.client.methods.HttpGet
import org.apache.http.client.methods.HttpPut
import org.apache.http.entity.StringEntity
import org.apache.http.entity.FileEntity
import org.apache.http.impl.client.DefaultHttpClient
import org.apache.http.util.EntityUtils

import org.jfrog.artifactory.client.ArtifactoryClient
import org.jfrog.artifactory.client.Artifactory

import com.urbancode.commons.fileutils.FileUtils
import com.urbancode.commons.fileutils.digest.DigestUtil
import com.urbancode.commons.httpcomponentsutil.HttpClientBuilder

public class ArtifactoryHelper {

    private final HttpClientBuilder builder = new HttpClientBuilder();
    private DefaultHttpClient client;
    private final ARTIFACT_FILE_HASH_ALGORITHM = "sha1";

    private String username;
    private String password;

    private void createClient() {
        builder.setUsername(username);
        builder.setPassword(password);
        builder.setPreemptiveAuthentication(true);
        client = builder.buildClient();
    }

    private List<File> findFiles(File baseDir, String fileNamePattern) {
        if ((!baseDir.exists()) || baseDir.isFile()) {
            throw new Exception("The base directory '" + baseDir.getPath() + "' does not exist or is a file");
        }
        String[] matchingFilePaths = FileUtils.getFileArray(baseDir, [fileNamePattern] as String[], [] as String[]);
        List<File> matchingFiles = new ArrayList<File>();
        for (String matchingFilePath : matchingFilePaths) {
            File file = new File(baseDir, matchingFilePath);
            if (file.isFile()) {
                matchingFiles.add(file);
            }
        }
        return matchingFiles;
    }
    //----------------------------------------------------------------------------------------------

    public ArtifactoryHelper(String username, String password) {
        this.username = username;
        this.password = password;
        createClient();
    }

    public void verifyHash(File fileToVerify, storedDigest) {
        if (storedDigest != null) {
            String computedDigest;
            try {
                computedDigest = DigestUtil.getHexDigest(fileToVerify, ARTIFACT_FILE_HASH_ALGORITHM);
                if (!ObjectUtils.equals(storedDigest, computedDigest)) {
                    throw new Exception("Artifact file verification of " + fileToVerify.getName() +
                    " failed. Expected digest of " + storedDigest + " but the downloaded file was " + computedDigest);
                }
            }
            catch (NoSuchAlgorithmException e) {
                throw new Exception("Algorithm to verify Maven remote artifacts not supported: " +
                ARTIFACT_FILE_HASH_ALGORITHM);
            }
            catch (IOException e) {
                throw new Exception("Error verifying downloaded Maven remote artifacts: " +
                e.getMessage(), e);
            }
        }
    }

    public Object[] searchArtifacts(String searchUrl) {
        HttpGet get = new HttpGet(searchUrl);
        HttpResponse response = client.execute(get);
        int status = response.getStatusLine().getStatusCode();
        if (status == HttpStatus.SC_OK) {
            def artifactUris = []
            def jsonString = EntityUtils.toString(response.getEntity());
            def slurper = new JsonSlurper();
            def resultArr = slurper.parseText(jsonString).results;
            for (result in resultArr) {
                artifactUris.add(result.uri)
            }
            return artifactUris;
        }
        else {
            throw new Exception("Exception searching: " + searchUrl + "\nErrorCode : " + status.toString());
        }
    }

    public File downloadFileFromRepo(String url, String checkHash) {
        HttpGet get = new HttpGet(url);
        HttpResponse response = client.execute(get);
        int status = response.getStatusLine().getStatusCode();
        if (status == HttpStatus.SC_OK) {
            def jsonString = EntityUtils.toString(response.getEntity());
            def slurper = new JsonSlurper();
            def infoJSON = slurper.parseText(jsonString);
            def checksumMap = infoJSON.checksums;
            def downloadUrl = infoJSON.downloadUri;
            System.out.println("Downloading: " + downloadUrl);
            get = new HttpGet(downloadUrl);
            response = client.execute(get);
            status = response.getStatusLine().getStatusCode();
            if (status == HttpStatus.SC_OK) {
                String tempFileSuffix = ".maven2";
                int extIndex = url.lastIndexOf(".");
                if (extIndex >= 0) {
                    tempFileSuffix = url.substring(extIndex);
                }
                File artifactFile = File.createTempFile("maven2-", tempFileSuffix);
                FileUtils.writeInputToFile(response.getEntity().getContent(), artifactFile);
                if (checkHash && Boolean.valueOf(checkHash)) {
                    //verify checksum
                    verifyHash(artifactFile, checksumMap.sha1);
                    System.out.println("Verification for file : " + artifactFile + " : succeeded!");
                }
                return artifactFile;
            } else {
                throw new Exception("Exception downloading file : " + downloadUrl + "\nErrorCode : " + status.toString());
            }
        }
    }

    public void uploadFileToRepo(String baseUrl, String repoName, String targetPath, File baseDir, String fileName) {
        List<File> fileList = findFiles(baseDir, fileName);
        println "Found " + fileList.size() + " file(s) matching the pattern '$fileName'";
        for (File file : fileList) {
            String uploadURL = baseUrl + "/" + repoName + "/" + targetPath + "/" + file.getName()
            println "Uploading file '" + file.getName() + "' to path '" + targetPath + "' of repository '" + repoName + "'"

            Artifactory artifactory = ArtifactoryClient.create(baseUrl, username, password);
            org.jfrog.artifactory.client.model.File result = artifactory.repository(repoName)
                    .upload(targetPath + "/"+ file.getName(), file).doUpload();
            String printMsg = "Upload done. Download url: " + result.getDownloadUri();
            println printMsg;
        }
    }
}
