*! version 0.1  24jan2022  Liyang Sun, lsun20@mit.edu

capture program drop eventstudyinteract
program define eventstudyinteract, eclass sortpreserve
	version 13
	syntax varlist(min=1 numeric) [if] [in] [aw fw iw pw], absorb(varlist numeric ts fv) cohort(varname) ///
		control_cohort(varname) ///
		[COVARIATEs(varlist numeric ts fv)  vce(string)   ///
		]
	set more off

	* Mark sample (reflects the if/in conditions, and includes only nonmissing observations)
	marksample touse
	markout `touse' `by' `xq' `covariates' `absorb', strok
	* Parse the dependent variable
	local lhs: word 1 of `varlist'
	local rel_time_list: list varlist - lhs
	* Convert the varlist of relative time indicators to nvarlist
	local nvarlist "" // copies of relative time indicators with control cohort set to zero
	local dvarlist "" // for display
	foreach l of varlist `rel_time_list' {
		local dvarlist "`dvarlist' `l'"
		tempname n`l'
		qui gen `n`l'' = `l'
		qui replace `n`l'' = 0 if  `control_cohort' == 1
		local nvarlist "`nvarlist' `n`l''"
	}

	* Get cohort count  and count of relative time
	qui levelsof `cohort' if  `control_cohort' == 0, local(cohort_list)
 	local nrel_times: word count `nvarlist'
	local ncohort: word count `cohort_list'

	* Initiate empty matrix for weights
	* ff_w stores the cohort shares (rows) for relative time (cols)
	tempname bb ff_w

	* Loop over cohort and get cohort shares for relative times
	local nresidlist ""
	foreach yy of local cohort_list {
		tempvar cohort_ind resid`yy'
		qui gen `cohort_ind'  = (`cohort' == `yy')
		qui regress `cohort_ind' `nvarlist'  if `touse' & `control_cohort' == 0 [`weight'`exp']  , nocons
		mat `bb' = e(b)
		matrix `ff_w'  = nullmat(`ff_w') \ `bb'
		qui predict double `resid`yy'', resid
		local nresidlist "`nresidlist' `resid`yy''"
	}


	* Get VCV estimate for the cohort shares using avar
	* In case users have not set relative time indicators to zero for control cohort
	* Manually restrict the sample to non-control cohort
	tempname XX Sxx Sxxi S KSxxi Sigma_ff
	mat accum `XX' = `nvarlist' if  `touse' & `control_cohort' == 0 [`weight'`exp'], nocons
	mat `Sxx' = `XX'*1/r(N)
    mat `Sxxi' = syminv(`Sxx')
	qui avar (`nresidlist') (`nvarlist')  if `touse' & `control_cohort' == 0 [`weight'`exp'], nocons robust
	mat `S' = r(S)
    mat `KSxxi' = I(`ncohort')#`Sxxi'
    mat `Sigma_ff' = `KSxxi'*`S'*`KSxxi'*1/r(N)
	// Note that the normalization is slightly different from the paper
	// The scaling factor is 1/N for N the obs of cross-sectional units
	// But here estimates are on the panel, which is why it is 1/NT instead
	// Should cancel out for balanced panel, but unbalanced panel is a TODO

	* Prepare interaction terms for the interacted regression
	local cohort_rel_varlist "" // hold the temp varnames
	foreach l of varlist `nvarlist' {
		foreach yy of local cohort_list {
			tempvar n`l'_`yy'
			qui gen `n`l'_`yy''  = (`cohort' == `yy') * `l'
			// TODO: might be more efficient to use the c. operator if format w/o missing
			local cohort_rel_varlist "`cohort_rel_varlist' `n`l'_`yy''"
		}
	}
	local bcohort_rel_varlist "" // hold the interaction varnames
	foreach l of varlist `rel_time_list'  {
		foreach yy of local cohort_list {
				local bcohort_rel_varlist "`bcohort_rel_varlist' `l'_x_`yy'"
		}
	}
	* Estimate the interacted regression
	tempname evt_bb b evt_VV V
	qui reghdfe `lhs'  `cohort_rel_varlist'  `covariates'  if `touse' [`weight'`exp'], absorb(`absorb') vce(`vce')
	local bcohort_rel_varlist "`bcohort_rel_varlist' `covariates'" // TODO: does not catch the constant term if reghdfe includes a constant.
	mat `b' = e(b)
	mata st_matrix("`V'",diagonal(st_matrix("e(V)"))')
	* Convert the delta estimate vector to a matrix where each column is a relative time
	local end = 0
	forval i = 1/`nrel_times' {
		local start = `end'+1
		local end = `start'+`ncohort'-1
		mat `b'`i' = `b'[.,`start'..`end']
		mat `evt_bb'  = nullmat(`evt_bb') \ `b'`i'
		mat `V'`i' = `V'[.,`start'..`end']
		mat `evt_VV'  = nullmat(`evt_VV') \ `V'`i'

	}
	mat `evt_bb' = `evt_bb''
	mat `evt_VV' = `evt_VV''

	* Take weighted average for IW estimators
	tempname w delta b_iw nc nr
	mata: `w' = st_matrix("`ff_w'")
	mata: `delta' = st_matrix("`evt_bb'")
	mata: `b_iw' = colsum(`w':* `delta')
	mata: st_matrix("`b_iw'", `b_iw')
	mata: `nc' = rows(`w')
	mata: `nr' = cols(`w')

	* Ptwise variance from cohort share estimation and interacted regression
	tempname VV  wlong V_iw V_iw_diag

	* VCV from the interacted regression
	mata: `VV' = st_matrix("e(V)")
	mata: `VV' = `VV'[1..`nr'*`nc',1..`nr'*`nc'] // in case reghdfe reports _cons
	mata: `wlong' = `w'':*J(1,`nc',e(1,`nr')') // create a "Toeplitz" matrix convolution
	forval i=2/`nrel_times' {
		mata: `wlong' = (`wlong', `w'':*J(1,`nc',e(`i',`nr')'))
	}
	mata: `V_iw' = `wlong'*`VV'*`wlong''
	* VCV from cohort share estimation
	tempname Vshare Vshare_evt share_idx Sigma_l
	mata: `Vshare' = st_matrix("`Sigma_ff'")
	mata: `Sigma_l' = J(0,0,.)
	mata: `share_idx' = range(0,(`nc'-1)*`nr',`nr')
	forval i=1/`nrel_times' {
		forval j=1/`i' {
			mata: `Vshare_evt' = `Vshare'[`share_idx':+`i', `share_idx':+`j']
			mata: `V_iw'[`i',`j'] = `V_iw'[`i',`j'] + (`delta'[,`i'])'*`Vshare_evt'*(`delta'[,`j'])
