*! version 1.0.3 29apr2015


program define igenerate, sortpreserve
version 12.1

	syntax varlist(numeric max=2 min=1) [if] [in] , Coding(name)  [ GENerate(namelist max=2) Omit(numlist max=2) ia]
	marksample touse


	* store r() to return it later
	tempname user_r
	capture _return drop user_r
	_return hold user_r

	* Some globals and temporary variables
	tempvar helpvar1
	capture macro drop iavarlist1 iavarlist2		// is there a better solution for this?



	* Fill or complete generate if not specified by user
	if "`generate'" == "" {
		local generate = "`varlist'"
	}

	* check ia-option
	if "`ia'" == "ia" & "`coding'" != "we" & "`coding'" != "weightedeffect" & "`coding'" != "sweeney" {
		dis as error "Option " as input "ia " as error "is allowed only with weighted effect coding / sweeney coding"
		exit 197
		}

	* check how many variables are specified, then call the algorithm for single variables in a loop
	local nv: word count `varlist'		// nv = number of variables
	local nn: word count `generate'		// nn = number of names in generate option
	local no: word count `omit'			// no = number of omited categories
	if `nv' > `nn' {
		dis as error "You must specify as many names in the generate option as variables in varlist"
		exit 103
	}
	if `nv' < `nn' {
		dis as error "You must specify as many names in the generate option as variables in varlist"
		exit 102
	}
	if `nv' < `no' {
		dis as error "You specified more than one omitted category in the generate option but you have only one variable"
		exit 123
	}

	gettoken var1 var2 : varlist
	gettoken gen1 gen2 : generate
	gettoken omit1 omit2 : omit
		if `no' == 1 & `nv' == 2 {
		local omit2 = `omit1'
		}


	* Loop that replaces the arguments varlist, omit and generate and then runs the code that has been written for one variable
	foreach num of numlist 1/`nv' {
		local varlist = "`var`num''"
		local omit = "`omit`num''"
		local generate = "`gen`num''"


		* HERE starts the code written for one variable

		* Check content of Coding;
		* allowed "d" "dummy" "a" "adjacent" "ra" "reverseadjacent" "e" "effect" "we" "weightedeffect" "sweeney"
		if "`coding'" == "d" | "`coding'" == "dummy" {
			display as text "Dummy coding of `varlist'"
				if  "`omit'" != "" {
					qui sum `varlist' if `varlist' == `omit' & `touse'
						if r(N) < 1 {
							dis as error "Category `omit' cannot be used as the reference category because there are no observations or the category `omit' does not exist at all"
							exit 2000
						}
				}
			igen_d `varlist' if `touse' , gen(`generate') o(`omit')
		}

		else if "`coding'" == "a" | "`coding'" == "adjacent" {
			display as text "Adjacent coding of `varlist' (forward differences)"
			if  "`omit'" != "" {
					display as error "Option " as input "omit " as error "is not allowed with reversed coding"
					exit 197
			}
			igen_a `varlist' if `touse', gen(`generate') c(forward)
		}

		else if "`coding'" == "ra" | "`coding'" == "reverseadjacent" {
			display as text "Reversed adjacent coding of `varlist' (backward differences)"
			if  "`omit'" != "" {
				display as error "Option " as input "omit " as error "is not allowed with reversed adjacent coding"
				exit 197
			}
			igen_a `varlist' if `touse', gen(`generate') c(backward)
		}

		else if "`coding'" == "e" | "`coding'" == "effect" {
			display as text "Effect coding of `varlist'"
				if  "`omit'" != "" {
					qui sum `varlist' if `varlist' == `omit' & `touse'
						if r(N) < 1 {
							dis as error "Category `omit' cannot be used as the reference category because there are no observations or the category `omit' does not exist at all"
							exit 2000
						}
				}
			igen_e `varlist' if `touse' , gen(`generate') o(`omit') c(asbalanced)
		}

		else if "`coding'" == "we" | "`coding'" == "weightedeffect" | "`coding'" == "sweeney" {
			display as text "Weighted effect coding (Sweeney coding) of `varlist'"
			if  "`omit'" != "" {
					qui sum `varlist' if `varlist' == `omit' & `touse'
						if r(N) < 1 {
							dis as error "Category `omit' cannot be used as the reference category because there are no observations or the category `omit' does not exist at all"
							exit 2000
						}
				}
			if "`ia'" == "" {
				igen_e `varlist' if `touse' , gen(`generate') o(`omit') c(asobserved)
			}
			if "`ia'" == "ia" {
				igen_e `varlist' if `touse' , gen(`generate') o(`omit') c(asobserved) ia(`num')
			}
		}

		else {
			dis as error "Option coding incorrectly specified. Coding must be one of the following elements:"
			dis as text "d dummy a adjacent ra reverseadjacent e effect we weightedeffect sweeney"
			dis as error "You typed: " as input "`coding'"
			exit 197
		}

	}

	* IF weighted effect coding and ia specified: Generate orthogonal interaction terms
	if "`ia'" == "ia" {
		tokenize "$iavarlist2"
		local nd: word count $iavarlist2
		foreach var of varlist $iavarlist1 {
			foreach num of numlist 1/`nd' {
				gen ia_`var'_``num'' = `var'*``num''
					label variable ia_`var'_``num'' "`var' X ``num''"
				qui sum ia_`var'_``num'' if `var' == 1 & ``num'' == 1 & `touse'
				local ia_`var'_``num'' = r(N)
				local ialist `ialist' ia_`var'_``num''
			}
		}
		egen helpvar1 = rowmax($iavarlist1 $iavarlist2)		// mark reference cases (they have values < 0)
		qui sum helpvar1 if helpvar1 < 0 & `touse'
		local a = r(N)										// a = frequency in the cell omitted in both sets of dummies
		foreach ia in `ialist' {
			qui replace `ia' = ``ia''/`a' if helpvar1 < 0 & `touse'		// replace ia list for reference observations
		}
		drop helpvar1
		foreach var in $iavarlist1 {
			foreach num of numlist 1/`nd' {
				qui sum ia_`var'_``num'' if ia_`var'_``num'' < 0 & ``num'' == 1 & `touse'
					local b = r(N)
				qui replace ia_`var'_``num'' = - `ia_`var'_``num'''/`b' if ia_`var'_``num'' < 0 & ``num'' == 1 & `touse'
				qui sum ia_`var'_``num'' if ia_`var'_``num'' < 0 & `var' == 1 & `touse'
					local c = r(N)
				qui replace ia_`var'_``num'' = - `ia_`var'_``num'''/`c' if ia_`var'_``num'' < 0 & `var' == 1 & `touse'
			}
		}

	}



capture macro drop iavarlist1 iavarlist2
*capture drop helpvar1		// can this be deleted later?
_return restore user_r


end


* Programme for Dummy Coding with or without chosen reference
{
capture program drop igen_d
program define igen_d, sortpreserve
	syntax varname if, GENerate(name) [Omit(numlist max=1)]
	marksample touse
	dis ""
	dis as text "Frequency table of `varlist':"
	tab `varlist' if `touse', gen(`generate')		// should this be done quietly later? or with an option to supress it
		local nc = r(r)
		dis ""

	if "`omit'" != ""	{		// omitting category if omit has been chosen
		qui levelsof `varlist' if `touse', local(l)
		tokenize `l'
		local i = 0
		while `i' < `nc' {
			local i = `i'+1
			if ``i'' == `omit'	{
				local omitpos = `i'
			}
		}

		* labeling the variables according to contrast
		local rlab: var l `generate'`omitpos'
		drop `generate'`omitpos'
		if `omitpos' == 1	{
			local varlistbegin = 2
		}
		else {
			local varlistbegin = 1
		}
		if `omitpos' == `nc'	{
			local varlistend = `nc'-1
		}
		else {
			local varlistend = `nc'
		}
		foreach var of varlist `generate'`varlistbegin'-`generate'`varlistend'	{
			local lab: var l `var'
			label variable `var' "`lab' (vs `rlab')
		}
	}

