* stripolate
*! 1.1.0 NJC 15dec2016
* 1.0.0 NJC 14dec2016
* mipolate 1.2.0 NJC 2sep2015
* 1.1.0 NJC 27aug2015
* 1.0.0 NJC 20jul2015
* ipolate 1.3.3  21sep2004
program stripolate, byable(onecall) sort
	version 10
	syntax varlist(min=2 max=2) [if] [in], ///
	GENerate(string) ///
	[ BY(varlist)    ///
	Forward          ///
	Backward         ///
	Groupwise ]

	// syntax checks
	tokenize `varlist'
	args stry x

	capture confirm string var `stry'
	if _rc {
		di as err "{p}stripolate is for interpolation of " ///
		"string variables only: try {cmd:mipolate} (SSC)?{p_end}"
		exit _rc
	}

	capture confirm numeric var `x'
	if _rc {
		di as err "{p}stripolate is for interpolation with " ///
		"respect to a numeric variable: see {help stripolate}{p_end}"
		exit _rc
	}

	if _by() {
		if "`by'" != "" {
			di as err /*
			*/ "option by() may not be combined with by prefix"
			exit 190
		}
		local by "`_byvars'"
	}

	local nopts : word count `forward' `backward' `groupwise'

	if `nopts' != 1 {
		di as err "must specify one interpolation method"
		exit 198
	}

	confirm new var `generate'

	quietly {
		// anything to do?
		marksample touse, novarlist
		replace `touse' = 0 if missing(`x')
		count if `touse'
		if r(N) == 0 error 2000

		count if missing(`stry') & `touse'
		if r(N) == 0 {
			noisily di as txt "{p}nothing to do; " ///
			"no missing `stry' that can be interpolated{p_end}"
			exit 0
		}

		// uniqueness checks
		tempvar diff z
		// if we have different strings say "A" "B" for identical `x'
		// then we don't know which to use

		bysort `touse' `by' `x' (`stry') : ///
			gen byte `diff' = !missing(`stry') & (`stry' != `stry'[_N])
		bysort `touse' `by' (`diff'): replace `diff' = `diff'[_N]
		replace `touse' = 0 if `diff'

		count if `touse'
		if r(N) == 0 {
			local msg "{p}no interpolation: different non-missing string values"
			if "`by'" != "" {
				di as err "`msg' for same `by' and `x'{p_end}"
			}
			else di as err "`msg' for same `x'{p_end}"
			exit 498
		}

		// forward or backward
		if "`forward'`backward'" != "" {
			clonevar `z' = `stry'

			if "`forward'" != "" {
				bysort `touse' `by' (`x') : ///
				replace `z' = `z'[_n-1] if `touse' & missing(`z' )
			}
			else {
				tempvar negx
				gen double `negx' = -`x'
				bysort `touse' `by' (`negx'): ///
				replace `z' = `z'[_n-1] if `touse' & missing(`z')
			}
		}

		if "`groupwise'" != "" {
			// check for uniqueness again
			// if we have different strings say "A" "B" in any group
			// then we don't know which to use
			bysort `touse' `by' (`stry') : ///
				replace `diff' = !missing(`stry') & (`stry' != `stry'[_N])
			bysort `touse' `by' (`diff') : replace `touse' = 0 if `diff'[_N]
			count if `touse'

			if r(N) == 0 {
				local msg1 "{p}no interpolation: different non-missing string values"
				if "`by'" != "" local msg2 " for same `by'"
				di as err "`msg1'`msg2'{p_end}"
				exit 498
			}

			clonevar `z' = `stry'
			bysort `touse' `by' (`stry') : ///
				replace `z' = `z'[_N] if missing(`z') & `touse'
		}

		rename `z' `generate'
		compress `generate'
		count if missing(`generate')
	}

	if r(N) > 0 {
		if r(N) != 1 local pl "s"
		di as txt "(" r(N) `" missing value`pl' generated)"'
	}
end