/*
 * 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.creadur.tentacles;

import static org.apache.creadur.tentacles.LicenseType.loadLicensesFrom;
import static org.apache.creadur.tentacles.RepositoryType.HTTP;
import static org.apache.creadur.tentacles.RepositoryType.LOCAL_FILE_SYSTEM;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import org.apache.logging.log4j.*;

public class Main {

    static {
/* TENTACLES-12: disabled root logger configuration       
        final Logger root = LogManager.getRootLogger();
        root.addAppender(new ConsoleAppender(new PatternLayout(
                PatternLayout.TTCC_CONVERSION_PATTERN)));
        root.setLevel(Level.INFO);
        */
    }

    private static final Logger log = LogManager.getLogger(Main.class);
    private static final String CRAWL_PATTERN = ".*\\.(jar|zip|war|ear|rar|tar.gz)";

    private final Reports reports;
    private final Licenses licenses;

    private final Layout layout;
    private final Platform platform;
    private final Configuration configuration;
    private final FileSystem fileSystem;
    private final IOSystem ioSystem;
    private final TentaclesResources tentaclesResources;
    private final Templates templates;

    public Main(final String... args) throws Exception {
        this(new Configuration(args), Platform.aPlatform());
    }

    public Main(final Configuration configuration, final Platform platform)
            throws Exception {
        this(configuration, platform, new Templates(platform), new Layout(
                platform, configuration));
    }

    public Main(final Configuration configuration, final Platform platform,
            final Templates templates, final Layout layout) throws Exception {
        this.platform = platform;
        this.configuration = configuration;
        this.layout = layout;
        this.fileSystem = platform.getFileSystem();
        this.ioSystem = platform.getIoSystem();
        this.tentaclesResources = platform.getTentaclesResources();
        this.templates = templates;

        this.reports = new Reports();

        log.info("Remote repository: "
                + this.configuration.getStagingRepositoryURI());
        log.info("Local root directory: " + this.layout.getLocalRootDirectory());

        this.tentaclesResources.copyTo("legal/style.css",
                new File(this.layout.getOutputDirectory(), "style.css"));

        this.licenses = loadLicensesFrom(platform);
    }

    public static void main(final String[] args) throws Exception {
    	
    	log.info("Launching Apache Tentacles ...");
    	
    	if(args == null || args.length < 1) {
    		log.error("Error: Input parameter missing - you did not specify any component to run Apache Tentacles on.");
    		log.error("Please launch Apache Tentacles with an URI to work on such as 'https://repository.apache.org/content/repositories/orgapachecreadur-1000/'.");
    	} else {
    		new Main(args).main();
    	}
    	
    }

    private void main() throws Exception {

        unpackContents(mirrorRepositoryFrom(this.configuration));

        reportOn(archivesIn(this.layout.getRepositoryDirectory()));
    }

    private List<Archive> archivesIn(final File repository) {
        final List<File> jars = this.fileSystem.documentsFrom(repository);

        final List<Archive> archives = new ArrayList<Archive>();
        for (final File file : jars) {
            final Archive archive =
                    new Archive(file, this.fileSystem, this.layout);
            archives.add(archive);
        }
        return archives;
    }

    private void reportOn(final List<Archive> archives) throws IOException {
        this.templates
                .template("legal/archives.vm")
                .add("archives", archives)
                .add("reports", this.reports)
                .write(new File(this.layout.getOutputDirectory(),
                        "archives.html"));

        reportLicenses(archives);
        reportNotices(archives);
        reportDeclaredLicenses(archives);
        reportDeclaredNotices(archives);
    }

    private void reportLicenses(final List<Archive> archives)
            throws IOException {
        initLicenses(archives);

        this.templates
                .template("legal/licenses.vm")
                .add("licenses", getLicenses(archives))
                .add("reports", this.reports)
                .write(new File(this.layout.getOutputDirectory(),
                        "licenses.html"));
    }

    private void initLicenses(final List<Archive> archives) throws IOException {
        final Map<License, License> licenses = new HashMap<License, License>();

        for (final Archive archive : archives) {
            final List<File> files =
                    this.fileSystem.licensesFrom(archive.contentsDirectory());
            for (final File file : files) {
                final License license = this.licenses.from(file);

                License existing = licenses.get(license);
                if (existing == null) {
                    licenses.put(license, license);
                    existing = license;
                }

                existing.getLocations().add(file);
                existing.getArchives().add(archive);
                archive.getLicenses().add(existing);
            }
        }
    }

    private Collection<License> getLicenses(final List<Archive> archives) {
        final Set<License> licenses = new LinkedHashSet<License>();
        for (final Archive archive : archives) {
            licenses.addAll(archive.getLicenses());
        }
        return licenses;
    }

    private void reportDeclaredLicenses(final List<Archive> archives)
            throws IOException {

        for (final Archive archive : archives) {

            classifyLicenses(archive);
        }
        for (final Archive archive : archives) {

            this.templates
                    .template("legal/archive-licenses.vm")
                    .add("archive", archive)
                    .add("reports", this.reports)
                    .write(new File(this.layout.getOutputDirectory(),
                            this.reports.licenses(archive)));
        }

    }

    private void classifyLicenses(final Archive archive) throws IOException {
        final Set<License> undeclared =
                new HashSet<License>(archive.getLicenses());

        final File contents = archive.contentsDirectory();
        final List<File> files = this.fileSystem.licensesDeclaredIn(contents);

        for (final File file : files) {

            undeclared.remove(this.licenses.from(file));

        }

        archive.getOtherLicenses().addAll(undeclared);

        final Set<License> declared =
                new HashSet<License>(archive.getLicenses());
        declared.removeAll(undeclared);
        archive.getDeclaredLicenses().addAll(declared);

        for (final License license : undeclared) {

            for (final License declare : declared) {
                if (license.implies(declare)) {
                    archive.getOtherLicenses().remove(license);
                }
            }
        }
    }

    private void reportDeclaredNotices(final List<Archive> archives)
            throws IOException {

        for (final Archive archive : archives) {

            final Set<Notice> undeclared =
                    new HashSet<Notice>(archive.getNotices());

            final File contents = archive.contentsDirectory();
            final List<File> files =
                    this.fileSystem.noticesDeclaredIn(contents);

            for (final File file : files) {

                final Notice notice = new Notice(this.ioSystem.slurp(file));

                undeclared.remove(notice);
            }

            archive.getOtherNotices().addAll(undeclared);

            final Set<Notice> declared =
                    new HashSet<Notice>(archive.getNotices());
            declared.removeAll(undeclared);
            archive.getDeclaredNotices().addAll(declared);

            for (final Notice notice : undeclared) {

                for (final Notice declare : declared) {
                    if (notice.implies(declare)) {
                        archive.getOtherLicenses().remove(notice);
                    }
                }
            }

            this.templates
                    .template("legal/archive-notices.vm")
                    .add("archive", archive)
                    .add("reports", this.reports)
                    .write(new File(this.layout.getOutputDirectory(),
                            this.reports.notices(archive)));
        }
    }

    private void reportNotices(final List<Archive> archives) throws IOException {
        final Map<Notice, Notice> notices = new HashMap<Notice, Notice>();

        for (final Archive archive : archives) {
            final List<File> noticeDocuments =
                    this.fileSystem.noticesOnly(archive.contentsDirectory());
            for (final File file : noticeDocuments) {
                final Notice notice = new Notice(this.ioSystem.slurp(file));

                Notice existing = notices.get(notice);
                if (existing == null) {
                    notices.put(notice, notice);
                    existing = notice;
                }

                existing.getLocations().add(file);
                existing.getArchives().add(archive);
                archive.getNotices().add(existing);
            }
        }

        this.templates
                .template("legal/notices.vm")
                .add("notices", notices.values())
                .add("reports", this.reports)
                .write(new File(this.layout.getOutputDirectory(),
                        "notices.html"));
    }

    private void unpackContents(final Set<File> files) throws IOException {
        for (final File file : files) {
            unpack(file);
        }
    }

    private Set<File> mirrorRepositoryFrom(final Configuration configuration)
            throws IOException {
        final Set<File> files = new HashSet<File>();
        if (HTTP.isRepositoryFor(configuration)) {
            final NexusClient client = new NexusClient(this.platform);
            final Set<URI> resources =
                    client.crawl(configuration.getStagingRepositoryURI());

            for (final URI uri : resources) {
                if (!uri.getPath().matches(CRAWL_PATTERN)) {
                    continue;
                }
                files.add(client.download(uri, mirroredFrom(uri)));
            }
        } else if (LOCAL_FILE_SYSTEM.isRepositoryFor(configuration)) {
            final File file = new File(configuration.getStagingRepositoryURI());
            final List<File> collect =
                    this.platform.getFileSystem().archivesInPath(file,
                            configuration.getFileRepositoryPathNameFilter());

            for (final File f : collect) {
                files.add(copyToMirror(f));
            }
        }
        return files;
    }

    private void unpack(final File archive) throws IOException {
        log.info("Unpack " + archive);

        try {
            final ZipInputStream zip = this.ioSystem.unzip(archive);

            final File contents =
                    new Archive(archive, this.fileSystem, this.layout)
                            .contentsDirectory();

            try {
                ZipEntry entry = null;

                while ((entry = zip.getNextEntry()) != null) {

                    if (entry.isDirectory()) {
                        continue;
                    }

                    final String path = entry.getName();

                    final File fileEntry = new File(contents, path);

                    this.fileSystem.mkparent(fileEntry);

                    // Open the output file

                    this.ioSystem.copy(zip, fileEntry);

                    if (fileEntry.getName().endsWith(".jar")) {
                        unpack(fileEntry);
                    }
                }
            } finally {
                this.ioSystem.close(zip);
            }
        } catch (final IOException e) {
            log.error("Not a zip " + archive);
        }
    }

    private File copyToMirror(final File src) throws IOException {
        final URI uri = src.toURI();

        final File file = mirroredFrom(uri);

        log.info("Copy " + uri);

        this.fileSystem.mkparent(file);

        this.ioSystem.copy(this.ioSystem.read(src), file);

        return file;
    }

    private File mirroredFrom(final URI uri) {
        final String name =
                uri.toString()
                        .replace(
                                this.configuration.getStagingRepositoryURI()
                                        .toString(), "").replaceFirst("^/", "");
        return new File(this.layout.getRepositoryDirectory(), name);
    }

}
