func constraintTilde(v *Version, c *constraint) bool {
	if v.Prerelease() != "" && c.con.Prerelease() == "" {
		return false
	}
	if v.LessThan(c.con) {
		return false
	}
	if c.con.Major() == 0 && c.con.Minor() == 0 && c.con.Patch() == 0 &&
		!c.minorDirty && !c.patchDirty {
		return true
	}
	if v.Major() != c.con.Major() {
		return false
	}
	if v.Minor() != c.con.Minor() && !c.minorDirty {
		return false
	}
	return true
}
~*, ~>* --> >= 0.0.0 (any)
~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0, <3.0.0
~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0, <2.1.0
~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0, <1.3.0
~1.2.3, ~>1.2.3 --> >=1.2.3, <1.3.0
~1.2.0, ~>1.2.0 --> >=1.2.0, <1.3.0
package semver
import (
	"errors"
	"fmt"
	"regexp"
	"strings"
)
type Constraints struct {
	constraints [][]*constraint
}
func NewConstraint(c string) (*Constraints, error) {
	c = rewriteRange(c)
	ors := strings.Split(c, "||")
	or := make([][]*constraint, len(ors))
	for k, v := range ors {
		cs := strings.Split(v, ",")
		result := make([]*constraint, len(cs))
		for i, s := range cs {
			pc, err := parseConstraint(s)
			if err != nil {
				return nil, err
			}
			result[i] = pc
		}
		or[k] = result
	}
	o := &Constraints{constraints: or}
	return o, nil
}
func (cs Constraints) Check(v *Version) bool {
	for _, o := range cs.constraints {
		joy := true
		for _, c := range o {
			if !c.check(v) {
				joy = false
				break
			}
		}
		if joy {
			return true
		}
	}
	return false
}
func (cs Constraints) Validate(v *Version) (bool, []error) {
	var e []error
	for _, o := range cs.constraints {
		joy := true
		for _, c := range o {
			if !c.check(v) {
				em := fmt.Errorf(c.msg, v, c.orig)
				e = append(e, em)
				joy = false
			}
		}
		if joy {
			return true, []error{}
		}
	}
	return false, e
}
var constraintOps map[string]cfunc
var constraintMsg map[string]string
var constraintRegex *regexp.Regexp
func init() {
	constraintOps = map[string]cfunc{
		"":   constraintTildeOrEqual,
		"=":  constraintTildeOrEqual,
		"!=": constraintNotEqual,
		">":  constraintGreaterThan,
		"<":  constraintLessThan,
		">=": constraintGreaterThanEqual,
		"=>": constraintGreaterThanEqual,
		"<=": constraintLessThanEqual,
		"=<": constraintLessThanEqual,
		"~":  constraintTilde,
		"~>": constraintTilde,
		"^":  constraintCaret,
	}
	constraintMsg = map[string]string{
		"":   "%s is not equal to %s",
		"=":  "%s is not equal to %s",
		"!=": "%s is equal to %s",
		">":  "%s is less than or equal to %s",
		"<":  "%s is greater than or equal to %s",
		">=": "%s is less than %s",
		"=>": "%s is less than %s",
		"<=": "%s is greater than %s",
		"=<": "%s is greater than %s",
		"~":  "%s does not have same major and minor version as %s",
		"~>": "%s does not have same major and minor version as %s",
		"^":  "%s does not have same major version as %s",
	}
	ops := make([]string, 0, len(constraintOps))
	for k := range constraintOps {
		ops = append(ops, regexp.QuoteMeta(k))
	}
	constraintRegex = regexp.MustCompile(fmt.Sprintf(
		`^\s*(%s)\s*(%s)\s*$`,
		strings.Join(ops, "|"),
		cvRegex))
	constraintRangeRegex = regexp.MustCompile(fmt.Sprintf(
		`\s*(%s)\s+-\s+(%s)\s*`,
		cvRegex, cvRegex))
}
type constraint struct {
	function cfunc
	msg string
	con *Version
	orig string
	minorDirty bool
	dirty      bool
	patchDirty bool
}
func (c *constraint) check(v *Version) bool {
	return c.function(v, c)
}
type cfunc func(v *Version, c *constraint) bool
func parseConstraint(c string) (*constraint, error) {
	m := constraintRegex.FindStringSubmatch(c)
	if m == nil {
		return nil, fmt.Errorf("improper constraint: %s", c)
	}
	ver := m[2]
	orig := ver
	minorDirty := false
	patchDirty := false
	dirty := false
	if isX(m[3]) {
		ver = "0.0.0"
		dirty = true
	} else if isX(strings.TrimPrefix(m[4], ".")) || m[4] == "" {
		minorDirty = true
		dirty = true
		ver = fmt.Sprintf("%s.0.0%s", m[3], m[6])
	} else if isX(strings.TrimPrefix(m[5], ".")) {
		dirty = true
		patchDirty = true
		ver = fmt.Sprintf("%s%s.0%s", m[3], m[4], m[6])
	}
	con, err := NewVersion(ver)
	if err != nil {
		return nil, errors.New("constraint Parser Error")
	}
	cs := &constraint{
		function:   constraintOps[m[1]],
		msg:        constraintMsg[m[1]],
		con:        con,
		orig:       orig,
		minorDirty: minorDirty,
		patchDirty: patchDirty,
		dirty:      dirty,
	}
	return cs, nil
}
func constraintNotEqual(v *Version, c *constraint) bool {
	if c.dirty {
		if v.Prerelease() != "" && c.con.Prerelease() == "" {
			return false
		}
		if c.con.Major() != v.Major() {
			return true
		}
		if c.con.Minor() != v.Minor() && !c.minorDirty {
			return true
		} else if c.minorDirty {
			return false
		}
		return false
	}
	return !v.Equal(c.con)
}
func constraintGreaterThan(v *Version, c *constraint) bool {
	if !isNonZero(c.con) && isNonZero(v) {
		return true
	}
	if v.Prerelease() != "" && c.con.Prerelease() == "" {
		return false
	}
	return v.Compare(c.con) == 1
}
func constraintLessThan(v *Version, c *constraint) bool {
	if v.Prerelease() != "" && c.con.Prerelease() == "" {
		return false
	}
	if !c.dirty {
		return v.Compare(c.con) < 0
	}
	if v.Major() > c.con.Major() {
		return false
	} else if v.Minor() > c.con.Minor() && !c.minorDirty {
		return false
	}
	return true
}
func constraintGreaterThanEqual(v *Version, c *constraint) bool {
	if !isNonZero(c.con) && isNonZero(v) {
		return true
	}
	if v.Prerelease() != "" && c.con.Prerelease() == "" {
		return false
	}
	return v.Compare(c.con) >= 0
}
func constraintLessThanEqual(v *Version, c *constraint) bool {
	if v.Prerelease() != "" && c.con.Prerelease() == "" {
		return false
	}
	if !c.dirty {
		return v.Compare(c.con) <= 0
	}
	if v.Major() > c.con.Major() {
		return false
	} else if v.Minor() > c.con.Minor() && !c.minorDirty {
		return false
	}
	return true
}