// Copyright 2021 Google LLC
//
// 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 compliance

import (
	"sync"
)

var (
	// AllResolutions is a TraceConditions function that resolves all
	// unfiltered license conditions.
	AllResolutions = TraceConditions(func(tn *TargetNode) LicenseConditionSet { return tn.licenseConditions })
)

// TraceConditions is a function that returns the conditions to trace for each
// target node `tn`.
type TraceConditions func(tn *TargetNode) LicenseConditionSet

// ResolveBottomUpConditions performs a bottom-up walk of the LicenseGraph
// propagating conditions up the graph as necessary according to the properties
// of each edge and according to each license condition in question.
//
// e.g. if a "restricted" condition applies to a binary, it also applies to all
// of the statically-linked libraries and the transitive closure of their static
// dependencies; even if neither they nor the transitive closure of their
// dependencies originate any "restricted" conditions. The bottom-up walk will
// not resolve the library and its transitive closure, but the later top-down
// walk will.
func ResolveBottomUpConditions(lg *LicenseGraph) {
	TraceBottomUpConditions(lg, AllResolutions)
}

// TraceBottomUpConditions performs a bottom-up walk of the LicenseGraph
// propagating trace conditions from `conditionsFn` up the graph as necessary
// according to the properties of each edge and according to each license
// condition in question.
func TraceBottomUpConditions(lg *LicenseGraph, conditionsFn TraceConditions) {

	// short-cut if already walked and cached
	lg.mu.Lock()
	wg := lg.wgBU

	if wg != nil {
		lg.mu.Unlock()
		wg.Wait()
		return
	}
	wg = &sync.WaitGroup{}
	wg.Add(1)
	lg.wgBU = wg
	lg.mu.Unlock()

	// amap identifes targets previously walked. (guarded by mu)
	amap := make(map[*TargetNode]struct{})

	// mu guards concurrent access to amap
	var mu sync.Mutex

	var walk func(target *TargetNode, treatAsAggregate bool) LicenseConditionSet

	walk = func(target *TargetNode, treatAsAggregate bool) LicenseConditionSet {
		priorWalkResults := func() (LicenseConditionSet, bool) {
			mu.Lock()
			defer mu.Unlock()

			if _, alreadyWalked := amap[target]; alreadyWalked {
				if treatAsAggregate {
					return target.resolution, true
				}
				if !target.pure {
					return target.resolution, true
				}
				// previously walked in a pure aggregate context,
				// needs to walk again in non-aggregate context
			} else {
				target.resolution |= conditionsFn(target)
				amap[target] = struct{}{}
			}
			target.pure = treatAsAggregate
			return target.resolution, false
		}
		cs, alreadyWalked := priorWalkResults()
		if alreadyWalked {
			return cs
		}

		c := make(chan LicenseConditionSet, len(target.edges))
		// add all the conditions from all the dependencies
		for _, edge := range target.edges {
			go func(edge *TargetEdge) {
				// walk dependency to get its conditions
				cs := walk(edge.dependency, treatAsAggregate && edge.dependency.IsContainer())

				// turn those into the conditions that apply to the target
				cs = depConditionsPropagatingToTarget(lg, edge, cs, treatAsAggregate)

				c <- cs
			}(edge)
		}
		for i := 0; i < len(target.edges); i++ {
			cs |= <-c
		}
		mu.Lock()
		target.resolution |= cs
		mu.Unlock()

		// return conditions up the tree
		return cs
	}

	// walk each of the roots
	for _, rname := range lg.rootFiles {
		rnode := lg.targets[rname]
		_ = walk(rnode, rnode.IsContainer())
	}

	wg.Done()
}

// ResolveTopDownCondtions performs a top-down walk of the LicenseGraph
// propagating conditions from target to dependency.
//
// e.g. For current policy, none of the conditions propagate from target to
// dependency except restricted. For restricted, the policy is to share the
// source of any libraries linked to restricted code and to provide notice.
func ResolveTopDownConditions(lg *LicenseGraph) {
	TraceTopDownConditions(lg, AllResolutions)
}

// TraceTopDownCondtions performs a top-down walk of the LicenseGraph
// propagating trace conditions returned by `conditionsFn` from target to
// dependency.
func TraceTopDownConditions(lg *LicenseGraph, conditionsFn TraceConditions) {

	// short-cut if already walked and cached
	lg.mu.Lock()
	wg := lg.wgTD

	if wg != nil {
		lg.mu.Unlock()
		wg.Wait()
		return
	}
	wg = &sync.WaitGroup{}
	wg.Add(1)
	lg.wgTD = wg
	lg.mu.Unlock()

	// start with the conditions propagated up the graph
	TraceBottomUpConditions(lg, conditionsFn)

	// amap contains the set of targets already walked. (guarded by mu)
	amap := make(map[*TargetNode]struct{})

	// mu guards concurrent access to amap
	var mu sync.Mutex

	var walk func(fnode *TargetNode, cs LicenseConditionSet, treatAsAggregate bool)

	walk = func(fnode *TargetNode, cs LicenseConditionSet, treatAsAggregate bool) {
		defer wg.Done()
		mu.Lock()
		fnode.resolution |= conditionsFn(fnode)
		fnode.resolution |= cs
		fnode.pure = treatAsAggregate
		amap[fnode] = struct{}{}
		cs = fnode.resolution
		mu.Unlock()
		// for each dependency
		for _, edge := range fnode.edges {
			func(edge *TargetEdge) {
				// dcs holds the dpendency conditions inherited from the target
				dcs := targetConditionsPropagatingToDep(lg, edge, cs, treatAsAggregate, conditionsFn)
				dnode := edge.dependency
				mu.Lock()
				defer mu.Unlock()
				depcs := dnode.resolution
				_, alreadyWalked := amap[dnode]
				if !dcs.IsEmpty() && alreadyWalked {
					if dcs.Difference(depcs).IsEmpty() {
						// no new conditions

						// pure aggregates never need walking a 2nd time with same conditions
						if treatAsAggregate {
							return
						}
						// non-aggregates don't need walking as non-aggregate a 2nd time
						if !dnode.pure {
							return
						}
						// previously walked as pure aggregate; need to re-walk as non-aggregate
					}
				}
				// add the conditions to the dependency
				wg.Add(1)
				go walk(dnode, dcs, treatAsAggregate && dnode.IsContainer())
			}(edge)
		}
	}

	// walk each of the roots
	for _, rname := range lg.rootFiles {
		rnode := lg.targets[rname]
		wg.Add(1)
		// add the conditions to the root and its transitive closure
		go walk(rnode, NewLicenseConditionSet(), rnode.IsContainer())
	}
	wg.Done()
	wg.Wait()
}
