*! xtevent.ado 2.2.0 Mar 15 2023

version 11.2

cap program drop xtevent
program define xtevent, eclass

	* Replay routine
	if replay() {
		if "`e(cmd2)'"!="xtevent" exit 301
		else {
			loc rep = e(cmd)
			`rep'
		}
		exit
	}

	#d;
	syntax varlist(fv ts numeric) [aw fw pw] [if] [in] , /* Proxy for eta and covariates go in varlist. Can add fv ts later */
	POLicyvar(varname) /* Policy variable */
	[
	Window(numlist min=1 max=2 integer) /* Estimation window */
	pre(numlist >=0 min=1 max=1 integer) /* Pre-event time periods where anticipation effects are allowed */
	post(numlist >=0 min=1 max=1 integer) /* Post-event time periods where dynamic effects are allowed */
	overidpre(numlist >=0 min=1 max=1 integer) /* Pre-event time periods for overidentification */
	overidpost(numlist >=0 min=1 max=1 integer) /* Post-event time periods for overidentification */
	Panelvar(varname) /* Panel variable */
	Timevar(varname) /* Time variable */
	proxyiv(string) /* Instruments. For FHS set ins equal to leads of the policy */
	proxy (varlist numeric) /* Proxy variable */
	TRend(string) /*trend(a -1) Include a linear trend from time a to -1. Method can be either GMM or OLS*/
	SAVek(string) /* Generate the time-to-event dummies, trend, and cohort-relative time interactions and keep them in the dataset */
	STatic /* Estimate static model */
	reghdfe /* Estimate with reghdfe */
	addabsorb(string) /* Absorb additional variables in reghdfe */
	norm(integer -1) /* Normalization */
	REPeatedcs /*indicate that the input data is a repeated cross-sectional dataset*/
	cohort(varname) /*categorial variable to indicate cohort in SA estimation*/
	control_cohort(varname) /* dummy variable to indicate cohort to be used as control in SA estimation*/
	plot /* Produce plot */
	*
	/*
	These options passed to subcommands

	nofe /* No fixed effects */
	note /* No time effects */
	Kvars(string) /* Use previously generated dummies */
	impute(string) /* impute policyvar */
	*/
	]
	;
	#d cr



	* Capture errors

	if "`addabsorb'"!="" & "`reghdfe'"=="" {
		di as err "option {bf:addabsorb} only allowed with option {bf:reghdfe}"
		exit 198
	}

	if "`proxy'" == "" & "`proxyiv'" != "" {
		di as err _n "With instruments, you must specify a proxy variable"
		exit 198
	}

	* If xtset, don't need panelvar and timevar
	cap xtset
	if _rc==459 {
		if "`panelvar'"=="" & "`timevar'"!="" | "`panelvar'"!="" & "`timevar'"=="" | "`panelvar'"=="" & "`timevar'"=="" {
			di as err _n "If data have not been xtset, you must specify options {bf:panelvar} and {bf:timevar}"
			exit 198
		}
	}
	else if ("`panelvar'"!="" & "`panelvar'"!=r(panelvar)) | ("`timevar'"!="" & "`timevar'"!=r(timevar)) {
		di as err _n "Data have been xtset, and you specified options {bf:panelvar} or {bf:timevar} with variables different from those previously set. Run {cmd:xtset,clear}  or {cmd:xtset} your data again"
		exit 198
	}
	else if ("`panelvar'"=="" & "`timevar'"=="") | ("`panelvar'"!="" & "`timevar'"=="") | ("`panelvar'"=="" & "`timevar'"!="")  {
		di as txt _n "Using options {bf:panelvar} and {bf:timevar} from {cmd:xtset}"
		loc panelvar=r(panelvar)
		loc timevar=r(timevar)
	}

	if "`trend'"!="" & "`proxy'"!="" {
		di as err _n "options {bf:proxy} and {bf:trend} not allowed simultaneously"
		exit 198
	}

	if "`trend'"!="" & "`static'"!="" {
		di as err _n "options {bf:static} and {bf:trend} not allowed simultaneously"
		exit 198
	}

	* Always need window unless static is specified
	if "`window'"=="" & ("`static'"=="" & ("`pre'"=="" | "`post'"=="" | "`overidpre'"=="" | "`overidpost'"=="")) {
		di as err _n "option {bf:window} is required unless option {bf:static}, or options {bf:pre},{bf:post},{bf:overidpre}, and {bf:overidpost} are specified"
		exit 198
	}
	if "`window'"!="" & "`static'"!="" {
		di as err _n "option {bf:window} not allowed with option {bf:static}"
		exit 198
	}
	if "`window'"!="" & ("`static'"!="" | ("`pre'"!="" | "`post'"!="" | "`overidpre'"!="" | "`overidpost'"!="")) {
		di as err _n "option {bf:window} not allowed with options {bf:static},{bf:pre},{bf:post},{bf:overidpre}, or {bf:overidpost}"
		exit 198
	}
	if ("`static'"!="" & ("`pre'"!="" | "`post'"!="" | "`overidpre'"!="" | "`overidpost'"!="")) {
		di as err _n "option {bf:static} not allowed with options {bf:static},{bf:pre},{bf:post},{bf:overidpre}, or {bf:overidpost}"
		exit 198
	}

	if "`savek'"=="_k" {
		di as err _n "_k reserved for internal variables. Please choose a different stub"
		exit 198
	}

	if "`reghdfe'" != "" {
		foreach p in reghdfe ftools {
			cap which `p'
			if _rc {
				di as err _n "option {bf:reghdfe} requires {cmd: `p'} to be installed"
				exit 199
			}
		}
		if "`proxy'"!="" {
			foreach p in ivreghdfe ivreg2 ranktest avar {
				cap which `p'
				if _rc {
					di as err _n "option {bf:reghdfe} and IV estimation requires {cmd: `p'} to be installed"
					exit 199
				}
			}
		}
	}

	*inform panel variables in case of data is repeated cross-sectional
	if "`repeatedcs'"!=""{
		di as txt _n "Option {bf:repeatedcs} was specified. Using {bf:`panelvar'} as the panel variable and {bf:`timevar'} as the time variable."
	}

	if ("`cohort'" != "" & "`control_cohort'" == "") | ("`cohort'" == "" & "`control_cohort'" != "")  {
		di as err _n "options {bf:cohort} and {bf:control_cohort} must be specified simultaneously"
		exit 199
	}
	if "`cohort'"!="" & "`control_cohort'"!=""  {
		cap which avar
		if _rc {
			di as err _n "Sun-and-Abraham estimation requires {cmd: avar} to be installed"
			exit 199
		}
	}

	tempvar sample tousegen

	* Do not mark variables, only if in here

	mark `tousegen' `if' `in'

	loc flagerr=0

	if "`static'"=="" {
		if "`window'"!="" {
			* Parse window
			loc nw : word count `window'
			if `nw'==1 {
				loc lwindow = -`window'
				loc rwindow = `window'
			}
			else if `nw'==2 {
				loc lwindow : word 1 of `window'
				loc rwindow : word 2 of `window'
			}

			if -`lwindow'<0 | `rwindow'<0 {
				di as err _n "Window can not be negative"
				exit 198
			}
		}
		else if "`window'"=="" & ("`pre'"!="" & "`post'"!="" & "`overidpre'"!="" & "`overidpost'"!="") {
			loc lwindow = `pre' + `overidpre'
			loc lwindow = -`lwindow'
			loc rwindow = `post' + `overidpost' -1
		}

		* If allowing for anticipation effects, change the normalization if norm is missing, or warn the user
		if ("`pre'"!="0" & "`pre'"!="") {
			if `norm'==-1 {
				loc norm = -`pre'-1
				di as text _n "You allowed for anticipation effects `pre' periods before the event, so the coefficient at `norm' was selected to be normalized to zero. Use options {bf:norm} and {bf:window} to override this."
			}
		}

		* Check that normalization is in window
		if `norm' < `=`lwindow'-1' | `norm' > `rwindow' {
			di as err _n "The coefficient to be normalized to 0 is outside of the estimation window"
			exit 498
		}

		* Do not allow norm and trend
		if "`norm'" !="-1" & "`trend'" != "" {
			di as err _n "Option {bf:trend} not allowed with a value for option {bf:norm} different from -1."
			exit 198
		}
		*user
		*if "`trend'"!="" loc trend "trend(`trend')"
		*else loc trend ""

		* Estimate

		if "`proxy'" == "" & "`proxyiv'" == "" {
			di as txt _n "No proxy or instruments provided. Implementing OLS estimator"
			cap noi _eventols `varlist' [`weight'`exp'] if `tousegen', panelvar(`panelvar') timevar(`timevar') policyvar(`policyvar') lwindow(`lwindow') rwindow(`rwindow') trend(`trend') savek(`savek') norm(`norm') `reghdfe' addabsorb(`addabsorb') `repeatedcs' cohort(`cohort') control_cohort(`control_cohort') `options'
			if _rc {
				errpostest
			}
		}
		else {
			di as txt _n "Proxy for the confound specified. Implementing FHS estimator"
			cap noi _eventiv `varlist' [`weight'`exp'] if `tousegen', panelvar(`panelvar') timevar(`timevar') policyvar(`policyvar') lwindow(`lwindow') rwindow(`rwindow') proxyiv(`proxyiv') proxy (`proxy') savek(`savek')    norm(`norm') `reghdfe' addabsorb(`addabsorb') `repeatedcs' `options'
			if _rc {
				errpostest
			}
		}
	}
	else if "`static'"=="static" {
		loc lwindow=.
		loc rwindow=.
		di as txt _n "option {bf:static} specified. Estimating static model"
		di as txt _n "Plotting options ignored"
		if "`proxy'" == "" & "`proxyiv'" == "" {
			di as txt _n "No proxy or instruments provided. Implementing OLS estimator"
			cap noi _eventolsstatic `varlist' [`weight'`exp'] if `tousegen', panelvar(`panelvar') timevar(`timevar') policyvar(`policyvar') `reghdfe' addabsorb(`addabsorb') `repeatedcs' `options' `static'
			if _rc {
				errpostest
			}
		}

		else {
			di as txt _n "Proxy for the confound specified. Implementing FHS estimator"

			cap noi _eventivstatic `varlist' [`weight'`exp'] if `tousegen', panelvar(`panelvar') timevar(`timevar') policyvar(`policyvar') proxyiv(`proxyiv') proxy (`proxy') `reghdfe' addabsorb(`addabsorb') `repeatedcs' `options' `static'
			if _rc {
				errpostest
			}
		}
	}

	*don't try returning matrices and macros if noestimate is specified
	loc noestimate = r(noestimate)
	if "`noestimate'"=="." loc noestimate ""
	if "`noestimate'"!="" exit

	if `=r(flagerr)'!=1  {

		loc noestimate=r(noestimate)
		if "`noestimate'"=="." loc noestimate ""
		if "`noestimate'"!="" {
			loc savek = r(savek)
			*clear previous estimates, so it will not mix them with the new ones
			ereturn clear
		}

		ereturn scalar lwindow= `lwindow'
		ereturn scalar rwindow=`rwindow'
		if "`pre'"!="" {
			ereturn scalar pre = `pre'
			ereturn scalar post = `post'
			ereturn scalar overidpre = `overidpre'
			ereturn scalar overidpost = `overidpost'
		}
		ereturn local cmdline `"xtevent `0'"' /*"*/
		ereturn local cmd2 "xtevent"
		ereturn local stub = "`savek'"
		ereturn local noestimate = "`noestimate'"
		*don't return the remaining if the user indicated not to estimate
		if "`noestimate'"!="" exit

		mat delta=r(delta)
		mat Vdelta=r(Vdelta)
		mat b = r(b)
		mat V = r(V)
		gen byte `sample' = e(sample)
		ereturn repost b=b V=V, esample(`sample')
		ereturn matrix delta = delta
		ereturn matrix Vdelta = Vdelta
		if "`=r(method)'"=="iv" {
			mat deltaxsc = r(deltaxsc)
			mat deltaov = r(deltaov)
			mat Vdeltaov = r(Vdeltaov)
			mat deltax = r(deltax)
			mat Vdeltax = r(Vdeltax)
			ereturn matrix deltaxsc = deltaxsc
			ereturn matrix deltaov = deltaov
			ereturn matrix Vdeltaov = Vdeltaov
			ereturn matrix deltax = deltax
			ereturn matrix Vdeltax = Vdeltax
			if `=r(x1)'!=. ereturn local x1 = r(x1)

		}
		loc sun_abraham = r(sun_abraham)
		if "`sun_abraham'"=="." loc sun_abraham ""
		if "`sun_abraham'"!="" {
			mat b_interact = r(b_interact)
			mat V_interact = r(V_interact)
			mat ff_w = r(ff_w)
			mat Sigma_ff = r(Sigma_ff)
			ereturn matrix b_interact = b_interact
			ereturn matrix V_interact = V_interact
			ereturn matrix ff_w = ff_w
			ereturn matrix Sigma_ff = Sigma_ff
		}

		loc saveov = r(saveov)
		if "`saveov'"=="." loc saveov ""
		if "`saveov'"!="" {

			mat mattrendy = r(mattrendy)
			mat mattrendx = r(mattrendx)
			mat deltaov = r(deltaov)
			mat Vdeltaov = r(Vdeltaov)
			ereturn matrix mattrendy = mattrendy
			ereturn matrix mattrendx = mattrendx
			ereturn matrix deltaov = deltaov
			ereturn matrix Vdeltaov = Vdeltaov
		}
		if "`trend'"!="" ereturn local trend = r(trend)

		ereturn local names=r(names)
		loc cmd = r(cmd)
		ereturn local cmd = r(cmd)
		ereturn local df = r(df)
		ereturn local komit = r(komit)
		ereturn local kmiss = r(kmiss)
		ereturn local y1 = r(y1)
		ereturn local method = r(method)
		ereturn local depvar = r(depvar)
	}
	else {
		exit 198
	}

	if "`plot'"!="" xteventplot

end

cap program drop cleanup
program define cleanup
	cap drop _k_eq*
	cap drop _ttrend
	cap drop __k
	cap drop _f*
	cap drop _interact*
	cap _estimates clear
end

cap program drop errpostest
program define errpostest, rclass
	cleanup _rc
	return local flagerr=1
end