*! tscollap 1.0.3 cfb 0617 taken from collapse.ado
* version 5.2.0  9jun2000
* 1.0.2 add generate option per NJC
* 1.0.3 deal with tsset with panelid
program define tscollap
	version 6.0
	di " "
	qui tsset /* error if not set as time series */
	local curfreq `r(unit1)'  /* capture current frequency of dataset */
	tempvar _oldfq
	local tv `r(timevar)'
	local pv `r(panelvar)'
*	if "`pv'"!="" { dis "panelvar set to `pv'"}
	preserve
	rename `r(timevar)' `_oldfq'
	local tv `_oldfq'
	qui tsset `pv' `_oldfq'
	local map "yh0q0000000m"
	local ncur = index("`map'","`curfreq'")
	local tf2 "halfyear"
	local tf4 "quarter"
	local tf12 "month"
	local n 1
	local fcn "mean"

	gettoken 1 0: 0, parse("=,[] ") match(parens)
	if "`parens'" != "" {
		local 1 `"(`1')"'
	}
	iskey `1'

	while r(key)==0 {
		gettoken 2: 0, parse("=,[] ")
		if substr(`"`1'"',1,1)=="(" {		/* is typespec */
			typespec `"`1'"'
			local fcn `"`r(type)'"'
			gettoken 1 0: 0, parse("=,[] ") match(parens)
			if "`parens'" != "" {
				local 1 `"(`1')"'
			}
		}
		else if `"`2'"'=="=" { /* is neworoldvarname=oldvarname */
			gettoken 2 0: 0, parse("=,[] ")
			gettoken 3 0: 0, parse("=,[] ")
			v_eq_v `1' `3'
			local keep `"`keep' `r(var2)'"'
			local tar `"`tar' `r(var1)'"'
			local old`n' `"`r(var2)'"'
			local fcn`n' `"`fcn'"'
			local new`n' `"`r(var1)'"'
			local fmt`n' : format `old`n''
			local n = `n'+1
			gettoken 1 0: 0, parse("=,[] ") match(parens)
			if "`parens'" != "" {
				local 1 `"(`1')"'
			}
		}
		else {			/* varlist */
			local list `"`1'"'
			local varlist "req ex"
			parse `"`list'"'
			local i 1
			local vi : word `i' of `varlist'
			while `"`vi'"' != "" {
				local keep `"`keep' `vi'"'
				local tar `"`tar' `vi'"'
				local old`n' `"`vi'"'
				local fcn`n' `"`fcn'"'
				local new`n' `"`vi'"'
				local fmt`n' : format `old`n''
				local n=`n'+1
				local i=`i'+1
				local vi : word `i' of `varlist'
			}
			gettoken 1 0: 0, parse("=,[] ") match(parens)
			if "`parens'" != "" {
				local 1 `"(`1')"'
			}
		}
		iskey `1'
	}
	local 0 `"`1' `0'"'
	local n=`n'-1
	if `n'==0 {
		di " "
		di in r "One or more variables must be specified."
		restore
		error 198
		}

	syntax , TO(string) [GENerate(string)]

	local nto = index("`map'",lower("`to'"))
	if `nto'==0 {
		di in r "Error: target frequency is not valid."
		restore
		exit 198
		}
	if `nto'>`ncur' {
		di in r "The target frequency must be lower than the current frequency."
		restore
		exit 198
	}
	if `nto'==`ncur' {
		di in r "The data are recorded at the target frequency."
		di in r "The target frequency must be lower than the current frequency."
		restore
		exit 198
	}
	local tofreq = lower("`to'_`to'")
*dis "tofreq is `tofreq'"
*dis "generate is `generate'"
	local generat = cond("`generate'" == "", "`tofreq'", "`generate'")
	capture confirm new variable `generat'
	if _rc {
		di in r "`generat' already exists: " _c
		di in r "specify new variable with generate( ) option"
		exit 110
	}
	di " "
	di in gr "Converting from " upper("`curfreq'") " to " upper("`to'") "
	di " "
		/* Set up lag and coefficient vectors */
	local nrat = `ncur'/`nto'
	local nlag = `nrat' -1
	local cv  "c(1"
	local i 0
	while `i'<`nlag' {
		local cv   " `cv' 1"
		local i = `i' + 1
		}
	local cv = "`cv')"
	qui keep `keep' `pv' `tv'

					/* check uniqueness */
/*
Table:
	old`i'	(original) name of source variable		x
	use`i'  renamed old`i'
	new`i'  target variable					x
	drp`i'  =use`i' if may be dropped, else `" "'
	fcn`i'  function to call				x
	fmt`i'	%format of original variable
*/
	local i 1
	while `i' <= `n' {
		if `"`drp`i''"'=="" {
			tempname use
			local use`i' `"`use'"'
			rename `old`i'' `use'
			local lasti `i'
		}
		local j=`i'+1
		while `j'<=`n' {
			if `"`new`i''"' == `"`new`j''"' {
				di in red "error:" _n /*
				*/ _col(8) `"`new`i'' = (`fcn`i'') `old`i''"' /*
				*/ _n /*
				*/ _col(8) `"`new`j'' = (`fcn`j'') `old`j''"' /*
				*/ _n "name conflict"
				exit 198
			}
			if `"`drp`i''"'=="" & `"`old`i''"' == `"`old`j''"' {
				local lasti `j'
				local use`j' `"`use'"'
				local drp`j' `" "'
			}
			local j=`j'+1
		}
		if `"`drp`i''"'=="" {
			local drp`lasti' `"`use'"'
		}
		local i=`i'+1
	}

*	quietly {
		tempvar new
		local i 1
		while `i'<=`n' {
				/* pass nlag, cv to filter routine */
			_`fcn`i'' `new`i'' `use`i'' `nlag' "`cv'"
			capture drop `drp`i''
			label var `new`i'' `"(`fcn`i'') `old`i''"'
			format `new`i'' `fmt`i''
			local i=`i'+1
		}