end
}



* Program for effect coding
{
capture program drop igen_e
program define igen_e, sortpreserve
	syntax varname if, GENerate(name) Contrast(name) [Omit(numlist max=1) ia(numlist max=1)]
	marksample touse
	dis ""
	dis as text "Frequency table of `varlist':"
	tab `varlist' if `touse', gen(`generate')		// should this be done quietly later? or with an option to supress it
	local nc = r(r)
	dis ""
	if "`omit'" == "" {
		qui levelsof `varlist' if `touse', local(l)
		tokenize `l'
		local omit = `1'
	}


	qui levelsof `varlist' if `touse', local(l)
	tokenize `l'
	local i = 0
	while `i' < `nc' {
		local i = `i'+1
		if ``i'' == `omit'	{
			local omitpos = `i'
		}
	}

	drop `generate'`omitpos'
	if `omitpos' == 1	{
		local varlistbegin = 2
	}
	else {
		local varlistbegin = 1
	}
	if `omitpos' == `nc'	{
		local varlistend = `nc'-1
	}
	else {
		local varlistend = `nc'
	}
	foreach var of varlist `generate'`varlistbegin'-`generate'`varlistend'	{
		qui replace `var' = -1 if `varlist' == `omit' & `touse'
		if "`contrast'" == "asobserved" {		// implement weighted effect coding
			qui sum `var' if `var' == 1 & `touse'
			local a = r(N)
			qui sum `var' if `var' == -1 & `touse'
			local b = r(N)
			qui replace `var' = -`a'/`b' if `var' == -1 & `touse'
			local lab: var l `var'
			label variable `var' "`lab' (vs observed mean)"

				* Save list of new variables for later use for building interaction terms
				if "`ia'" == "1" {
					global iavarlist1 $iavarlist1 `var'
				}
				if "`ia'" == "2" {
					global iavarlist2 $iavarlist2 `var'
				}
		}
		else {
			local lab: var l `var'
			label variable `var' "`lab' (vs as balanced mean)"
		}
	}

end
}


