/*
Pengzhan Qian, p.qian@qmul.ac.uk, 2023/01/07
*/

cap prog drop rowsum
program define rowsum, sortpreserve
	version 17.0
	syntax namelist(min=3), SUMLIST(varlist min=1) [NEW(str) KEEP EXAMPLE(varlist)]
	//Split the main input and define sonlist
	tokenize "`namelist'"
	local size=wordcount("`namelist'")
	local id="`1'"
	local name_mother="`2'"
	local sonlist = "`3'"
	if `size'>3 {
	    forvalues i=4(1)`size'{
			local sonname="``i''"
		    local sonlist="`sonlist'"+" `sonname'"
			}
	}
	//Create a copy for mother obs
	qui expand 2 if `id'=="`name_mother'", gen(_rowsum)
	//Re-define _rowsum
	label var _rowsum "Summed obs from rowsum"
	label define _rowsum_mean 0 "not involved obs" 1 "summed obs" 2 "original obs", replace
	label values _rowsum _rowsum_mean
	qui gen _rowsum_temp=0
	qui replace _rowsum_temp=1 if _rowsum==1
	qui replace _rowsum_temp=1 if `id'=="`name_mother'"
	//Flag son obs
	foreach name_son_order in `sonlist'{
		qui replace _rowsum_temp=1 if `id'=="`name_son_order'"
	}
	//Sum and replace
	foreach v of varlist `sumlist' {
		local vartype: type `v'
		if substr("`vartype'",1,3)=="str" {
			di as error "cannot sum string variables"
		}
		if substr("`vartype'",1,4)=="byte" {
			di as error "`v' maybe a categorical variable (program is still running)"
		}
		//let the value of newly created obs be 0
	    qui replace `v'=0 if _rowsum==1
	    qui bysort _rowsum_temp: egen `v'_temp=sum(`v')
		qui replace `v'=`v'_temp if _rowsum==1
		drop `v'_temp
	}
	//Create new name if specified
	if "`new'"!= "" {
		qui replace `id'="`new'" if _rowsum==1
	}
	//Show examples of summing up
	tokenize "`sumlist'"
	local var_example="`1'"
	qui replace _rowsum=2 if _rowsum_temp==1 & _rowsum!=1
	if "`example'"=="" {
	    di as result "rowsum results example (with the first variable in sumlist):"
		list `id' `var_example' _rowsum if _rowsum_temp==1
	}
	else {
	   di as result "rowsum results example (with user-defined variables):"
	   list `id' `example' _rowsum if _rowsum_temp==1
	}
	//Drop original obs unless specified
	if "`keep'"!="keep" {
		qui drop if _rowsum==2
		di in red "original observations are dropped"
	}
	if "`keep'"=="keep" & "`new'"!= "" {
		di as result "original observations are kept"
	}
	if "`keep'"=="keep" & "`new'"== "" {
		di in red "original observations are kept and share the same name with the new observation"
	}
	//Drop temp variable
	drop _rowsum_temp
end