// goredo -- djb's redo implementation on pure Go
// Copyright (C) 2020-2026 Sergey Matveev <stargrave@stargrave.org>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 3 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

// .do finder

package main

import (
	"io"
	"path"
	"strings"
)

const (
	EnvTopDir = "REDO_TOP_DIR"
	TopFile   = "top"
)

var TopDir string

func existsDo(w io.Writer, fdDepName, cwd, pth string) (bool, error) {
	if FileExists(path.Join(cwd, pth)) {
		return true, nil
	}
	if w == nil {
		return false, nil
	}
	return false, ifcreate(w, fdDepName, pth)
}

func findDo(w io.Writer, fdDepName, cwd, tgt string) (string, int, error) {
	doFile := tgt + ".do"
	exists, err := existsDo(w, fdDepName, cwd, doFile)
	if err != nil {
		return "", 0, err
	}
	if exists {
		return doFile, 0, nil
	}
	doFileOrig := doFile
	levels := []string{}
	extsOrig := strings.Split(tgt, ".")[1:]
	dirAbsPrev := ""
	for {
		exts := extsOrig
		updir := path.Join(levels...)
		for len(exts) > 0 {
			doFile = strings.Join(append(
				[]string{"default"}, append(exts, "do")...,
			), ".")
			if len(levels) > 0 || (doFile != doFileOrig && doFile != tgt) {
				exists, err = existsDo(w, fdDepName, cwd, path.Join(updir, doFile))
				if err != nil {
					return "", 0, err
				}
				if exists {
					return doFile, len(levels), nil
				}
			}
			exts = exts[1:]
		}
		doFile = "default.do"
		if len(levels) > 0 || (doFile != doFileOrig && doFile != tgt) {
			exists, err = existsDo(w, fdDepName, cwd, path.Join(updir, doFile))
			if err != nil {
				return "", 0, err
			}
			if exists {
				return doFile, len(levels), nil
			}
		}
		levels = append(levels, "..")
		dirAbs := mustAbs(path.Join(cwd, updir))
		if err != nil {
			panic(err)
		}
		if dirAbs == TopDir {
			break
		}
		if FileExists(path.Join(dirAbs, RedoDir, TopFile)) {
			break
		}
		if dirAbs == dirAbsPrev {
			break
		}
		dirAbsPrev = dirAbs
	}
	return "", 0, nil
}