*	}
		/* convert to new frequency */
	tempvar whmo want
	gen `whmo'=`tf`ncur''(dof`curfreq'(`tv'))
	gen `want'=(`whmo'==int(`whmo'/`nrat')*`nrat')
	qui drop if !`want'
	local lto = lower("`to'")
* dis "generate is `generate'"
	gen `generat'=`lto'ofd(dof`curfreq'(`tv'))
	format `generat' %t`lto'
	drop `tv'
	tsset,clear
	tsset `pv' `generat'
	restore,not

end

program define v_eq_v, rclass /* neworoldvar oldvar */
	unabbrev `2'
	ret local var2 `"`s(varlist)'"'
	capture confirm var `1'
	if _rc {
		capture confirm new var `1'
		if _rc {
			di in red `"`1' invalid variable name"'
			exit 198
		}
	}
	ret local var1 `"`1'"'
end

program define typespec, rclass /* <typespec> ) */
	tokenize `"`*'"', parse(`"() "')
	if `"`3'"' != ")" {
		unexpect `"`3'"' quote ")"
		/*NOTREACHED*/
	}
	ret local type `"`2'"'
	if `"`2'"'=="mean" | `"`2'"'=="gmean" | `"`2'"'=="sum" | /*
		*/ `"`2'"'=="rawsum" { exit }
	if `"`2'"'=="first" | `"`2'"'=="last"  { exit }
	unexpect `"`2'"' noquote "mean, sum, etc."
	/*NOTREACHED*/
end

program define unexpect /* <what_found> {quote|noquote} <what_expected> */
	if `"`2'"'=="quote" {
		local q "_quote"
	}
	di in red _quote `"`1'"' _quote " found where " /*
		*/ `q' `"`3'"' `q' " expected"
	exit 198
end

program define iskey, rclass
	ret scalar key = 1
	if `"`1'"'=="" | `"`1'"'=="[" | `"`1'"'=="," { exit }
	if `"`1'"'=="if" | `"`1'"'=="in" { exit }
	ret scalar key = 0
end


/* routines for calculating statistics */

program define _mean /* newvar oldvar nlag cv */
	args y x nlag cv

	local ty : type `x'
	if `"`ty'"'=="double" | `"`ty'"'=="long" {
		local ty "double"
	}
	else	local ty /* erase macro */
	quietly {
		egen `ty' `y' = filter(`x'),lags(0/`nlag') `cv' normalize
	}
end

program define _gmean /* newvar oldvar nlag cv */
	args y x nlag cv

	local ty : type `x'
	if `"`ty'"'=="double" | `"`ty'"'=="long" {
		local ty "double"
	}
	else	local ty /* erase macro */

		capture assert `x' > 0
		if _rc == 9 { noi di in bl "warning: taking logarithms of values <= 0" }
	quietly {
		replace `x' = log(`x')
		egen `ty' `y' = filter(`x'),lags(0/`nlag') `cv' normalize
		replace `y' = exp(`y')
	}
end

program define _sum /* newvar oldvar nlag cv */
	args y x nlag cv

	local ty : type `x'
	if `"`ty'"'=="double" | `"`ty'"'=="long" {
		local ty "double"
	}
	else	local ty /* erase macro */
	quietly {
		egen `ty' `y' = filter(`x'),lags(0/`nlag') `cv'
	}
end

program define _first /* newvar oldvar nlag */
	args y x nlag

	local ty : type `x'
	if `"`ty'"'=="double" | `"`ty'"'=="long" {
		local ty "double"
	}
	else	local ty /* erase macro */

	quietly {
		gen `ty' `y' = L`nlag'.`x'
	}
end

program define _last /* newvar oldvar */
	args y x

	local ty : type `x'
	if `"`ty'"'=="double" | `"`ty'"'=="long" {
		local ty "double"
	}
	else	local ty /* erase macro */

	quietly {
		gen `ty' `y' = `x'
	}
end