// 			mata: `Sigma_l' = blockdiag(`Sigma_l',`Vshare_evt')
		}
	}
	mata: `V_iw' = makesymmetric(`V_iw')
// 	mata: `V_iw' = `V_iw''
// 	mata: st_matrix("`Sigma_l'", `Sigma_l')
	mata: st_matrix("`V_iw'", `V_iw')

	mata: `V_iw_diag' = diag(`V_iw')
	mata: st_matrix("`V_iw_diag'", `V_iw_diag')
	mata: mata drop `b_iw' `VV' `nc' `nr' `w' `wlong' `Vshare' `share_idx' `delta' `Vshare_evt' `Sigma_l' `V_iw' `V_iw_diag'

	matrix colnames `b_iw' =  `dvarlist'
	matrix colnames `V_iw' =  `dvarlist'
	matrix rownames `V_iw' =  `dvarlist'

	matrix rownames `ff_w' =  `cohort_list'
	matrix colnames `ff_w' =  `dvarlist'
	matrix rownames `Sigma_ff' =  `cohort_list'
	matrix colnames `Sigma_ff' =  `cohort_list'

	matrix colnames `evt_bb' =  `dvarlist'
	matrix rownames `evt_bb' =  `cohort_list'
	matrix colnames `evt_VV' =  `dvarlist'
	matrix rownames `evt_VV' =  `cohort_list'

	ereturn matrix b_interact `evt_bb'
	ereturn matrix V_interact `evt_VV'
	ereturn matrix b_iw  `b_iw'
	ereturn matrix V_iw `V_iw'
	ereturn matrix ff_w `ff_w'
// 	ereturn matrix Sigma_l `Sigma_l'
	ereturn matrix Sigma_ff `Sigma_ff'

	ereturn local title "IW estimates for dynamic effects"
	* Display results
	_coef_table_header
	_coef_table , bmatrix(e(b_iw)) vmatrix(`V_iw_diag')

end