*MWG edited 3/11/2020: fixed variable abbreviation switch.

cap program drop apchx
program define apchx, rclass
	syntax using/ [, ///
	Label /// Check value label consistency
	Range /// Check value range consistency
	]
	cap drop __0*
	local switchback=0
	if `"`c(varabbrev)'"' == `"on"' {
		set varabbrev off
		local switchback=1
	}

	local vlist ""
	foreach check in type `range' `label' {
		local `check'list ""
		local `check'ct=0
	}
	local allmissmain
	local allmissuse
	local vct=0
	foreach var of varlist * {
		local ++vct
		************************Check type
		local v`vct'n `var'
		local v`vct't: type `var'
		if substr(`"`v`vct't'"',1,3)=="str" {
			local v`vct't "str"
			local v`vct'td "string"
		}
		if substr(`"`v`vct't'"',1,3)!="str" {
			local v`vct't "num"
			local v`vct'td "numeric"
		}
		****Check range
		local v`vct'mn
		local v`vct'mx
		if `"`range'"'!=`""'&!regexm(`"`:type `v`vct'n''"',"str") {
			qui count if !mi(`v`vct'n')
			if `r(N)'!=0 {
				qui sum `v`vct'n'
				local v`vct'mn=`r(min)'
				local v`vct'mx=`r(max)'
			}
			if `r(N)'==0 {
				local allmissmain `"`allmissmain' `v`vct'n'"'
			}

		}
		****Check value label
		local v`vct'va
		if `"`label'"'!=`""'&`"`:value label `v`vct'n''"'!=`""' {
			local v`vct'va `"`:value label `v`vct'n''"'
			local mnlb=100000000
			local mxlb=-100000000
			foreach v of varlist * {
				if `"`:value label `v''"'==`"`v`vct'va'"' {
					qui sum `v'
					if !inlist(`r(N)',0,.) {
						if `r(min)'<`mnlb' local mnlb=`r(min)'
						if `r(max)'>`mxlb' local mxlb=`r(max)'
					}
				}
			}
			local v`vct'mnlb `mnlb'
			local v`vct'mxlb `mxlb'
			forvalues lb=`v`vct'mnlb'/`v`vct'mxlb' {
				local v`vct'lb`lb' `"`:label (`var') `lb''"'
			}


		}

		local vlist "`vlist' `var'"
	}
	tempfile main
	qui sa `main'
	qui use `"`using'"', clear
	cap drop __0*
	forvalues c=1/`vct' {
		local var `v`c'n'
		cap confirm variable `var'
		if _rc==0 {
			****************Check type
			local typ: type `var'
			if substr(`"`typ'"',1,3)=="str" {
				local typ "str"
				local typd "string"
			}
			if substr(`"`typ'"',1,3)!="str" {
				local typ "num"
				local typd "numeric"
			}
			if `"`typ'"'!=""&`"`typ'"'!=`"`v`c't'"' {
				di as error `"`var' is `v`c'td' in main dataset and `typd' in the dataset to append"'
				local ++typect
				local typelist "`typelist' `var'"
			}
			*****Check ranage
			if `"`range'"'!=`""'&!regexm(`"`:type `var''"',"str")&!regexm(`"`v`c't'"',`"str"') {
				qui count if !mi(`var')
				if `r(N)'!=0&!regexm(`"`allmissmain'"',`"`var'"') {
					qui sum `var'
					if `r(min)'!=`v`c'mn'|`r(max)'!=`v`c'mx' {
						di as error `"`var' has range of `v`c'mn' to `v`c'mx' in main dataset and `r(min)' to `r(max)' in the dataset to append"'
						local rangelist `"`rangelist' `var'"'
						local ++rangect

					}
				}
				if `r(N)'==0 {
					local allmissuse `"`allmissuse' `var'"'
				}

			}
			**Check value labels
			if `"`label'"'!=`""'&!regexm(`"`:type `var''"',"str")&!inlist(`"`:value label `var''"',`""',`"`v`c'va'"') {
				di as error `"`var' has `v`c'va' value label in main dataset and `:value label `var'' in the dataset to append"'
				local labellist `"`labellist' `var'"'
				local ++labelct
			}

			if `"`label'"'!=`""'&`"`:value label `var''"'!=`""'&inlist(`"`:value label `var''"',`"`v`c'va'"') {
				forvalues lb=`v`c'mnlb'/`v`c'mxlb' {
					if `"`v`c'lb`lb''"'!=`"`:label (`var') `lb''"' {
						di as error `"`var' value label (`v`c'va') value `lb' is "`v`c'lb`lb''" in main dataset and "`:label (`var') `lb''" in the dataset to append"'
						if !regexm(`" `labellist' "',`" `var' "') local labellist `"`labellist' `var'"'
						local ++labelct
					}
				}
			}
		}
	}
	qui use `main', clear
	if `switchback' == 1 {
		set varabbrev on
	}

	foreach check in type `range' `label' {
		return local `check'_mismatch=`"``check'list'"'
		if ``check'ct'==0 di as result `"No `check' inconsistencies found"'
		if ``check'ct'==1 di as error `"1 `check' inconsistency found"'
		if ``check'ct'>1 di as error `"``check'ct' `check' inconsistencies found"'
	}

	local allmissmain=trim(`"`allmissmain'"')
	local allmissuse=trim(`"`allmissuse'"')
	if `"`allmissmain'"'!=`""' di as error `"`allmissmain' are all missing in master dataset"'
	if `"`allmissuse'"'!=`""' di as error `"`allmissuse' are all missing in using dataset"'


end