*! 1.0.0 Ariel Linden 04July2018

program define itsarand, rclass
version 11.0

	/* obtain settings */
	syntax varlist(min=1 numeric ts fv) [if] [in] [aw fw iw],	/// pweights not supported by -statsby-
	TREAT(varname)  			                             	///	treatment variable
	[ BLMin(integer 2)					                    	/// baseline period minimum observations
	TRMin(integer 2)											/// treatment period minimum observations
	REPs(integer 100)       									///
	SEED(string)            									///
	SAVing(string)												///
	NODOTS														///
	LEVel														/// evaluate level rather trend (the default)
	LEFT														///
	RIGHT														///
	CI(cilevel) ]



	/* check if data is tsset with panel and time vars */
	/* -tsset- errors out if no time variable set */
	qui	tsset
	local tvar `r(timevar)'
	local pvar `r(panelvar)'

	if "`pvar'" != "" {
		if "`r(balanced)'" != "strongly balanced" {
				di as err "strong balance required"
				exit 498
		}
	}

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

	if "`pvar'" != "" {
		local pv "bys `pvar' (`tvar'): "
	}

	if "`left'"!="" & "`right'"!="" {
		di as err "only one of left or right can be specified"
        exit 198
	}

	/* get measures */
	tempvar _t
	quietly {
		`pv' gen `_t' = _n if `touse'
		sum `_t' if `touse'
		local tmax `r(max)'
		local tr_max = `tmax' - `trmin' + 1
		local tr_start = `blmin' + 1
	}

	gettoken dvar xvar : varlist

	*******************************************************************
	* run the command using the entire dataset to get test statistic *
	******************************************************************
	preserve
	quietly {
		if "`pvar'" != "" & "`level'" != "" {
			statsby x=_b[`treat'], by(`pvar') clear: regress `dvar' `treat' `xvar' if `touse' [`weight' `exp']
			qui sum x
			local xstat = r(sum)
		}
		else if "`pvar'" != "" & "`level'" == "" {
			statsby xt=_b[1.`treat'#c.`_t'], by(`pvar') clear: regress `dvar' `xvar' c.`_t'##`treat' if `touse' [`weight' `exp']
			qui sum xt
			local xstat = r(sum)
		}
		else if "`pvar'" == "" & "`level'" != "" {
			regress `dvar' `treat' `xvar' if `touse' [`weight' `exp']
			return scalar xorig = _b[`treat']
			local xstat = _b[`treat']
		}
		else if "`pvar'" == "" & "`level'" == "" {
			regress `dvar' `xvar' c.`_t'##`treat' if `touse' [`weight' `exp']
			local xstat = _b[1.`treat'#c.`_t']
		}
		return local xstat `"`xstat'"'

		restore
	} // end quietly

	/* set the seed */
	if "`seed'" != "" {
		`version' set seed `seed'
	}
	local seed `c(seed)'

	************************************
	*********   MC simulations  ********
	************************************
	tempvar start test randseq

	if "`level'" != "" {
		local names "level"
	}
	else {
		local names "trend"
	}

	if `"`saving'"'=="" {
		tempfile saving
		local filetmp "yes"
	}
	else {
		_prefix_saving `saving'
		local saving    `"`s(filename)'"'
		local replace   `"`s(replace)'"'
	}

	// prepare post
	tempname postnam

	postfile `postnam' `names' using `"`saving'"', `replace'

    // setup for dots
	if "`nodots'" == "" {
		di
		_dots 0, title(Permutation replications) reps(`reps')
	}

	forval i = 1/`reps' {

		if "`nodots'" == "" {
			_dots `i' 0
		}

		quietly {

			tempvar start test randseq

			gen `start' = floor((`tr_max' - `tr_start' + 1)*runiform() + `tr_start') if `touse'
			gen `test'=. if `touse'
			`pv' replace `test' = `start'[1] if `touse'
			gen `randseq' =. if `touse'
			`pv' replace `randseq' = `_t' >= `test' if `touse'

			preserve
			capture {
				if "`pvar'" != "" & "`level'" != "" {
					statsby x=_b[`randseq'], by(`pvar') clear: regress `dvar' `randseq' `xvar' if `touse' [`weight' `exp']
					qui sum x
					local stat = r(sum)
				}
				else if "`pvar'" != "" & "`level'" == "" {
					statsby xt=_b[1.`randseq'#c.`_t'], by(`pvar') clear: regress `dvar' `xvar' c.`_t'##`randseq' if `touse' [`weight' `exp']
					qui sum xt
					local stat = r(sum)
				}
				else if "`pvar'" == "" & "`level'" != "" {
					regress `dvar' `randseq' `xvar' if `touse' [`weight' `exp']
					local stat = _b[`randseq']
				}
				else if "`pvar'" == "" & "`level'" == "" {
					regress `dvar' `xvar' c.`_t'##`randseq' if `touse' [`weight' `exp']
					local stat = _b[1.`randseq'#c.`_t']
				}
			} // capture

			if c(rc) == 111 {
				di as err "The statistic of interest (i.e. level or trend) was omitted because of collinearity. Respecify your xvars and/or weights"
				exit 111
			}

			post `postnam' (`stat')
			restore
			drop `start' `test' `randseq'

		} //end quietly

	} //end forval
	postclose `postnam'

	***************************************************************
	/* load file `saving' with permutation results and evaluate  */
	***************************************************************
	preserve

	capture use `"`saving'"', clear
	if c(rc) {
		if c(rc) >= 900 & c(rc) <= 903 {
			di as err "insufficient memory to load file with permutation results"
		}
		error c(rc)
	}

	/* Evaluate observed data relative to original data */

	di _n
	tempname tobs c n p //se ll ul ci

	quietly {

		/* "T(obs)" */
		scalar `tobs' = `xstat'

		/* Get name of variable in saving dataset */
		describe, varlist
		local name = r(varlist)

		/* Get count of actual reps */
		count
		scalar `n' =  r(N)

		/* left, right or absolute */
		if "`left'"!="" {
			count if `name' <= `xstat'
			local event "T <= T(obs)"
		}
		else if "`right'"!="" {
			count if `name' >= `xstat'
			local event "T >= T(obs)"
		}
		else {
			count if abs(`name') >= abs(`xstat')
			local event "|T| >= |T(obs)|"
		}

		scalar `c' =  r(N)
		scalar `p' = `c' / `n'
		return scalar n =  `n'
		return scalar c =  `c'
		return scalar p = `p'

		/* get CIs */
		cii_14_0 `n' `c' , level(`ci')
		tempname se ll ul
		scalar `se' =  r(se)
		scalar `ll' = r(lb)
		scalar `ul' = r(ub)

	} // end quietly

	*******************
	* Display results *
	*******************

	disp ""
	disp "Monte Carlo permutation results                    Number of obs   = "  %9.0g as result  `N'
	disp ""
	tempname Tab results
    .`Tab' = ._tab.new, col(8) lmargin(0) //ignore(.b)
    ret list
    // column           1      2     3     4     5     6     7     8
    .`Tab'.width       13    |12     8     8     8     8    10    10
    .`Tab'.titlefmt %-12s      .     .     .     .     .  %20s     .
    .`Tab'.pad          .      2     0     0     0     0     0     1
    .`Tab'.numfmt       .  %7.4g     .     . %7.4f %7.4f     .     .
	.`Tab'.sep, top
    .`Tab'.titles "T" "T(obs)" "c" "n" "p=c/n" "SE(p)" "[`ci'% Conf. Interval]" ""
	.`Tab'.sep, middle
	.`Tab'.row    "`name'" 				///
		`tobs'							///
		`c'								///
		`n'								///
		`p'								///
		`se'							///
		`ll'							///
		`ul'
	.`Tab'.sep, bottom

	/* Table footnote */
	di as txt ///
	"Note: Confidence intervals are with respect to p=c/n."
     di in smcl as txt "Note: c = #{`event'}"

	/* restore to orginal file */
	restore

end