*! REGMSNG.ADO, by Mead Over, 07May2009, Version 2.11
*! Updated version of REGMSNG.ADO, by Mead Over, July 31, 1998  Version 1.0.4 STB-47 sg99
*	Changes in updated version:
*		accepts variable names up to 30 characters in length
*		stores results in ereturn instead of as global $S_ macros
*       ereturn results include all test statistics & nmiss

program define regmsng, eclass
	version 9.2
	if replay() {
		if `"`e(cmd)'"' != "regmsng" & `"`e(cmd)'"' != "regmsng2"   {
			error 301
		}
		else if _by() {
			error 190
		}
		else {
			syntax [, Level(integer `c(level)')]
			regress, level(`level')
		}
		exit
	}
	else {
		syntax varlist(min=3 numeric) [if] [aw fw pw iw/], NMiss(integer) [ Inst(string) NOHist NOTEst FITted STeps CHange NOAux Level(integer `c(level)')]
		tempvar Nmiss hat misslt2 missimp misssum
		if `nmiss' < 0 {
			di in red "The option -nmiss- cannot be negative."
			error 198
			/* This line is not reached.*/
		}
		if "`inst'"~="" {
			unabbrev `inst'
			local inst "$S_1"
			if "`fitted'"=="" {
				di in red "The option -inst- requires the option -fitted-."
				error 198
				/* This line is not reached.*/
			}
		}
		if "`steps'"=="" {
			local shhh quietly
		}
		if "`change'" ~="" {
			label data "Data changed by REGMSMG"
		}
		else {
			preserve
				if "`weight'"!="" {
					tempvar wt
					gen double `wt' `exp'
					local exp "=`wt'"
				}

			keep `varlist' `inst' `wt'	/* Drop unused variables only if data is preserved. */
		}
		capture keep `"`if'"'	/* Drop unused observations regardless of whether data is preserved. */

		parse "`varlist'", parse(" ")
		local dvar `1'
		macro shift
		local ivar "`*'"

*	How many missing variables are present on each observation?
		egen `Nmiss' = rmiss(`ivar')
		label variable `Nmiss' "No. of RHS variables missing"
		if "`nohist'"=="" {
			di " "
			di in gr "Number of observations with 0, 1, 2, ... RHS variables missing"
			tab `Nmiss' if `dvar'~=., plot mi
		}
		quietly summ `Nmiss'
		if r(max) < 1 {
			di in red "None of the RHS variables is missing when the LHS variable is present."
			di in red "Therefore, it was not necessary to use regmsng."
			local notests "No missing"
		}
		capture keep if `Nmiss' <= `nmiss' & `dvar'~=.

*	Compute & display summary statistics for data prior to zero-filling the missing values.
		di " "
		`shhh' di in green "Summary statistics prior to zero substitution."
		`shhh' summ  `dvar' `ivar' `wt'

*	Store the mean of each ind. variable in a global macro called Mvarname.
		while "`1'"~=""  {
			local summ_wt "`weight'"  /* Convert pweights and iweights to aweights for the summarize command. */
			if "`weight'" == "pweight" | "`weight'" == "iweight" {
				local summ_wt "aweight"
			}
			qui summ `1' [`summ_wt' `exp']
			if length("`1'") > 30 {
				di in red "The names of independent variables can be no longer than 30 characters."
				error 198
				/* This line is not reached. */
			}
			global M`1' = r(mean)
			macro shift
		}

*	Create an auxiliary variable for every independent variable and zero-fill the variables.
		qui gen byte `misslt2' = .  /* Temp. variable used below to check candidate predictor variables. */
		qui gen byte `missimp' = .  /* Temp. variable used below to check if any obs are missing.*/
		local beenhre
		local i = 1
		local k : word count `ivar'
		local m : word count `inst'
		while `i' <= `k' {	/* Consider all the r.h.s. variables as candidates to predict -impvar-.*/
			local impvar : word `i' of `ivar'
			qui replace `missimp' = (`impvar'==.)
			qui summ `missimp'
			if r(max)>0  { /* Skip r.h.s variables that have no missing values. */
				if "`fitted'"~="" {  /* Generate imputed values by regression. */
					`shhh' di _newline (2)
					`shhh' di in green "The regression for imputing the missing values of " in ye "`impvar':"
					local nextvar
					local othvars
					local j = 1
					while `j' <= `k' {	/*Reject candidate r.h.s vars. which are missing when -impvar- is missing.*/
						if `j'~=`i' {
							local nextvar : word `j' of `ivar'
							qui replace `misslt2' = (`impvar'==.)&(`nextvar'==.)
							qui summ `misslt2'
							if r(max)<1 {
								local othvars `othvars' `nextvar'
							}
						}
						local j = `j' + 1
					}
					if "`inst'"~="" {
						local nextvar
						local instvrs
						local j = 1
						while `j' <= `m' {	/*Reject candidate instruments which are missing when -impvar- is missing.*/
							if `j'~=`i' {
								local nextvar : word `j' of `inst'
								qui replace `misslt2' = (`impvar'==.)&(`nextvar'==.)
								qui summ `misslt2'
								if r(max)<1 {
									local instvrs `instvrs' `nextvar'
								}
							}
							local j = `j' + 1
						}
					}
					`shhh' regress `impvar' `othvars' `instvrs'[`weight'`exp'], level(`level')
					qui predict `hat'
					qui gen A`impvar' = 0 if `impvar'~=.
					if "`shhh'"=="" {
						di " "
						di in gr "On observations where " in ye "`impvar' " in gr "is missing, insert fitted values into " in ye "A`impvar'."
					}
					`shhh' replace A`impvar' = `hat' if `impvar'==.
					qui gen `misssum' = sum(A`impvar')
					local missbar = `misssum'[_N]/(_N - r(N))
					local mthis : word count `instvrs'
					drop `misssum'
					drop `hat'
					if "`shhh'"~="" {
						if "`beenhre'"=="" {
							di in gr 				             _col(17) "Number of"   _col(29) "Number of"
							di in gr "Independent"               _col(17) " Proposed"   _col(29) "  Actual"                  _col(53) "Mean of"   _col(65) "Mean of"
							di in gr "Variables" _col(12) "nobs" _col(17) "Instruments" _col(29) "Regressors" _col(42) "F-stat"  _col(51) "Non-missing" _col(65) "Imputed"
							di in gr "---------" _col(12) "----" _col(17) "-----------" _col(29) "----------" _col(42) "------"  _col(51) "-----------" _col(65) "-------"
							local beenhre "already"
						}
						di in ye "`impvar'" _col(13) e(N) _col(22) `mthis' _col(32) e(df_m) %6.2f _col(42) e(F) _col(53) ${M`impvar'} _col(65) `missbar'
					}
				}
				else {		/* Generate auxiliary values as the means. */
					qui gen A`impvar' =  ${M`impvar'}   	if `impvar'==.
					qui replace A`impvar' = 0 			    if `impvar'~=.
				}
