/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.apache.maven.plugins.resources.stub;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;

import org.apache.maven.model.Build;
import org.codehaus.plexus.util.FileUtils;

public class MavenProjectBuildStub extends MavenProjectBasicStub {
    protected Build build;

    protected String srcDirectory;

    protected String targetDirectory;

    protected String buildDirectory;

    protected String outputDirectory;

    protected String testOutputDirectory;

    protected String resourcesDirectory;

    protected String testResourcesDirectory;

    protected String targetResourceDirectory;

    protected String targetTestResourcesDirectory;

    protected ArrayList<String> fileList;

    protected ArrayList<String> directoryList;

    protected HashMap<String, String> dataMap;

    public MavenProjectBuildStub(String key) throws Exception {
        super(key);

        build = new Build();
        fileList = new ArrayList<>();
        directoryList = new ArrayList<>();
        dataMap = new HashMap<>();
        setupBuild();
    }

    public void addDirectory(String name) {
        if (isValidPath(name)) {
            directoryList.add(name);
        }
    }

    public void setOutputDirectory(String dir) {
        outputDirectory = buildDirectory + "/" + dir;
        build.setOutputDirectory(outputDirectory);
    }

    public void addFile(String name) {
        if (isValidPath(name)) {
            fileList.add(name);
        }
    }

    public void addFile(String name, String data) {
        File fileName = new File(name);

        addFile(name);
        dataMap.put(fileName.getName(), data);
    }

    public String getOutputDirectory() {
        return outputDirectory;
    }

    public String getTestOutputDirectory() {
        return testOutputDirectory;
    }

    public String getResourcesDirectory() {
        return resourcesDirectory;
    }

    public String getTestResourcesDirectory() {
        return testResourcesDirectory;
    }

    public Build getBuild() {
        return build;
    }

    /**
     * returns true if the path is relative
     * and false if absolute
     * also returns false if it is relative to
     * the parent
     *
     * @param path
     * @return
     */
    private boolean isValidPath(String path) {
        boolean bRetVal = true;

        if (path.startsWith("c:") || path.startsWith("..") || path.startsWith("/") || path.startsWith("\\")) {
            bRetVal = false;
        }

        return bRetVal;
    }

    private void setupBuild() {
        // check getBasedir method for the exact path
        // we need to recreate the dir structure in
        // an isolated environment
        srcDirectory = testRootDir + "/src";
        buildDirectory = testRootDir + "/target";
        outputDirectory = buildDirectory + "/classes";
        testOutputDirectory = buildDirectory + "/test-classes";
        resourcesDirectory = srcDirectory + "/main/resources/";
        testResourcesDirectory = srcDirectory + "/test/resources/";

        build.setDirectory(buildDirectory);
        build.setOutputDirectory(outputDirectory);
        build.setTestOutputDirectory(testOutputDirectory);
    }

    public void cleanBuildEnvironment() throws Exception {
        if (FileUtils.fileExists(resourcesDirectory)) {
            FileUtils.deleteDirectory(resourcesDirectory);
        }

        if (FileUtils.fileExists(testResourcesDirectory)) {
            FileUtils.deleteDirectory(testResourcesDirectory);
        }

        if (FileUtils.fileExists(outputDirectory)) {
            FileUtils.deleteDirectory(outputDirectory);
        }

        if (FileUtils.fileExists(testOutputDirectory)) {
            FileUtils.deleteDirectory(testOutputDirectory);
        }
    }

    public void setupBuildEnvironment() throws Exception {
        // populate dummy resources and dummy test resources

        // setup src dir
        if (!FileUtils.fileExists(resourcesDirectory)) {
            FileUtils.mkdir(resourcesDirectory);
        }

        if (!FileUtils.fileExists(testResourcesDirectory)) {
            FileUtils.mkdir(testResourcesDirectory);
        }

        createDirectories(resourcesDirectory, testResourcesDirectory);
        createFiles(resourcesDirectory, testResourcesDirectory);

        // setup target dir
        if (!FileUtils.fileExists(outputDirectory)) {
            FileUtils.mkdir(outputDirectory);
        }

        if (!FileUtils.fileExists(testOutputDirectory)) {
            FileUtils.mkdir(testOutputDirectory);
        }
    }

    private void createDirectories(String parent, String testparent) {
        File currentDirectory;

        for (String directory : directoryList) {
            currentDirectory = new File(parent, "/" + directory);

            if (!currentDirectory.exists()) {
                currentDirectory.mkdirs();
            }

            // duplicate dir structure in test resources
            currentDirectory = new File(testparent, "/" + directory);

            if (!currentDirectory.exists()) {
                currentDirectory.mkdirs();
            }
        }
    }

    private void createFiles(String parent, String testparent) throws IOException {
        File currentFile;

        for (String file : fileList) {
            currentFile = new File(parent, file);

            // create the necessary parent directories
            // before we create the files
            if (!currentFile.getParentFile().exists()) {
                currentFile.getParentFile().mkdirs();
            }

            if (!currentFile.exists()) {
                try {
                    currentFile.createNewFile();
                    populateFile(currentFile);
                } catch (IOException io) {
                    // TODO: handle exception
                }
            }

            // duplicate file in test resources
            currentFile = new File(testparent, file);

            if (!currentFile.getParentFile().exists()) {
                currentFile.getParentFile().mkdirs();
            }

            if (!currentFile.exists()) {
                currentFile.createNewFile();
                populateFile(currentFile);
            }
        }
    }

    private void populateFile(File file) throws IOException {
        String data = dataMap.get(file.getName());

        if ((data != null) && file.exists()) {
            try (FileOutputStream outputStream = new FileOutputStream(file)) {
                outputStream.write(data.getBytes());
            }
        }
    }
}
