capture program drop genstacks
program define genstacks
	version 9.0
	syntax namelist, [CONtextvars(varlist)] [STAckid(name)] [ITEmname(name)] [TOTstackname(name)] [REPlace] [RESpid(name)] [NOCheck] [fe(namelist)] [FEPrefix(string)]

	gettoken firststub otherstubs: namelist

	// namelist contains stubs
	// stackvars contains vars which identify a set of PTVS: e.g. cid respid

	set more off

	display in smcl
	display as text

	display "{text}{pstd}"


		/* diagnosing batteries with different sizes: */

		if ("`nocheck'"!="nocheck") {

			local diffsize = 0
			local previousvarsize = 0
			foreach stub of local namelist {
				local varexists = 0
				if (`varexists'!=`previousvarsize') local diffsize = 1

				//display "`stub'*"



				foreach var of varlist `stub'* {

					// if what comes after the stub is not numeric, skip
					// this is useful if different batteries share part of the stub (e.g. rsym and rsymp)
					local strindex = substr("`var'",strlen("`stub'")+1,.)
					//display "`strindex'"

					if (real("`strindex'")==.) continue

					local varexists = `varexists' + 1
				}


				if (`varexists'==0) {
					// unreachable anyway: it stops earlier with an error
					display "No variables starting with {bf:`stub'}"
					exit
				}
				else {
					display "Battery {bf:`stub'} contains `varexists' variables{break}"
				}
				local previousvarsize = `varexists'
			}
			display ""
			if (`diffsize'==1) {
				display "ERROR: Not all batteries have the same size!"
				display "Processing stopped."
				error 416
			}
		}
		/* */







		//local itemlist = ""

		foreach var of varlist `firststub'* {
			local strindex = substr("`var'",strlen("`firststub'")+1,.)
			if (real("`strindex'")==.) continue

			//local itemlist = "`itemlist'`strindex',"
			local itemlist `itemlist' `strindex'

		}
		// remove extra comma
		//local itemlist = substr("`itemlist'",1,strlen("`itemlist'")-1)

		display "***`itemlist'***"

		local error = 0

		foreach stub of local otherstubs {

			foreach var of varlist `stub'* {
				local strindex = substr("`var'",strlen("`stub'")+1,.)

				if (real("`strindex'")==.) continue

				local thisindex = real("`strindex'")
				local thislist `thisindex'

				local isinlist : list thislist in itemlist

				display "--(`isinlist')--`thislist' > `itemlist'"
				//if (inlist(real("`strindex'"),`itemlist')==0) {
				if (`isinlist'==0) {
					display "ERROR: battery {bf:`stub'} includes item with code {bf:`strindex'}, which is not present in master battery {bf:`firststub'}.{break}"
					local error = 1
				}
			}
			if (`error'==1) {
				display " {break} {break}"
			}
		}

		if (`error'==1) {
			display "Processing stopped."
			error 416
		}

	display ""

	display "{text}{pstd}"


	capture drop _respid
	egen _respid=fill(1/2)
	local stkvars = "_respid"

	if ("`contextvars'" == "") {
		//display "not set"
		capture drop _ctx_temp
		gen _ctx_temp = 1
		local ctxvar = "_ctx_temp"
		//local stkvars = "_ctx_temp `stackvars'"
	}
	else {

		capture drop _ctx_temp
		capture label drop _ctx_temp
		quietly _mkcross `contextvars', generate(_ctx_temp) missing

		//display "contextvar set as `contextvar'"
		local ctxvar = "_ctx_temp"
		//local stkvars = "`stackvars'"
	}

	//exit

	// loads all values of the context variable
	quietly levelsof `ctxvar', local(contexts)

	// stacked variable "party" can be different from stacked variable "stack", if parties are not always used consecutively!!!
	capture drop genstacks_stack
	capture drop genstacks_item

	quietly generate genstacks_stack = .
	quietly generate genstacks_item = .

	// create stacked variables
	foreach stub of local namelist {
		display "Creating empty stacked variable {result:`stub'}..." _continue
		capture drop `stub'
		quietly gen `stub' = .
		display "done.{break}"
	}

	display ""

	capture drop genstacks_totstacks
	generate genstacks_totstacks = .

	// now the beef.

	// loops over all contexts
	foreach context in `contexts' {
		display "{text}{pstd}Context {result:`context'} uses " _continue

		/* 1. finding used PTVs in this context */
		// NOTE: ONLY THE FIRST STUB IS USED
		// FOR TESTING how many parties are used


		// count observations in this context
		quietly count if `ctxvar'==`context'
		quietly return list
		local numobs = r(N)

		local countUsedPTVs = 0
		local usedPTVs = ""

		// new
		//display "Looping over stubs"

		local countProcessedStubs = 0

		foreach stub of local namelist {
			local theseIndices = ""

			//display "`stub' ["

			foreach var of varlist `stub'* {
				// if what comes after the stub is not numeric, skip
				// this is useful if different batteries share part of the stub (e.g. rsym and rsymp)
				local strindex = substr("`var'",strlen("`stub'")+1,.)
				//display "`strindex'"
				if (real("`strindex'")==.) continue


				// count missing values for this item within this context
				quietly count if `var'==. & `ctxvar'==`context'
				quietly return list
				local missingptvs = r(N)

				// if no. of missing values less than no. of observations, this PTV is used
				if `missingptvs'<`numobs' {
					local theseIndices "`theseIndices' `strindex'"
				}
			}
			//display "`theseIndices'] "
			if (`countProcessedStubs'==0) {
				local usedIndices "`theseIndices'"
			}
			else {
				local usedIndices: list usedIndices | theseIndices

				// this is alphabetical!
				//local usedIndices: list sort usedIndices
			}
			local countProcessedStubs = `countProcessedStubs' + 1
			//display "`usedIndices'"
		}

		local countUsedIndices : list sizeof usedIndices

		display "{result:`countUsedIndices'} items" " " "({result:" trim("`usedIndices'") "})." _continue
		display ""

		replace genstacks_totstacks = `countUsedIndices' if `ctxvar'==`context'

		/* 2. expanding and numbering stacks */

		//{text}{pmore}
		display "{break}Expanding cases..." _continue

		// expand cases
		quietly expand `countUsedIndices' if `ctxvar'==`context'	    /* create as many cases as ptvs in country */
		// assign stack number
		quietly: bysort `stkvars': replace genstacks_stack = _n if `ctxvar'==`context' /* stack variable identifies each case
									  within each respondent id                */

		display "done. " _continue //{break}

		/* 3. copying data */

		display "Copying values: " _continue

		// processing different stubs
		foreach stub of local namelist {

			local stack = 0
			//display "Copying values for `stub' (" _continue
			display " `stub'" _continue
			foreach thisIndex in `usedIndices' {
				local stack = `stack' + 1
				//local thisIndex = subinstr("`thisptv'", "`ptvstub'","",.)

				//display "`stub'" "`thisIndex' " _continue
				capture quietly replace `stub' = `stub'`thisIndex' if genstacks_stack==`stack' & `ctxvar'==`context'
				if _rc {
					//display "WARNING: `_rc'"
				}

				quietly replace genstacks_item = `thisIndex' if genstacks_stack==`stack' & `ctxvar'==`context'
			}
			// )
			//display "done." _continue
			//display ""

		}
		display ""
		display ""

	}

	display "{text}{pstd}"

	// labeling, based on last usedPTVs
	foreach stub of local namelist {

		gettoken firstIndex : usedIndices

		//local firstIndex = subinstr(word("`usedIndices'",1), "","",.)
		local firstvar = "`stub'" + "`firstIndex'"
		local label1 : variable label `firstvar'
		local valindex = strpos("`label1'", "`firstIndex'")
		//local label = subinstr("`label1'", "`firstIndex'","_",.)
		local label = substr("`label1'", 1, `valindex'-1)
		display "Labeling {result:`stub'}: `label'"
		label var `stub' "`label'*" // copy from first label, by replacing 'stack' with nothing
		display "{break}"
	}

	display ""

	// optionally dropping original vars
	if ("`replace'"=="replace") {
		display "{text}{pstd}"
		foreach stub of local namelist {
			// preserve new, stacked vars (they have plain stub names)
			quietly rename `stub' tmp`stub'
			display "As requested, dropping {result:`stub'*}.{break}"
			drop `stub'*
			quietly rename tmp`stub' `stub'
		}
	}

	sort `stkvars' genstacks_stack

	if ("`fe'"!="") {
		if ("`feprefix'"!="") {
			local fpref = "`feprefix'"
		}
		else {
			local fpref = "mean_"
		}

		display "{text}{pstd}Applying fixed-effects treatment (saving and subtracting the respondent-level mean){break}"
		display "to variables "
		foreach var of local fe {
			display "`var'..."
			capture drop `fpref'`var'
			bysort _respid: egen `fpref'`var' = mean(`var')
			replace `var' = `var' - `fpref'`var'
		}
		display "{break}done."
	}


	if ("`respid'"!="") {
		rename _respid `respid'
	}
	else {
		capture drop _respid
	}


	//if ("`contextvar'"=="") {
		capture drop _ctx_temp
	//}

	// NOTE: this drops existing variables if the user specifies them as names of variables to create,
	// and does so without requiring a "replace" option (this might be contra Stata practices)

	if ("`stackid'"!="") {
		capture drop `stackid'
		rename genstacks_stack `stackid'
	}

	if ("`itemname'"!="") {
		capture drop `itemname'
		rename genstacks_item `itemname'
	}

	if ("`totstackname'"!="") {
		capture drop `totstackname'
		rename genstacks_totstacks `totstackname'
	}
	else {
		capture drop genstacks_nstacks
		rename genstacks_totstacks genstacks_nstacks
	}


end