*!version 1.0.0  03may2023
/*
	syntax:

	steptest , [always(varlist) alpha(0.05) nowarmstart] :
			{it:est_cmd} {it:depvar} {it:varlist}
			 [if] [in] [weight], [options]
*/
program steptest
	version 16
					// parse syntax
	ParseSyntax `0'
	local always `r(always)'
	local controls `r(controls)'
	local cmd `r(cmd)'
	local model_opts `r(model_opts)'
	local depvar `r(depvar)'
	local speedup `r(speedup)'
	local alpha `r(alpha)'
	local px `r(px)'
					// compute
	Compute, always(`always')		///
		controls(`controls')		///
		cmd(`cmd')			///
		model_opts(`model_opts')	///
		depvar(`depvar')		///
		speedup(`speedup')		///
		alpha(`alpha')			///
		px(`px')
end

						//---------------------------//
						//	Parse syntax
						//---------------------------//
program ParseSyntax, rclass

	_on_colon_parse `0'
	local before `s(before)'
	local after `s(after)'
					//  before colon
	local 0 `before'
	syntax [, always(varlist numeric fv)	///
		alpha(real 0.05) 		///
		noBONferroni			///
		nowarmstart]

	fvexpand `always'
	local always `r(varlist)'

	if (`"`warmstart'"' == "nowarmstart") {
		local speedup = 0
	}
	else {
		local speedup = 1
	}

	if (`alpha' <= 0 | `alpha' > 1) {
		di as err "option {bf:alpha()} must be a "	///
			"positive number less than 1"
		exit 198
	}
					//  after colon
	local 0 `after'
	syntax anything(name=model) [if] [in] [fw iw] [, *]

	gettoken cmd varlist: model

	local model_opts `if' `in' [`weight'`exp'] , `options' vce(robust)

	fvexpand `varlist'
	local allvars `r(varlist)'
	gettoken depvar allvars: allvars

	// local in : list always in allvars

	// if (!`in') {
	// 	di as err "option {bf:always()} specifies variables not " ///
	// 		"in the model"
	// 	exit 198
	// }

	local controls : list allvars - always

	local px : list sizeof controls

	if (`"`bonferroni'"' == "nobonferroni") {
		local px = 1
	}

	ret local always `always'
	ret local controls `controls'
	ret local cmd `cmd'
	ret local model_opts `model_opts'
	ret local depvar `depvar'
	ret local speedup `speedup'
	ret local alpha	`alpha'
	ret local px `px'
end
						//---------------------------//
						//	compute
						//---------------------------//
program	Compute, rclass
	syntax, cmd(passthru)		///
		controls(string)	///
		depvar(passthru)	///
		speedup(passthru)	///
		alpha(passthru)		///
		px(passthru)		///
		[always(string)		///
		model_opts(passthru) ]

	local cont = 1
	local candi `controls'
	local i = 1
	local included `always'
	tempname b_from

	di
	while (`cont') {
		qui GetNext , `cmd' `depvar' candi(`candi') 	///
			included(`included') `model_opts' `from' ///
			`alpha' `px'

		local wt_next = r(wt_next)
		local var_next `r(var_next)'
		local cval = r(cval)
		local cval_lb `r(cval_lb)'
		mat `b_from' = r(eb_next)

		if (`"`var_next'"' == "") {
			local cont = 0
		}
		else {
			local included `included' `var_next'
			local candi : list candi - var_next

			DisplayLog, var_next(`var_next') 	///
				wt_next(`wt_next')		///
				cval_lb(`cval_lb')		///
				cval(`cval')

			if (`"`candi'"' == "") {
				local cont = 0
			}

			GetFrom, `cmd' `speedup' b_from(`b_from')
			local from `s(from)'
		}
		local i = `i' + 1
	}

	local included : list uniq included
	local cadi : list uniq candi

	FinalModel, `cmd' `depvar' included(`included') `model_opts'

	ret local included `included'
	ret local excluded `candi'
	ret local always `always'
	ret scalar cval = `cval'
end

						//---------------------------//
						//	 Get next
						//---------------------------//
program GetNext, rclass
	syntax	, cmd(string)		///
		depvar(string)		///
		alpha(string)		///
		px(string)		///
		[ candi(string)		///
		from(passthru)		///
		included(string) 	///
		model_opts(string)]

	tempname eb
	local wt_max = -1E+10

	foreach var of local candi {
		qui `cmd' `depvar' `included' `var' `model_opts' `from'

		test `var'
		local wt_tmp = r(chi2)
		if (`wt_tmp' == .) {
			local wt_tmp = r(F)
		}

		if (`"`cval'"' == "") {
			GetCval, alpha(`alpha') px(`px')
			local cval `s(cval)'
			local cval_lb `s(cval_lb)'
		}

		if (`wt_tmp' >= `cval' & `wt_tmp' >= `wt_max') {
			local wt_next = `wt_tmp'
			local var_next `var'
			local wt_max = `wt_tmp'
			mat `eb' = e(b)
		}
	}

	if (`"`var_next'"' != "") {
		ret scalar wt_next = `wt_next'
		ret matrix eb_next = `eb'
	}

	ret local var_next `var_next'
	ret scalar cval  = `cval'
	ret local cval_lb `cval_lb'
end
						//---------------------------//
						//	 Display log
						//---------------------------//
program DisplayLog
	syntax, var_next(string) 	///
		wt_next(string)		///
		cval(string)		///
		cval_lb(string)

	di as txt "Wald test = " as res %9.4f `wt_next' 		///
		_column(25) as txt "`cval_lb'" as res %9.4f `cval' 	///
		_column(65) as txt "Add " as res "`var_next'"
end
						//---------------------------//
						//	 display
						//---------------------------//
program Display
	syntax , cmd(string)

	`cmd'
end

						//---------------------------//
						//	 Final model estimation
						//---------------------------//
program FinalModel
	syntax, cmd(string)		///
		depvar(string)		///
		[included(string)	///
		model_opts(string)]

	qui `cmd' `depvar' `included' `model_opts'

	Display, cmd(`cmd')
end
						//---------------------------//
						// get from options (warm start)
						//---------------------------//
program GetFrom, sclass
	syntax, cmd(string)	///
		speedup(string)	///
		b_from(string)

	if (`"`cmd'"' == "regress") {
		exit
		//NotReached
	}

	if (`speedup') {
		sret local from from(`b_from', skip)
	}
end
						//------------------------//
						// get critical value
						//------------------------//
program GetCval, sclass
	syntax, alpha(string)	///
		px(string)

	if (r(chi2) != .) {
		local cval = invchi2tail(1, `alpha'/`px')
		local cval_lb `"invchi2(1, 1-`alpha'/`px') ="'
	}
	else if (r(F) != .) {
		local cval = invFtail(1, r(df_r), `alpha'/`px')
		local df_r = r(df_r)
		local cval_lb `"invF(1, `df_r', 1-`alpha'/`px') ="'
	}

	if (`"`e(cmd)'"' == "regress" & r(F) == . ) {
		local cval = .
		local df_r = r(df_r)
		local cval_lb `"invF(1, `df_r', 1-`alpha'/`px') ="'
	}
	else if (`"`e(cmd)'"' != "regress" & r(chi2) == .) {
		local cval = .
		local cval_lb `"invchi2(1, 1-`alpha'/`px') ="'
	}

	sret local cval `cval'
	sret local cval_lb `cval_lb'
end