* Program for adjacent and reversed adjacent coding
{
capture program drop igen_a
program define igen_a, sortpreserve
	syntax varname if, GENerate(name) Contrast(name)
	marksample touse
	dis ""
	dis as text "Frequency table of `varlist':"
	tab `varlist' if `touse', gen(`generate')		// should this be done quietly later? or with an option to supress it
	local nc = r(r)
	dis ""

		* Making a copy of each variable to read labels in later loop
		foreach var of varlist `generate'1-`generate'`nc'	{
		tempvar `var'_
		gen `var'_ = `var'
		local lab: var l `var'
		label var `var'_ "`lab'"
		}

	drop `generate'1
	qui levelsof `varlist', local(l)
	tokenize "`l'"
	local i = 0
	foreach var of varlist `generate'2-`generate'`nc' {
		local i = `i'+1
		qui replace `var' = (`nc'-`i')/`nc' if `varlist' <= ``i''
		qui replace `var' = -`i'/`nc' if `varlist' > ``i''
	}
	if "`contrast'" == "backward" {
		local i = 0
		foreach var of varlist `generate'2-`generate'`nc' {
			local i = `i'+1
			qui replace `var' = `var'*-1
			local lab: var l `var'
			local labc: var l `generate'`i'_
			label variable `var' "`lab' vs `labc'"
		}
	}
	if "`contrast'" == "forward" {
		local i = 0
		foreach var of varlist `generate'2-`generate'`nc' {
			local i = `i'+1
			local lab: var l `var'
			local labc: var l `generate'`i'_
			label variable `var' "`labc' vs `lab'"
		}
	}
	drop `generate'1_-`generate'`nc'_

end
}