*	Now replace the missing values.
				if "`noaux'"~= "" { /* Replace with imputed values if the -noaux- option is set. */
					quietly replace `impvar' = A`impvar' if `impvar' == .
				}
				else {
					quietly replace `impvar' = 0 if `impvar' == .  /* Otherwise zero-fill the missing values. */
					local AuxVars `AuxVars' A`impvar' /* and assemble the list of auxiliary variables. */
				}
			}
			local i = `i' + 1
		}

*	Estimate regression.
		di " "
		di " "
		di _n in gr "Regression with Imputed Values of Missing R.H.S. Variables"

*		Either estimate regression with imputed values substituted for missing variables.
		if "`noaux'"~="" {
			if "`fitted'"~="" {
				di in green "Fitted values substituted for missing observations of RHS variables."
			}
			else {
				di in green "Means substituted for missing observations of RHS variables."
			}

			regress `dvar' `ivar' [`weight'`exp'] , level(`level')
		}

*		Or add "auxiliary" variables containing imputed variables.
		else {
			if "`fitted'"~="" {
				di in green "A-variables contain the fitted values of corresponding independent variables."
			}
			else {
				di in green "A-variables contain the mean values of corresponding independent variables."
			}

			regress `dvar' `ivar' `AuxVars' [`weight'`exp'] , level(`level')
		}
		if e(N)==0 | e(N)==. {
			error 2000
		}

*	Perform the joint tests of significance on each variable & its auxiliary.
*	Also test for equality between the coefficient of each variable and its auxiliary variable.
		if "`notest'"=="" & "`noaux'"=="" {
			parse "`ivar'", parse(" ")  /* First, test hypotheses on each variable. */
			di " "
			while "`1'"~=""  {
				capture confirm variable A`1'
				if _rc==0 {
					qui count if A`1'~=0 & `Nmiss' <= `nmiss'
					di _n in gr "A total of " in ye r(N) in gr " observations were missing for variable " in ye "`1'"
					test `1'  A`1'
					test `1' == A`1'
					ereturn scalar p_`1'eqA = r(p)
				}
				macro shift
			}
			parse "`ivar'", parse(" ") /* Then test joint hypotheses. */
			local beenhre
			di " "
			while "`1'"~=""  {
				capture confirm variable A`1'
				if _rc==0 {
					if "`beenhre'"=="" {
						qui test `1' == A`1', notest
						local beenhre already
					}
					else {
						qui test `1' == A`1', accum notest
					}
				}
				macro shift
			}
*	And on all auxiliary variables.
			di " "
			if "`notests'" == ""  {
				di in gr "A joint test of all equality constraints:"
				test
				ereturn scalar p_Joint_eq = r(p)
				di in gr "A joint test that the coefficients of all the A-variables are zero:"
				test `AuxVars'
				ereturn scalar p_Joint_Aux = r(p)
			}
		}
		if "`change'"~="" {
			rename `Nmiss' _Nmiss
			di in red "Warning! Data has been changed."
			if "`noaux'"~="" {
				di in red "Missing values of independent variables have been replaced by imputed values."
			}
			else {
				di in red "Missing values of independent variables have been zero-filled."
			}
		}
		ereturn scalar nmiss= `nmiss'
		ereturn local  cmd    "regmsng"
	}
end