*! 1.0.1 Ariel Linden 18Apr2024 	// fixed issue with "dots" not displaying properly
									// changed trperiod() to "string" so that command will work with updated itsamatch and itsa
*! 1.0.0 Ariel Linden 03Apr2018


program define itsaperm, rclass
version 11.0

	/* obtain settings */
	syntax varlist(min=1 numeric) [if] [in] [aweight] ,       		/// weight only relevant for -newey-
	TRPeriod(string)												/// start time of intervention
	TREATid(numlist min=1 max=1 int sort)                         	/// ID of actual treated unit
	[ Pr(numlist max=1 >0 <1)										/// minimum p-value for balancing covariates
	MATCHvar(varlist)												/// variables used for matching
	LAG(int -1)														/// lag only relevant for -newey-
	PRAIS															///	use -prais- rather than default -newey-
	NOIsily															/// shows _zxt estimates as they are computed
	PLOt PLOt2(str asis)											/// generate forest-plot
	FAVors(str)														/// labels for left and right side of zero
	REPLace															/// replace variables generated in previous run
	* ]


	/* check if data is tsset with panel and time var */

	quietly {
		marksample touse
		count if `touse'
		if r(N) == 0 error 2000
		local N = r(N)
		replace `touse' = -`touse'

		tsset
		local tvar `r(timevar)'
		local pvar `r(panelvar)'

		/* drop program variables if option "replace" is chosen */
		if "`replace'" != "" {
			local itsapermvars : char _dta[_itsapermvars]
				if "`itsapermvars'" != "" {
					foreach v of local itsapermvars {
						capture drop `v'
					}
				}
		}

		/********* validate options ************/
		if "`exp'" != "" & "`prais'" != "" {
			di as err "weights may not be specified with prais option"
		exit 101
		}

		if "`prais'" != "" {
			if `lag' != -1 {
				di as err "lag() may not be specified with prais option"
			exit 198
			}
		}
		else if `lag' == -1 local lag 0

		if "`pr'" == "" {
			local pr = 0
		}

		/* Get unique levels of the panel (pvar) variable */
		sum `pvar' if `touse'
		local rmin = r(min)
		local rmax = r(max)
		levelsof `pvar' if `touse', local(levels)
		local cnt = r(r)

		/* determine if pvar has value labels and assign them to ID*/
		local pvarlabl: value label `pvar'
		if "`pvarlabl'" != "" {
			gen id:`pvarlabl' = . if `touse'
		}
		else {
			gen id = . if `touse'
		}

		gen strL idC = "" if `touse'
		gen estimate =. if `touse'
		gen se = . if `touse'
		gen t = . if `touse'
		gen p = . if `touse'
		gen lcl = . if `touse'
		gen ucl = . if `touse'

		/* if matchvar is not specified, use varlist */
		if "`matchvar'" == "" {
			local matchvar `varlist'
		}
		local r 1 // row
	} // end quietly

	/* setup for dots */
		if "`noisily'" == "" {
		di _n
		di as txt "Iterating across (" as res `cnt' as txt ") units of {bf:`pvar'} "
		di as txt "{hline 4}{c +}{hline 3} 10 " "{hline 3}{c +}{hline 3} 20 " "{hline 3}{c +}{hline 3} 30 " "{hline 3}{c +}{hline 3} 40 " "{hline 3}{c +}{hline 3} 50 "
		}
	/* loop thru -itsamatch- then -itsa- for each unit of pvar */
	foreach i of local levels {
		if "`noisily'" == "" {
		_dots `cnt' 0
		}
		else if "`noisily'" != "" {
		di _n
		 di as txt "ID#: `i'"
		}
		capture `noisily' {
			qui replace id = `i' in `r'
			qui itsamatch `matchvar' if `touse', treatid(`i') trperiod(`trperiod') pr(`pr') lag(`lag') `prais' local(controls) `options'
			qui	replace idC = "`controls'" in `r'
			qui itsa `varlist' if `touse', treatid(`i') trperiod(`trperiod') contid(`controls') lag(`lag') `prais' replace `options'
			lincom _b[_z_x_t`trperiod'] // diff-in-diffs

		quietly {
			replace estimate = r(estimate) in `r'
			replace se = r(se) in `r'
			replace t = r(t) in `r'
			replace p = r(p) in `r'
			replace lcl = r(lb) in `r'
			replace ucl = r(ub) in `r'
			} // end quietly
		} // end capture
	local r = `r' + 1
	} // end foreach

	/* track variables generated */
     local itsapermvars id nC idC estimate se t p lcl ucl
     char def _dta[_itsapermvars] "`itsapermvars'"

	/* generate forest-plot */
	if `"`plot'`plot2'"' != ""{

		/* handling value labels */
		tempvar id2
		if "`pvarlabl'" != "" {
			tempvar id1
			decode id, gen(`id1')
			encode `id1', gen(`id2')
		}
		else {
			qui gen `id2' = id if id !=.
		}

		/* get pvar variable label */
		local ydesc : var label `pvar'
		if `"`ydesc'"' == "" local ydesc "`pvar'"

		/* location of xmlabels */
		quietly sum lcl
		local lxmlabl = (r(min) - 0)/2
		quietly sum ucl
		local uxmlabl = (r(max) - 0)/2

		/* favors */
		if "`favors'" != "" {
			local pos = strpos("`favors'", "#")
			local leftfav = substr("`favors'",1,(`pos'-1))
			local rightfav = substr("`favors'",(`pos'+1),(length("`favors'")-`pos'+1) )
			local favopt `"xmlabel(`lxmlabl' `"`leftfav'"' `uxmlabl' `"`rightfav'"', noticks labels labsize(*1.5) labgap(5))"'
		}

		twoway(rcap lcl ucl `id2', lwidth(thin) lcolor(gray) hor) ///
		(scatter `id2' estimate, msymbol(circle_hollow) mcolor(gray) msize(medsmall)) ///
		(rcap lcl ucl `id2' if `id2'==`treatid', lwidth(thin) lcolor(black) hor) ///
		(scatter `id2' estimate if `id2'==`treatid', msymbol(circle) msize(medsmall) mcolor(black)), ///
		ytitle("`ydesc'") ///
		ylabel(`rmin'(1)`rmax', labsize(vsmall) angle(hor) valuelabel glcolor(dimgray)) ///
		xtitle(Difference-in-differences in trends (95% CIs), size(medium)) ///
		xscale(titlegap(3)) ///
		xline(0) xlabel(, nogrid format(" %9.0fc") labsize(small)) `favopt' ///
		legend(off) scheme(s2mono) `plot2'

	} // end plot

end