*! version 1.1.6 MLB 15Jan2014
* version 1.1.5 MLB 27Okt2010
* version 1.1.4 MLB 13Jan2010
* version 1.1.2 MLB 22Jun2009
* remove a -set trace on-
* version 1.1.1 MLB 22Nov2008
* fixed bug with obspr option
* version 1.1.0 MLB 31Mar2008
* bootstrap standard errors
* version 1.0.2 MLB 22Feb2008
* fix a bug in in the -normal- option
program define _ldecomp, eclass properties(or)
	version 9.0
	syntax varlist [if] [in] [fw iw pw], ///
	Direct(varname)                      ///
	Indirect(varlist)                    ///
	[                                    ///
	at(string)                           ///
	OBSpr                                ///
	PREDPr                               ///
	PREDOdds                             ///
	RIndirect                            ///
	or                                   ///
	noLEGend                             ///
	noDEComp                             ///
	INTeractions                         ///
	NORMal                               ///
	range(numlist min=2 max=2)           ///
	nip(integer 1000)                    ///
	Reps(passthru)                       ///
	STRata(passthru)                     ///
	SIze(passthru)                       ///
	CLuster(passthru)                    ///
	IDcluster(passthru)                  ///
	SAVing(passthru)                     ///
	bca                                  ///
	mse                                  ///
	Level(passthru)                      ///
	nodots                               ///
	seed(passthru)                       ///
	JACKknifeopts(passthru)              ///
	noBOOTstrap                          ///
	]

	marksample touse
	markout `touse' `direct' `indirect'

	// remove the direct and indirect variables from varlist
	local varlist : list varlist - direct
	local varlist : list varlist - indirect

	// split varlist into dependent (lhs) and control (rhs) variables
	gettoken lhs rhs : varlist


	local wgt "[`weight'`exp']"
	if "`weight'" == "pweight" {
		local swgt "[aw`exp']"
	}
	else {
		local swgt "[`weight'`exp']"
	}

	if "`range'" != "" & "`normal'" == "" {
		di as err "option range() may only be specified if option normal is also specified"
		exit 198
	}
	if `nip' != 1000 & "`normal'" == "" {
		di as err "option nip() may only be specified if option normal is also specified"
		exit 198
	}
	if `: word count `indirect'' > 1 & "`normal'" != "" {
		di as err "option indirect() may contain only one variable if option normal is specified"
		exit 198
	}

	// Parse at()
	local i = 1
	while "`at'" != "" {
		gettoken block at : at, parse(";")
		local ok = `: word count `block'' == 2
		local atvar`i' : word 1 of `block'
		local atval`i' : word 2 of `block'
		capture unab atvar`i' : `atvar`i'', max(1)
		if _rc local ok = 0
		if !`: list atvar`i' in rhs' local ok = 0
		capture confirm number `atval`i''
		if _rc {
			capture confirm scalar `atval`i''
			if _rc local ok = 0
		}
		gettoken semicolon at : at, parse(";")
		if  !`ok' {
			di as error "each element in the at() option must contain of two elements"
			di as error "the first element is one of the control variables and the second element its value"
			exit 198
		}
		local atvars "`atvars' `atvar`i''"
		local `i++'
	}
	local k_at = `i' - 1
	local rest : list rhs - atvars

	// compute predicted and counterfactual proportions
	preserve

	qui levelsof `direct' if `touse'
	local levs "`r(levels)'"

	local i = 1

	tempname prop odds prop_obs b
	local k : word count `levs'
	matrix `prop_obs' = J(`k',1,.)

	foreach lev in `levs' {
		tempvar d`lev'
		qui gen byte `d`lev'' = `direct' == `lev' if `touse'
		local dirvars "`dirvars' `d`lev''"
		if "`interactions'" != "" {
			foreach var of varlist `indirect' {
				tempvar d`lev'X`var'
				qui gen `d`lev'X`var'' = `d`lev'' * `var' if `touse'
				local dirvars "`dirvars' `d`lev'X`var''"
			}
		}
	}

	if "`interactions'" == "" {
		local indir "`indirect'"
	}
	else {
		local indir ""
	}

	qui logit `lhs' `rhs' `indir' `dirvars' if `touse' `wgt', nocons

	if "`normal'" == "" {
		forvalues i = 1/`k_at' {
			qui replace `atvar`i'' = `atval`i''
		}
		if "`rest'" != "" {
			foreach var of varlist `rest' {
				sum `var' if `touse' `swgt', meanonly
				qui replace `var' = r(mean)
			}
		}
		local i = 1
		foreach lev in `levs' {
			qui replace `d`lev'' = 1 if `touse'
			if "`interactions'" != "" {
				foreach var of varlist `indirect' {
					qui  replace `d`lev'X`var'' = `var' if `touse'
				}
			}
			local restvals : list levs - lev
			foreach rest in `restvals' {
				qui replace `d`rest'' = 0 if `touse'
				if "`interactions'" != "" {
					foreach var of varlist `indirect' {
						qui  replace `d`rest'X`var'' = 0 if `touse'
					}
				}
			}
			tempvar pr`lev'
			local pr "`pr' `pr`lev''"
			qui predict double `pr`lev'' if `touse', pr
			local vallab : label (`direct') `lev'
			local vallab : subinstr local vallab " " "_", all
			local coln "`coln' association:`vallab'"
			local rown "`rown' `vallab'"
			sum `lhs' if `direct' == `lev' & `touse' `swgt', meanonly
			matrix `prop_obs'[`i',1] = `r(mean)'
			local `i++'
		}
		collapse (mean) `pr' if `touse' `wgt', by(`direct')
		mkmat `pr', matrix(`prop')
	}

	if "`normal'" != ""{
		foreach lev in `levs' {
			tempname m`lev' sd`lev'
			qui sum `indirect' if `direct' == `lev' & `touse' `swgt'
			scalar `m`lev'' = r(mean)
			scalar `sd`lev'' = r(sd)
		}

		tempvar y x

		if "`range'" == "" {
			qui sum `indirect' if `touse' `swgt', meanonly
			local low =  r(min) - .1*(r(max) - r(min))
			local high = r(max) + .1*(r(max) - r(min))
			qui range `x' `low' `high' `nip'
		}
		else {
			qui range `x' `range' `nip'
		}
		qui gen `y' = .

		matrix `prop' = J(`k', `k', .)

		forvalues i = 1/`k_at' {
			local fixat "_b[`atvar`i'']*`atval`i'' + `fixat'"
		}
		if "`rest'" != "" {
			foreach var of varlist `rest' {
				sum `var' if `touse', meanonly
				local fixrest "_b[`var']*`r(mean)' + `fixrest'"
			}
		}
		local i = 1
		foreach lev in `levs' {
			local j = 1
			if "`interactions'" == "" {
				local indir "_b[`indirect']*`x' + "
				local int ""
			}
			else {
				local indir ""
				local int "+ _b[`d`lev'X`indirect'']*`x'"
			}
			foreach lev2 in `levs' {
				qui replace `y' = normalden(`x', scalar(`m`lev2''), scalar(`sd`lev2''))* ///
					          invlogit(`indir' `fixat' `fixrest' _b[`d`lev''] `int')
				qui integ `y' `x'
				matrix `prop'[`j', `i'] = `r(integral)'
				local `j++'
			}
			sum `lhs' if `direct' == `lev' & `touse' `swgt', meanonly
			matrix `prop_obs'[`i',1] = `r(mean)'
			local `i++'
			local vallab : label (`direct') `lev'
			local vallab : subinstr local vallab " " "_", all
			local coln "`coln' association:`vallab'"
			local rown "`rown' `vallab'"
			local title2 "(assuming that `indirect' is normally distributed)"
		}
	}

	restore

