*! version 1.0.0 13Jul2020
//-----------------------------------------------------------------------------
//
//	mivcausal - Testing the hypothesis about the signs of the 2SLS weights
//	Extract the list of variables from `anything'
//
//-----------------------------------------------------------------------------

capt program drop mivvars

program mivvars, sclass

	version 10.0
	syntax anything [if] [in] [, VCE(passthru) 								///
								 Robust 									///
								 CLuster(passthru)]

	// Step 1 - Extract the variable names
	gettoken vars xvars : anything, parse(" ,[") match(paren)

	// Step 2 - Check if there is anything before the parentheses
	* Count the number of words in vars
	local vn : word count `vars'

	* Message for incorrect syntax
	local varerrmsg "Error: The list of variables is specified "			///
					"incorrectly. The list of variables should be " 		///
				    "'(D = Z1 Z2) X' where D is the endogenous variable, "	///
					"Z1 and Z2 are the instrumental variables and X " 		///
				    "is the list of covariates."

	* Return error if users put variables before the list of parentheses or
	* if more than one set of parentheses is included
	if "`paren'" != "(" | strpos("`xvars'", "(") != 0 {
		di as error "`varerrmsg'"
		exit 498
	}

	// Step 3 - Check the syntax of the terms inside the parenthesis
	* Return error if user does not put an equal sign inside the cluster of
	* variables inside the parentheses
	if strpos("`vars'", "=") == 0 {
		di as error "`varerrmsg'"
		exit 498
	}

	* Check the syntax
	scalar zstart = 0
	while `vn' != 0 {
		gettoken fvar vars : vars, parse(" =") match(paren)

		* Return error if the variables "vars" include any parentheses
		if "`paren'" == "(" {
			di as error "`varerrmsg'"
			exit 498
		}

		if "`fvar'" != "=" & zstart == 0 {
			local dvar `dvar' `fvar'
		}
		else if "`fvar'" == "=" {
			scalar zstart = 1
		}
		else {
			* Return error if the user puts more than one equal sign inside
			* the cluster of variables inside the parentheses
			if strpos("`vars'", "=") != 0 {
				di as error "`varerrmsg'"
				exit 498
			}

			local zvars `zvars' `fvar'
		}

		* Count the remaining number of words
		local vn : word count `vars'
	}

	// Step 4 - Retokenize the variables
	local dvar : list retokenize dvar
	local zvars : list retokenize zvars
	local xvars : list retokenize xvars

	// Step 5 - Form the list of the variables explicitly if they include "*"
	* Treatment
	if strpos("`dvar'", "*") != 0 {
		local dvar_final `'
		foreach d of varlist `dvar' {
			local dvar_final `dvar_final' `d'
		}
	}
	else {
		local dvar_final `dvar'
	}

	* Instruments
	if strpos("`zvars'", "*") != 0 {
		local zvars_final `'
		foreach z of varlist `zvars' {
			local zvars_final `zvars_final' `z'
		}
	}
	else {
		local zvars_final `zvars'
	}

	// Step 6 - Count the number of variables dvar and zvars
	* Count the number of treatments
	local dn : word count `dvar_final'
	local zn : word count `zvars_final'

	* Return error if the number of variables is incorrect
	if `dn' != 1 {
		di as error "Error: There has to be one endogenous variable."
		exit 498
	}

	* Count the number of instruments
	if `zn' != 2 {
		di as error "Error: There have to be two binary instrumental variables."
		exit 498
	}

	// Step 7 - Check if the variables exist in the dataset
	foreach x of varlist `dvar_final' `zvars_final' `xvars' {
		capture confirm variable `x', exact
		if _rc != 0 {
			di as error "Error: The variable " `x' " does not exist in " 	///
						"the dataset."
			exit 498
		}
	}

	// Step 8 - Check variance
	* Parse the standard errors
	_vce_parse, optlist(Robust) argoptlist(CLuster) old : , `vce' 			///
															`robust'		///
															`cluster'

	// Step 9 - Assign the return list
	* Assign the return list of the variance
	if missing(r(vce)) {
		sreturn local vce "unadjusted"
	}
	else {
		sreturn local robust `r(robust)'
		sreturn local cluster `r(cluster)'
		sreturn local vceopt `r(vceopt)'
		sreturn local vceargs `r(vceargs)'
		sreturn local vce `r(vce)'
	}

	* Assign the return list of the variables
	sreturn local dvar `dvar_final'
	sreturn local zvars `zvars_final'
	sreturn local xvars `xvars'

end