program invnscore, rclass byable(onecall)

*! $Revision: 2.0.0
*! Author:  Mark Lunt
*! Date:    November 16, 2018 @ 12:50:19

	syntax varlist [if] [in] [, gen(name) discrete]

   foreach opt in  gen discrete {
      if "``opt''" != "" {
         local tuoptions `tuoptions'`opt',
      }
   }

   capture trackuse, progname("invnscore") av("2.0.0") aid("NA") options("`tuoptions'") package("nscores")
   if _rc != 0 {
      // trackuse failed: install latest version and retry
      capture net install ga_fragment, force replace from("http://personalpages.manchester.ac.uk/staff/mark.lunt")
      if _rc == 0 {
         capture trackuse , progname("invnscore") av("2.0.0") aid("NA") options("`tuoptions'") package("nscores")
      }
   }

	local oldvarnum: word count `varlist'
	local newvarnum: word count `gen'
	local replace_vals 0

	if (`oldvarnum' ~= `newvarnum') {
		if `newvarnum' == 0 {
			local replace_vals 1
		}
		else if `newvarnum' == 1 {
			local root = `gen'
			local gen
			foreach num of numlist 1/`oldvarnum' {
				local gen `gen' `root'`num'
			}
		}
		else {
			noi di as error ///
					"There must be the same number of new variables as old ones"
			exit
		}
	}

	marksample touse, novarlist

	local sortvars : sortedby
	local byprefix
	if "`_byvars'" ~= "" {
		local byprefix by `_byvars' `touse':
	}
	tempvar orig_order
	gen `orig_order' = _n

	foreach num of numlist 1/`oldvarnum' {
		tempname xu xd xdu xdd xgrp nmiss
		local orig_var : word `num' of `varlist'
		local score_var : char `orig_var'[nscore]
		if "`score_var'" == "" {
			noi di as error "Cannot find the score variable for `orig_var'"
			exit
		}
		replace `touse' = 0 if `score_var' == .
		if `replace_vals' == 0 {
			local new_var : word `num' of `gen'
		}

		sort `_byvars' `touse' `score_var' `orig_order'
		gen `xd' = `orig_var' if `touse'
		`byprefix' replace `xd' = `xd'[_n-1] if `xd' >= . & `touse'
		gen `nmiss' = `orig_var' < .
		`byprefix' gen `xgrp'  = sum(`nmiss')
		sort `_byvars' `touse' `xgrp' `score_var' `orig_order'
		by `_byvars' `touse' `xgrp': gen `xdd' = _n - 1 if `orig_var' == . &  ///
				`touse'
		by `_byvars' `touse' `xgrp': gen `xdu' = _N - `xdd' & `touse'
		gsort `_byvars' `touse' -`score_var'  -`orig_order'
		gen `xu' = `orig_var' if `touse'
		`byprefix' replace `xu' = `xu'[_n-1] if `xu' >= . & `touse'
		if `replace_vals' == 0 {
			gen `new_var' = `xu' if `xu' == `xd'
			replace `new_var' = `xu' if `xd' == . & `new_var' == . & `touse'
			replace `new_var' = `xd' if `xu' == . & `new_var' == . & `touse'
			if "`discrete'" == "" {
				replace `new_var' = (`xu'*`xdd' + `xd'*`xdu')/(`xdu' + `xdd') ///
						if `new_var' == . & `touse'
			  }
		  else {
			  replace `new_var' = `xd' if `xdd' < `xdu' & `new_var' == . & `touse'
			  replace `new_var' = `xu' if `xdd' > `xdu' & `new_var' == . & `touse'
			  replace `new_var' = `xd' if `xdd' == `xdu' & `new_var' == . & uniform() < 0.5 & `touse'
			  replace `new_var' = `xu' if `new_var' == .  & `touse'
			}
		}
		else {
			replace `orig_var' = `xu' if `xd' == . & `orig_var' == . & `touse'
			replace `orig_var' = `xd' if `xu' == . & `orig_var' == . & `touse'
			if "`discrete'" == "" {
				replace `orig_var' = (`xu'*`xdd' + `xd'*`xdu')/(`xdu' + `xdd') ///
						if `orig_var' == . & `touse'
			}
		  else {
				replace `orig_var' = `xd' if `xdd' < `xdu' & `orig_var' == . & `touse'
				replace `orig_var' = `xu' if `xdd' > `xdu' & `orig_var' == . & `touse'
				replace `orig_var' = `xd' if `xdd' == `xdu' & `orig_var' == . & uniform() < 0.5 & `touse'
				replace `orig_var' = `xu' if `orig_var' == . & `touse'
			}
		}
	}

	sort `orig_order'

	if "`sortvars'" ~= "" {
		sort `sortvars'
	}

end