/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * 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 com.android.compatibility.common.tradefed.testtype;

import com.android.compatibility.common.util.AbiUtils;
import com.android.compatibility.common.util.TestFilter;
import com.android.ddmlib.Log.LogLevel;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.config.ConfigurationException;
import com.android.tradefed.config.ConfigurationFactory;
import com.android.tradefed.config.IConfiguration;
import com.android.tradefed.config.IConfigurationFactory;
import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.testtype.IAbi;
import com.android.tradefed.testtype.IBuildReceiver;
import com.android.tradefed.testtype.IRemoteTest;
import com.android.tradefed.testtype.IShardableTest;
import com.android.tradefed.testtype.ITestFileFilterReceiver;
import com.android.tradefed.testtype.ITestFilterReceiver;
import com.android.tradefed.util.FileUtil;
import com.android.tradefed.util.TimeUtil;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * Retrieves Compatibility test module definitions from the repository.
 */
public class ModuleRepo implements IModuleRepo {

    private static final String CONFIG_EXT = ".config";
    private static final Map<String, Integer> ENDING_MODULES = new HashMap<>();
    static {
        ENDING_MODULES.put("CtsMonkeyTestCases", 1);
    }
    private static final long SMALL_TEST = TimeUnit.MINUTES.toMillis(2); // Small tests < 2mins
    private static final long MEDIUM_TEST = TimeUnit.MINUTES.toMillis(10); // Medium tests < 10mins

    private int mShards;
    private int mModulesPerShard;
    private int mSmallModulesPerShard;
    private int mMediumModulesPerShard;
    private int mLargeModulesPerShard;
    private int mModuleCount = 0;
    private Set<String> mSerials = new HashSet<>();
    private Map<String, Set<String>> mDeviceTokens = new HashMap<>();
    private Map<String, Map<String, String>> mTestArgs = new HashMap<>();
    private Map<String, Map<String, String>> mModuleArgs = new HashMap<>();
    private boolean mIncludeAll;
    private Map<String, List<TestFilter>> mIncludeFilters = new HashMap<>();
    private Map<String, List<TestFilter>> mExcludeFilters = new HashMap<>();
    private IConfigurationFactory mConfigFactory = ConfigurationFactory.getInstance();

    private volatile boolean mInitialized = false;
    // Whether the modules in this repo are ready to run on their assigned devices.
    // True until explicitly set false in setPrepared().
    private volatile boolean mPrepared = true;
    private CountDownLatch mPreparedLatch;

    // Holds all the small tests waiting to be run.
    private List<IModuleDef> mSmallModules = new ArrayList<>();
    // Holds all the medium tests waiting to be run.
    private List<IModuleDef> mMediumModules = new ArrayList<>();
    // Holds all the large tests waiting to be run.
    private List<IModuleDef> mLargeModules = new ArrayList<>();
    // Holds all the tests with tokens waiting to be run. Meaning the DUT must have a specific token.
    private List<IModuleDef> mTokenModules = new ArrayList<>();

