*! evstudydd: estimate event studies in D-i-D settings using the reghdfe or ppmlhdfe packages. It requires reghdfe and ppmlhdfe to be installed.
*! Version: September, 2024
*! Authors: Adrien Matray, Pablo E. Rodriguez

qui{

cap program drop evstudydd
program define evstudydd
version 13.0
    syntax varlist(numeric min=2 max=2) [if] [in], Treated(name) SHOCKTime(string) Period(string) CLuster(string) FE(string) Name(string) [Weight(name)] [CONTrols(string)] ///
	[Estimator(string)]

    * Temporarily capture variables from varlist
    tokenize `varlist'
    local Y `1'
    local t `2'

    * Validate treated var defined
    if "`treated'" == "" {
        di as err "You must specify a treated variable"
        exit 198
    }
    * Validate shock period defined
    if "`shocktime'" == "" {
        di as err "You must specify the variable or numeric value for the time of the shock (also used as the ref. time for event study)"
        exit 198
    }

    * Validate period option defined
    if "`period'" == "" {
        di as err "You must specify the period option in the format lower_bound upper_bound"
        exit 198
    }

    * Validate name option defined
    if "`name'" == "" {
        di as err "You must specify the name option to store .dta dataset"
        exit 198
    }

	* Validate estimator option
    if "`estimator'" != "" & "`estimator'" != "ols" & "`estimator'" != "reghdfe" & "`estimator'" != "ppmlhdfe" & "`estimator'" != "poisson" {
        di as err "Invalid estimator specified. Allowed values are blank (default is reghdfe), ols, reghdfe, ppmlhdfe, or poisson."
        exit 198
    }

    * Parse the period option
    tokenize `period'
    local before `1'
    local after `2'

    * Check if `shockperiod` is a variable or a number
    capture confirm variable `shocktime'
    if _rc == 0 {
        local is_var = 1
    }
    else {
        local is_var = 0
    }

    * Make sure no variable needed are already in the sample
    cap drop DiD*
    cap drop *B* SE* TIME

    * Create coefficients
    if `is_var' {
        * If shocktime is a variable
        gen DiD0 = (`t' < `shocktime' - `before') * (`treated' == 1)

        local T = `before' + `after' + 1
        forvalues time_evstudy = 1(1)`T' {
            if `time_evstudy' != `before' + 1 {
                qui gen DiD`time_evstudy' = (`t' == `shocktime' + `time_evstudy' - `before' - 1) * (`treated')
            }
        }

        gen DiDpost = (`t' > `shocktime' + `after') * (`treated')
    }
    else {
        * If shocktime is a number
        local shockperiod_val = real("`shocktime'")
        gen DiD0 = (`t' < `shockperiod_val' - `before') * (`treated')

        local T = `before' + `after' + 1
        forvalues time_evstudy = 1(1)`T' {
            if `time_evstudy' != `before' + 1 {
                qui gen DiD`time_evstudy' = (`t' == `shockperiod_val' + `time_evstudy' - `before' - 1) * (`treated')
            }
        }

        gen DiDpost = (`t' > `shockperiod_val' + `after') * (`treated')
    }

    * Estimate event study
    if "`estimator'" == "" | "`estimator'" == "reghdfe" | "`estimator'" == "ols" {
        * if weight is specified
        if "`weight'" != "" {
            if "`controls'" != "" {
                reghdfe `Y' DiD* `controls' [aw = `weight'], a(`fe') vce(cluster `cluster') noconst
            }
            else {
                reghdfe `Y' DiD* [aw = `weight'], a(`fe') vce(cluster `cluster') noconst
            }
        }
        * if weight is not specified
        if "`weight'" == "" {
            if "`controls'" != "" {
                reghdfe `Y' DiD* `controls', a(`fe') vce(cluster `cluster') noconst
            }
            else {
                reghdfe `Y' DiD*, a(`fe') vce(cluster `cluster') noconst
            }
        }
    }

    if "`estimator'" == "ppmlhdfe" | "`estimator'" == "poisson" {
        * Poisson estimators do not allow analytical weights
        if "`weight'" != "" {
            display in red "Poisson estimators do not allow analytical weights"
            exit 198
        }
        * if weight is not specified
        if "`weight'" == "" {
            if "`controls'" != "" {
                ppmlhdfe `Y' DiD* `controls', a(`fe') vce(cluster `cluster')
            }
            else {
                ppmlhdfe `Y' DiD*, a(`fe') vce(cluster `cluster')
            }
        }
    }

    * Save the coeffs and standard errors
    * Start at -k -1
    qui gen TIME 	= -`before' - 1 			if _n == 1
    qui gen B 		= _b[DiD0] 					if _n == 1
    qui gen SE 		= _se[DiD0] 				if _n == 1

    * Values from -k to k
    forvalues time_evstudy = 1(1)`T' {
        if `time_evstudy' != `before' + 1 {
            qui replace TIME 	= `time_evstudy' - `before' - 1 	if _n == `time_evstudy' + 1
            qui replace B 		= _b[DiD`time_evstudy'] 			if _n == `time_evstudy' + 1
            qui replace SE 		= _se[DiD`time_evstudy'] 			if _n == `time_evstudy' + 1
        }
    }

    * Ref year not estimated
    qui replace TIME 	= 0 			if _n == `before' + 2
    qui replace B 		= 0 			if _n == `before' + 2
    qui replace SE 		= 0 			if _n == `before' + 2

    * Adjust k+1 onward
    qui replace TIME 	= `after' + 1 	if _n == `T' + 2
    qui replace B 		= _b[DiDpost] 	if _n == `T' + 2
    qui replace SE 		= _se[DiDpost] 	if _n == `T' + 2

	quiet drop DiD*
    preserve
        keep TIME B* SE*
        keep if TIME < .
		rename TIME time

        * Ensure the specified name includes the full path and filename
        local filepath `"`name'"'

        * Check if the .dta extension is included, if not, add it
        if strpos("`filepath'", ".dta") == 0 {
            local filepath = "`filepath'.dta"
        }

        * Set up file write using the specified path and filename
        save "`filepath'", replace
    restore

end

}