/*
 * Copyright 2018 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.api.internal.tasks.compile.incremental.processing;

import org.gradle.api.internal.tasks.compile.incremental.compilerapi.deps.GeneratedResource;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Contains all the data necessary to make annotation processing incremental.
 */
public class AnnotationProcessingResult implements Serializable {

    private final Map<String, Set<String>> generatedTypesByOrigin = new LinkedHashMap<>();
    private final Map<String, Set<GeneratedResource>> generatedResourcesByOrigin = new LinkedHashMap<>();
    private final Set<String> aggregatedTypes = new HashSet<>();
    private final Set<String> generatedTypesDependingOnAllOthers = new HashSet<>();
    private final Set<GeneratedResource> getGeneratedResourcesDependingOnAllOthers = new HashSet<>();
    private final List<AnnotationProcessorResult> annotationProcessorResults = new ArrayList<>();
    private String fullRebuildCause;

    public void addGeneratedType(String name, Set<String> originatingElements) {
        for (String originatingElement : originatingElements) {
            Set<String> derived = generatedTypesByOrigin.get(originatingElement);
            if (derived == null) {
                derived = new LinkedHashSet<>();
                generatedTypesByOrigin.put(originatingElement, derived);
            }
            derived.add(name);
        }
    }

    public void addGeneratedResource(GeneratedResource resource, Set<String> originatingElements) {
        for (String originatingElement : originatingElements) {
            Set<GeneratedResource> derived = generatedResourcesByOrigin.get(originatingElement);
            if (derived == null) {
                derived = new LinkedHashSet<>();
                generatedResourcesByOrigin.put(originatingElement, derived);
            }
            derived.add(resource);
        }
    }

    /**
     * Contains the types generated by isolating annotation processors, grouped by the type they were generated from.
     */
    public Map<String, Set<String>> getGeneratedTypesWithIsolatedOrigin() {
        return generatedTypesByOrigin;
    }

    /**
     * Contains the resources generated by isolating annotation processors, grouped by the type they were generated from.
     */
    public Map<String, Set<GeneratedResource>> getGeneratedResourcesWithIsolatedOrigin() {
        return generatedResourcesByOrigin;
    }

    /**
     * Contains the types that aggregating annotation processors registered themselves for.
     * These types need to be reprocessed no matter what source changes are made to ensure that the generated types contain all relevant information.
     */
    public Set<String> getAggregatedTypes() {
        return aggregatedTypes;
    }

    /**
     * Contains the types that aggregating annotation processors generated.
     * These types need to be recompiled on any source change, because it may not be clear where these types came from and whether they are now stale.
     */
    public Set<String> getGeneratedAggregatingTypes() {
        return generatedTypesDependingOnAllOthers;
    }

    /**
     * Contains the resources that aggregating annotation processors generated.
     * These resources need to be recreated on any source change, because it may not be clear where these resources came from and whether they are now stale.
     */
    public Set<GeneratedResource> getGeneratedAggregatingResources() {
        return getGeneratedResourcesDependingOnAllOthers;
    }

    public void setFullRebuildCause(String fullRebuildCause) {
        this.fullRebuildCause = fullRebuildCause;
    }

    public String getFullRebuildCause() {
        return fullRebuildCause;
    }

    public List<AnnotationProcessorResult> getAnnotationProcessorResults() {
        return annotationProcessorResults;
    }
}