    /**
     * {@inheritDoc}
     */
    @Override
    public int getNumberOfShards() {
        return mShards;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int getModulesPerShard() {
        return mModulesPerShard;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Map<String, Set<String>> getDeviceTokens() {
        return mDeviceTokens;
    }

    /**
     * A {@link FilenameFilter} to find all modules in a directory who match the given pattern.
     */
    public static class NameFilter implements FilenameFilter {

        private String mPattern;

        public NameFilter(String pattern) {
            mPattern = pattern;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public boolean accept(File dir, String name) {
            return name.contains(mPattern) && name.endsWith(CONFIG_EXT);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Set<String> getSerials() {
        return mSerials;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public List<IModuleDef> getSmallModules() {
        return mSmallModules;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public List<IModuleDef> getMediumModules() {
        return mMediumModules;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public List<IModuleDef> getLargeModules() {
        return mLargeModules;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public List<IModuleDef> getTokenModules() {
        return mTokenModules;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String[] getModuleIds() {
        Set<String> moduleIdSet = new HashSet<>();
        for (IModuleDef moduleDef : mSmallModules) {
            moduleIdSet.add(moduleDef.getId());
        }
        for (IModuleDef moduleDef : mMediumModules) {
            moduleIdSet.add(moduleDef.getId());
        }
        for (IModuleDef moduleDef : mLargeModules) {
            moduleIdSet.add(moduleDef.getId());
        }
        for (IModuleDef moduleDef : mTokenModules) {
            moduleIdSet.add(moduleDef.getId());
        }
        return moduleIdSet.toArray(new String[moduleIdSet.size()]);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isPrepared(long timeout, TimeUnit unit) {
        // returns true only if CountDownLatch reaches zero && no shards have setPrepared to false
        try {
            return (mPreparedLatch.await(timeout, unit)) ? mPrepared : false;
        } catch (InterruptedException e) {
            return false;
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void setPrepared(boolean isPrepared) {
        mPrepared &= isPrepared;
        mPreparedLatch.countDown();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isInitialized() {
        return mInitialized;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void initialize(int shards, File testsDir, Set<IAbi> abis, List<String> deviceTokens,
            List<String> testArgs, List<String> moduleArgs, Set<String> includeFilters,
            Set<String> excludeFilters, IBuildInfo buildInfo) {
        CLog.d("Initializing ModuleRepo\nShards:%d\nTests Dir:%s\nABIs:%s\nDevice Tokens:%s\n" +
                "Test Args:%s\nModule Args:%s\nIncludes:%s\nExcludes:%s",
                shards, testsDir.getAbsolutePath(), abis, deviceTokens, testArgs, moduleArgs,
                includeFilters, excludeFilters);
        mInitialized = true;
        mShards = shards;
        mPreparedLatch = new CountDownLatch(shards);
        for (String line : deviceTokens) {
            String[] parts = line.split(":");
            if (parts.length == 2) {
                String key = parts[0];
                String value = parts[1];
                Set<String> list = mDeviceTokens.get(key);
                if (list == null) {
                    list = new HashSet<>();
                    mDeviceTokens.put(key, list);
                }
                list.add(value);
            } else {
                throw new IllegalArgumentException(
                        String.format("Could not parse device token: %s", line));
            }
        }
        putArgs(testArgs, mTestArgs);
        putArgs(moduleArgs, mModuleArgs);
        mIncludeAll = includeFilters.isEmpty();
        // Include all the inclusions
        addFilters(includeFilters, mIncludeFilters, abis);
        // Exclude all the exclusions
        addFilters(excludeFilters, mExcludeFilters, abis);

        File[] configFiles = testsDir.listFiles(new ConfigFilter());
        if (configFiles.length == 0) {
            throw new IllegalArgumentException(
                    String.format("No config files found in %s", testsDir.getAbsolutePath()));
        }
        for (File configFile : configFiles) {
            final String name = configFile.getName().replace(CONFIG_EXT, "");
            final String[] pathArg = new String[] { configFile.getAbsolutePath() };
            try {
                // Invokes parser to process the test module config file
                // Need to generate a different config for each ABI as we cannot guarantee the
                // configs are idempotent. This however means we parse the same file multiple times
                for (IAbi abi : abis) {
                    IConfiguration config = mConfigFactory.createConfigurationFromArgs(pathArg);
                    String id = AbiUtils.createId(abi.getName(), name);
                    if (!shouldRunModule(id)) {
                        // If the module should not run tests based on the state of filters,
                        // skip this name/abi combination.
                        continue;
                    }
                    {
                        Map<String, String> args = new HashMap<>();
                        if (mModuleArgs.containsKey(name)) {
                            args.putAll(mModuleArgs.get(name));
                        }
                        if (mModuleArgs.containsKey(id)) {
                            args.putAll(mModuleArgs.get(id));
                        }
                        if (args != null && args.size() > 0) {
                            for (Entry<String, String> entry : args.entrySet()) {
                                config.injectOptionValue(entry.getKey(), entry.getValue());
                            }
                        }
                    }
                    List<IRemoteTest> tests = config.getTests();
                    for (IRemoteTest test : tests) {
                        String className = test.getClass().getName();
                        Map<String, String> args = new HashMap<>();
                        if (mTestArgs.containsKey(className)) {
                            args.putAll(mTestArgs.get(className));
                        }
                        if (args != null && args.size() > 0) {
                            for (Entry<String, String> entry : args.entrySet()) {
                                config.injectOptionValue(entry.getKey(), entry.getValue());
                            }
                        }
                        addFiltersToTest(test, abi, name);
                    }
                    List<IRemoteTest> shardedTests = tests;
                    if (mShards > 1) {
                         shardedTests = splitShardableTests(tests, buildInfo);
                    }
                    for (IRemoteTest test : shardedTests) {
                        if (test instanceof IBuildReceiver) {
                            ((IBuildReceiver)test).setBuild(buildInfo);
                        }
                        addModuleDef(name, abi, test, pathArg);
                    }
                }
            } catch (ConfigurationException e) {
                throw new RuntimeException(String.format("error parsing config file: %s",
                        configFile.getName()), e);
            }
        }
        mModulesPerShard = mModuleCount / shards;
        if (mModuleCount % shards != 0) {
            mModulesPerShard++; // Round up
        }
        mSmallModulesPerShard = mSmallModules.size() / shards;
        mMediumModulesPerShard = mMediumModules.size() / shards;
        mLargeModulesPerShard = mLargeModules.size() / shards;
    }

    private static List<IRemoteTest> splitShardableTests(List<IRemoteTest> tests,
            IBuildInfo buildInfo) {
        ArrayList<IRemoteTest> shardedList = new ArrayList<>(tests.size());
        for (IRemoteTest test : tests) {
            if (test instanceof IShardableTest) {
                if (test instanceof IBuildReceiver) {
                    ((IBuildReceiver)test).setBuild(buildInfo);
                }
                shardedList.addAll(((IShardableTest)test).split());
            } else {
                shardedList.add(test);
            }
        }
        return shardedList;
    }

    private static void addFilters(Set<String> stringFilters,
            Map<String, List<TestFilter>> filters, Set<IAbi> abis) {
        for (String filterString : stringFilters) {
            TestFilter filter = TestFilter.createFrom(filterString);
            String abi = filter.getAbi();
            if (abi == null) {
                for (IAbi a : abis) {
                    addFilter(a.getName(), filter, filters);
                }
            } else {
                addFilter(abi, filter, filters);
            }
        }
    }

    private static void addFilter(String abi, TestFilter filter,
            Map<String, List<TestFilter>> filters) {
        getFilter(filters, AbiUtils.createId(abi, filter.getName())).add(filter);
    }

    private static List<TestFilter> getFilter(Map<String, List<TestFilter>> filters, String id) {
        List<TestFilter> fs = filters.get(id);
        if (fs == null) {
            fs = new ArrayList<>();
            filters.put(id, fs);
        }
        return fs;
    }

    private void addModuleDef(String name, IAbi abi, IRemoteTest test,
            String[] configPaths) throws ConfigurationException {
        // Invokes parser to process the test module config file
        IConfiguration config = mConfigFactory.createConfigurationFromArgs(configPaths);
        addModuleDef(new ModuleDef(name, abi, test, config.getTargetPreparers()));
    }

    private void addModuleDef(IModuleDef moduleDef) {
        Set<String> tokens = moduleDef.getTokens();
        if (tokens != null && !tokens.isEmpty()) {
            mTokenModules.add(moduleDef);
        } else if (moduleDef.getRuntimeHint() < SMALL_TEST) {
            mSmallModules.add(moduleDef);
        } else if (moduleDef.getRuntimeHint() < MEDIUM_TEST) {
            mMediumModules.add(moduleDef);
        } else {
            mLargeModules.add(moduleDef);
        }
        mModuleCount++;
    }

    private void addFiltersToTest(IRemoteTest test, IAbi abi, String name) {
        String moduleId = AbiUtils.createId(abi.getName(), name);
        if (!(test instanceof ITestFilterReceiver)) {
            throw new IllegalArgumentException(String.format(
                    "Test in module %s must implement ITestFilterReceiver.", moduleId));
        }
        List<TestFilter> mdIncludes = getFilter(mIncludeFilters, moduleId);
        List<TestFilter> mdExcludes = getFilter(mExcludeFilters, moduleId);
        if (!mdIncludes.isEmpty()) {
            addTestIncludes((ITestFilterReceiver) test, mdIncludes, name);
        }
        if (!mdExcludes.isEmpty()) {
            addTestExcludes((ITestFilterReceiver) test, mdExcludes, name);
        }
    }

    private boolean shouldRunModule(String moduleId) {
        List<TestFilter> mdIncludes = getFilter(mIncludeFilters, moduleId);
        List<TestFilter> mdExcludes = getFilter(mExcludeFilters, moduleId);
        // if including all modules or includes exist for this module, and there are not excludes
        // for the entire module, this module should be run.
        return (mIncludeAll || !mdIncludes.isEmpty()) && !containsModuleExclude(mdExcludes);
    }

    private void addTestIncludes(ITestFilterReceiver test, List<TestFilter> includes,
            String name) {
        if (test instanceof ITestFileFilterReceiver) {
            File includeFile = createFilterFile(name, ".include", includes);
            ((ITestFileFilterReceiver)test).setIncludeTestFile(includeFile);
        } else {
            // add test includes one at a time
            for (TestFilter include : includes) {
                String filterTestName = include.getTest();
                if (filterTestName != null) {
                    test.addIncludeFilter(filterTestName);
                }
            }
        }
    }

    private void addTestExcludes(ITestFilterReceiver test, List<TestFilter> excludes,
            String name) {
        if (test instanceof ITestFileFilterReceiver) {
            File excludeFile = createFilterFile(name, ".exclude", excludes);
            ((ITestFileFilterReceiver)test).setExcludeTestFile(excludeFile);
        } else {
            // add test excludes one at a time
            for (TestFilter exclude : excludes) {
                test.addExcludeFilter(exclude.getTest());
            }
        }
    }

    private File createFilterFile(String prefix, String suffix, List<TestFilter> filters) {
        File filterFile = null;
        PrintWriter out = null;
        try {
            filterFile = FileUtil.createTempFile(prefix, suffix);
            out = new PrintWriter(filterFile);
            for (TestFilter filter : filters) {
                String filterTest = filter.getTest();
                if (filterTest != null) {
                    out.println(filterTest);
                }
            }
            out.flush();
        } catch (IOException e) {
            throw new RuntimeException("Failed to create filter file");
        } finally {
            if (out != null) {
                out.close();
            }
        }
        filterFile.deleteOnExit();
        return filterFile;
    }

    /*
     * Returns true iff one or more test filters in excludes apply to the entire module.
     */
    private boolean containsModuleExclude(Collection<TestFilter> excludes) {
        for (TestFilter exclude : excludes) {
            if (exclude.getTest() == null) {
                return true;
            }
        }
        return false;
    }

    /**
     * A {@link FilenameFilter} to find all the config files in a directory.
     */
    public static class ConfigFilter implements FilenameFilter {

        /**
         * {@inheritDoc}
         */
        @Override
        public boolean accept(File dir, String name) {
            CLog.d("%s/%s", dir.getAbsolutePath(), name);
            return name.endsWith(CONFIG_EXT);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public synchronized List<IModuleDef> getModules(String serial) {
        List<IModuleDef> modules = new ArrayList<>(mModulesPerShard);
        Set<String> tokens = mDeviceTokens.get(serial);
        getModulesWithTokens(tokens, modules);
        getModules(modules);
        mSerials.add(serial);
        if (mSerials.size() == mShards) {
            for (IModuleDef def : mTokenModules) {
                CLog.logAndDisplay(LogLevel.WARN,
                        String.format("No devices found with %s, running %s on %s",
                                def.getTokens(), def.getId(), serial));
                modules.add(def);
            }
            // Add left over modules
            modules.addAll(mLargeModules);
            modules.addAll(mMediumModules);
            modules.addAll(mSmallModules);
        }
        long estimatedTime = 0;
        for (IModuleDef def : modules) {
            estimatedTime += def.getRuntimeHint();
        }
        Collections.sort(modules, new ExecutionOrderComparator());
        CLog.logAndDisplay(LogLevel.INFO, String.format(
                "%s running %s modules, expected to complete in %s",
                serial, modules.size(), TimeUtil.formatElapsedTime(estimatedTime)));
        return modules;
    }

    /**
     * Iterates through the remaining tests that require tokens and if the device has all the
     * required tokens it will queue that module to run on that device, else the module gets put
     * back into the list.
     */
    private void getModulesWithTokens(Set<String> tokens, List<IModuleDef> modules) {
        if (tokens != null) {
            List<IModuleDef> copy = mTokenModules;
            mTokenModules = new ArrayList<>();
            for (IModuleDef module : copy) {
                // If a device has all the tokens required by the module then it can run it.
                if (tokens.containsAll(module.getTokens())) {
                    modules.add(module);
                } else {
                    mTokenModules.add(module);
                }
            }
        }
    }

    /**
     * Adds count modules that do not require tokens, to run on a device.
     */
    private void getModules(List<IModuleDef> modules) {
        // Take the normal share of modules unless the device already has token modules.
        takeModule(mSmallModules, modules, mSmallModulesPerShard - modules.size());
        takeModule(mMediumModules, modules, mMediumModulesPerShard);
        takeModule(mLargeModules, modules, mLargeModulesPerShard);
        // If one bucket runs out, take from any of the others.
        boolean success = true;
        while (success && modules.size() < mModulesPerShard) {
            // Take modules from the buckets until it has enough, or there are no more modules.
            success = takeModule(mSmallModules, modules, 1)
                    || takeModule(mMediumModules, modules, 1)
                    || takeModule(mLargeModules, modules, 1);
        }
    }

    /**
     * Takes count modules from the first list and move it to the second.
     */
    private static boolean takeModule(
            List<IModuleDef> source, List<IModuleDef> destination, int count) {
        if (source.isEmpty()) {
            return false;
        }
        if (count > source.size()) {
            count = source.size();
        }
        for (int i = 0; i < count; i++) {
            destination.add(source.remove(source.size() - 1));// Take from the end of the arraylist.
        }
        return true;
    }

    /**
     * @return the {@link List} of modules whose name contains the given pattern.
     */
    public static List<String> getModuleNamesMatching(File directory, String pattern) {
        String[] names = directory.list(new NameFilter(pattern));
        List<String> modules = new ArrayList<String>(names.length);
        for (String name : names) {
            int index = name.indexOf(CONFIG_EXT);
            if (index > 0) {
                String module = name.substring(0, index);
                if (module.equals(pattern)) {
                    // Pattern represents a single module, just return a single-item list
                    modules = new ArrayList<>(1);
                    modules.add(module);
                    return modules;
                }
                modules.add(module);
            }
        }
        return modules;
    }

    private static void putArgs(List<String> args, Map<String, Map<String, String>> argsMap) {
        for (String arg : args) {
            String[] parts = arg.split(":");
            String target = parts[0];
            String key = parts[1];
            String value = parts[2];
            Map<String, String> map = argsMap.get(target);
            if (map == null) {
                map = new HashMap<>();
                argsMap.put(target, map);
            }
            map.put(key, value);
        }
    }

    private static class ExecutionOrderComparator implements Comparator<IModuleDef> {

        @Override
        public int compare(IModuleDef def1, IModuleDef def2) {
            int value1 = 0;
            int value2 = 0;
            if (ENDING_MODULES.containsKey(def1.getName())) {
                value1 = ENDING_MODULES.get(def1.getName());
            }
            if (ENDING_MODULES.containsKey(def2.getName())) {
                value2 = ENDING_MODULES.get(def2.getName());
            }
            if (value1 == 0 && value2 == 0) {
                return (int) Math.signum(def2.getRuntimeHint() - def1.getRuntimeHint());
            }
            return (int) Math.signum(value1 - value2);
        }
    }
}