// decompose total effect into direct and indirect effects
	mata: decomp_lor()

// display results
	matrix rownames `prop_obs' = `rown'
	matrix colnames `prop_obs' = "proportion"

	matrix rownames `prop' = `rown'
	matrix colnames `prop' = `coln'
	matrix rownames `odds' = `rown'
	matrix colnames `odds' = `coln'

	forvalues i= 1/`k' {
		local l = `i' + 1
		forvalues j = `l'/`k'{
			local eq "`: word `j' of `levs''/`:word `i' of `levs''"
			local rown2 "`rown2' `eq':total `eq':indirect1 `eq':direct1 `eq':indirect2 `eq':direct2 "
		}
	}
	forvalues i= 1/`k' {
		local l = `i' + 1
		forvalues j = `l'/`k'{
			local eq "`: word `j' of `levs''/`:word `i' of `levs''"
			local rown2 "`rown2' `eq'r:method1 `eq'r:method2 `eq'r:average"
		}
	}
	matrix colnames `b'  = b
	matrix rownames `b'  = `rown2'
	matrix `b' = `b''
	ereturn post `b', esample(`touse')
	ereturn scalar k_eform = comb(`: word count `levs'',2)
	ereturn matrix prop_obs = `prop_obs'
	ereturn matrix prop_pred = `prop'
	ereturn matrix odds_pred = `odds'
end

mata:
void decomp_lor() {
	matname = st_local("prop")
	matodds = st_local("odds")
	matdist = st_local("b")
	prop = st_matrix(matname)
	odds = prop :/ (1:- prop)
	st_matrix(matodds, odds)
	r =
	b = J(comb(rows(prop),2):*8,1,.)
	k=1
	for(i=1;i<=rows(odds);i++){
		for(j=i+1;j<=rows(odds);j++) {
			b[k,1] = ln(odds[j,j]/odds[i,i])
			k = k + 1
			b[k,1] = ln(odds[j,i]/odds[i,i])
			k = k + 1
			b[k,1] = ln(odds[j,j]/odds[j,i])
			k = k + 1
			b[k,1] = ln(odds[j,j]/odds[i,j])
			k = k + 1
			b[k,1] = ln(odds[i,j]/odds[i,i])
			k = k + 1
		}
	}
	l=1
	for(i=1;i<=rows(odds);i++) {
		for(j=i+1;j<=rows(odds);j++) {
			b[k,1] = b[l+1,1]/b[l,1]
			k = k + 1
			b[k,1] = b[l+3,1]/b[l,1]
			k = k + 1
			b[k,1] = (b[k-1,1]+b[k-2,1])/2
			k = k + 1
			l=l+5
		}
	}
	st_matrix(matdist, b)
}
end