// generated by znkr.io/diff/internal/cmd/specializemyers
// DO NOT EDIT

package impl

import (
	"math"
)

type myersInt struct {
	x, y []int

	vf, vb []int
	v0     int

	costLimit int

	xidx, yidx []int

	rx, ry []bool
}

func (m *myersInt) init(x, y []int) (smin, smax, tmin, tmax int) {
	smin, tmin = 0, 0
	smax, tmax = len(x), len(y)

	for smin < smax && tmin < tmax && x[smin] == y[tmin] {
		smin++
		tmin++
	}

	for smax > smin && tmax > tmin && x[smax-1] == y[tmax-1] {
		smax--
		tmax--
	}

	N, M := smax-smin, tmax-tmin
	diagonals := N + M
	vlen := 2*diagonals + 3
	buf := make([]int, 2*vlen)

	m.x = x
	m.y = y
	m.vf = buf[:vlen]
	m.vb = buf[vlen:]
	m.v0 = diagonals + 1

	costLimit := 1
	for i := diagonals; i != 0; i >>= 2 {
		costLimit <<= 1
	}
	m.costLimit = max(minCostLimit, costLimit)

	if m.xidx == nil || m.yidx == nil {
		idx := make([]int, max(len(x), len(y)))
		for i := range idx {
			idx[i] = i
		}
		m.xidx = idx[:len(x)]
		m.yidx = idx[:len(y)]
	}

	if m.rx == nil || m.ry == nil {

		r := make([]bool, (len(x) + len(y) + 2))
		m.rx = r[: len(x)+1 : len(x)+1]
		m.ry = r[len(x)+1:]
	}
	return
}

func (m *myersInt) compare(smin, smax, tmin, tmax int, optimal bool) {
	if smin == smax {

		for t := tmin; t < tmax; t++ {
			m.ry[m.yidx[t]] = true
		}
	} else if tmin == tmax {

		for s := smin; s < smax; s++ {
			m.rx[m.xidx[s]] = true
		}
	} else {

		s0, s1, t0, t1, opt0, opt1 := m.split(smin, smax, tmin, tmax, optimal)

		m.compare(smin, s0, tmin, t0, opt0)
		m.compare(s1, smax, t1, tmax, opt1)
	}
}

