package net.cijber.pubgrub import net.cijber.pubgrub.packages.PackageSelection import net.cijber.pubgrub.stubs.PackageId import net.cijber.pubgrub.stubs.Version import net.cijber.pubgrub.version.VersionConstraint open class Term

>(val pkgSelection: PackageSelection, val exclusive: Boolean) { val constraint get() = pkgSelection.constraint val pkg get() = pkgSelection.pkg val inverse by lazy { Term(pkgSelection, !exclusive) } infix fun relation(rhs: Term): SetRelation { if (rhs.pkg !== pkg) { throw RuntimeException("Relations between terms can only be compared if they have the same package id") } val rhsConstraint = rhs.constraint if (!rhs.exclusive) { if (exclusive) { if (rhsConstraint.allowsAll(constraint)) return SetRelation.Subset } } return SetRelation.Disjoint } fun intersect(rhs: Term): Term? { if (rhs.pkg !== pkg) { throw RuntimeException("Relations between terms can only be compared if they have the same package id") } return if (exclusive != rhs.exclusive) { val positive = if (!exclusive) this else rhs val negative = if (!exclusive) rhs else this nonEmptyTerm(positive.constraint.difference(negative.constraint), false) } else if (!exclusive) { nonEmptyTerm(constraint.intersect(rhs.constraint), false) } else { nonEmptyTerm(constraint.union(rhs.constraint), true) } } private fun nonEmptyTerm(constraint: VersionConstraint, exclusive: Boolean): Term? { if (constraint.isEmpty) return null return Term(PackageSelection(pkg, constraint), exclusive) } fun satisfies(term: Term): Boolean = term.pkg == pkg && (relation(term) == SetRelation.Subset || relation(term) == SetRelation.Equal) fun difference(rhs: Term) = intersect(rhs.inverse) }