func (m *myersInt) split(smin, smax, tmin, tmax int, optimal bool) (s0, s1, t0, t1 int, opt0, opt1 bool) {
	N, M := smax-smin, tmax-tmin
	x, y := m.x, m.y
	vf, vb := m.vf, m.vb
	v0 := m.v0

	kmin, kmax := smin-tmax, smax-tmin

	fmid, bmid := smin-tmin, smax-tmax
	fmin, fmax := fmid, fmid
	bmin, bmax := bmid, bmid

	odd := (N-M)%2 != 0

	vf[v0+fmid] = smin
	vb[v0+bmid] = smax

	for d := 1; ; d++ {

		longestDiag := 0

		if fmin > kmin {
			fmin--
			vf[v0+fmin-1] = math.MinInt
		} else {
			fmin++
		}
		if fmax < kmax {
			fmax++
			vf[v0+fmax+1] = math.MinInt
		} else {
			fmax--
		}

		for k := fmin; k <= fmax; k += 2 {
			k0 := k + v0

			var s int
			if vf[k0-1] < vf[k0+1] {

				s = vf[k0+1]
			} else {

				s = vf[k0-1] + 1
			}
			t := s - k

			s0, t0 := s, t
			for s < smax && t < tmax && x[s] == y[t] {
				s++
				t++
			}

			longestDiag = max(longestDiag, s-s0)

			vf[k0] = s

			if odd && bmin <= k && k <= bmax && s >= vb[k0] {
				return s0, s, t0, t, true, true
			}
		}

		if bmin > kmin {
			bmin--
			vb[v0+bmin-1] = math.MaxInt
		} else {
			bmin++
		}
		if bmax < kmax {
			bmax++
			vb[v0+bmax+1] = math.MaxInt
		} else {
			bmax--
		}
		for k := bmin; k <= bmax; k += 2 {
			k0 := k + v0
			var s int
			if vb[k0-1] < vb[k0+1] {
				s = vb[k0-1]
			} else {
				s = vb[k0+1] - 1
			}
			t := s - k

			s0, t0 := s, t
			for s > smin && t > tmin && x[s-1] == y[t-1] {
				s--
				t--
			}

			longestDiag = max(longestDiag, s0-s)

			vb[k0] = s

			if !odd && fmin <= k && k <= fmax && s <= vf[v0+k] {
				return s, s0, t, t0, true, true
			}
		}

		if optimal {
			continue
		}

		if longestDiag >= goodDiagMinLen && d >= goodDiagCostLimit {
			best := struct {
				v              int
				s0, s1, t0, t1 int
				opt0, opt1     bool
			}{}

			for k := fmin; k <= fmax; k += 2 {
				k0 := k + v0
				s := vf[k0]
				t := s - k
				v := (s - smin) + (t - tmin) - max(fmid-d, d-fmid)
				if s < smin || smax <= s || t < tmin || tmax <= t {
					continue
				}
				if v <= goodDiagMagic*d || v < best.v {
					continue
				}

				var pk int
				if vf[k0-1] < vf[k0+1] {
					pk = k + 1
				} else {
					pk = k - 1
				}
				ps := vf[pk+v0]
				pt := ps - pk
				diag := min(s-ps, t-pt)
				if diag < goodDiagMinLen {
					best.v = v
					best.s0 = s - diag
					best.s1 = s
					best.t0 = t - diag
					best.t1 = t
					best.opt0 = true
					best.opt1 = false
				}
			}

			for k := bmin; k <= bmax; k += 2 {
				k0 := k + v0
				s := vb[k0]
				t := s - k
				if s < smin || smax <= s || t < tmin || tmax <= t {
					continue
				}
				v := (smax - s) + (tmax - t) - max(bmid-d, d-bmid)
				if v <= goodDiagMagic*d || v < best.v {
					continue
				}

				var pk int
				if vb[k0-1] < vb[k0+1] {
					pk = k - 1
				} else {
					pk = k + 1
				}
				ps := vb[pk+v0]
				pt := ps - pk
				diag := min(ps-s, pt-t)
				if diag >= goodDiagMinLen {
					best.v = v
					best.s0 = s
					best.s1 = s + diag
					best.t0 = t
					best.t1 = t + diag
					best.opt0 = false
					best.opt1 = true
				}
			}
			if best.v > 0 {
				return best.s0, best.s1, best.t0, best.t1, best.opt0, best.opt1
			}
		}

		if d >= m.costLimit {

			fbest, fbestk := math.MinInt, math.MinInt
			for k := fmin; k <= fmax; k += 2 {
				k0 := k + v0
				s := vf[k0]
				t := s - k
				if smin <= s && s < smax && tmin <= t && t < tmax && fbest < s+t {
					fbest = s + t
					fbestk = k
				}
			}

			bbest, bbestk := math.MaxInt, math.MaxInt
			for k := bmin; k <= bmax; k += 2 {
				k0 := k + v0
				s := vb[k0]
				t := s - k
				if smin <= s && s < smax && tmin <= t && t < tmax && s+t < bbest {
					bbest = s + t
					bbestk = k
				}
			}

			if fbest != math.MinInt && (smax+tmax)-bbest < fbest-(smin+tmin) {
				k := fbestk
				k0 := k + v0
				s := vf[k0]
				t := s - k

				var pk int
				if vf[k0-1] < vf[k0+1] {
					pk = k + 1
				} else {
					pk = k - 1
				}
				ps := vf[pk+v0]
				pt := ps - pk
				diag := min(s-ps, t-pt)
				s0, t0 := s-diag, t-diag
				return s0, s, t0, t, true, false
			} else if bbest != math.MaxInt {
				k := bbestk
				k0 := k + v0
				s := vb[k0]
				t := s - k

				var pk int
				if vb[k0-1] < vb[k0+1] {
					pk = k - 1
				} else {
					pk = k + 1
				}
				ps := vb[pk+v0]
				pt := ps - pk
				diag := min(ps-s, pt-t)
				s0, t0 := s+diag, t+diag
				return s, s0, t, t0, false, true
			} else {
				panic("no best path found")
			}
		}
	}
}
