*! version 1.0
* By Kerry Du, 29 Oct 2019
capture program drop sbmeff
program define sbmeff, rclass
    version 16

    if strpos(`"`0'"',":")==0{  // Tone(2001) SBM without undesriable outputs
	   sbmeffnu `0'
	   exit

	}

    gettoken word 0 : 0, parse(" =:,")
    while `"`word'"' != ":" & `"`word'"' != "=" {
        if `"`word'"' == "," | `"`word'"'=="" {
                error 198
        }
		local invars `invars' `word'
		gettoken word 0 : 0, parse("=:,")
    }
    unab invars : `invars'

	gettoken word 0 : 0, parse(" =:,")
    while `"`word'"' != ":" & `"`word'"' != "=" {
        if `"`word'"' == "," | `"`word'"'=="" {
                error 198
        }
		local gopvars `gopvars' `word'
		gettoken word 0 : 0, parse(" =:,")
    }
    unab gopvars : `gopvars'


    syntax varlist [if] [in], dmu(varname) [Time(varname) SEQuential  VRS  SAVing(string) maxiter(numlist integer >0 max=1) tol(numlist max=1)]

	if "`maxiter'"==""{
		local maxiter=-1
	}
	if "`tol'"==""{
		local tol=-1
	}

	if "`sequential'"!=""{
		if "`time'"==""{
		   disp as error "For sequential SBM model, time() should be specified."
		   error 498
		}
		else{
		   local techflag "<="
		}

	}

	preserve
	marksample touse
	markout `touse' `invars' `gopvars'

	local bopvars `varlist'

	local invars: list uniq invars
	local gopvars: list uniq gopvars
	local bopvars: list uniq bopvars

	confirm numeric var `invars' `gopvars' `bopvars'

	local comvars: list invars & gopvars
	if !(`"`comvars'"'==""){
		disp as error "`comvars' should not be specified as input and desriable output simultaneously."
		error 498
	}

	local comvars: list invars & bopvars
	if !(`"`comvars'"'==""){
		disp as error "`comvars' should not be specified as input and undesriable output simultaneously."
		error 498
	}

	local comvars: list gopvars & bopvars
	if !(`"`comvars'"'==""){
		disp as error "`comvars' should not be specified as desriable and undesriable outputs simultaneously."
		error 498
	}


	local ninp: word count `invars'
    local ngo: word count `gopvars'
    local nbo: word count `bopvars'

	local rstype=1
	if "`vrs'"!=""{
	   local rstype=0
	}



	qui keep if `touse'
	qui keep   `invars' `gopvars' `bopvars' `dmu' `time'
	qui gen _Row=_n
	label var _Row "Row #"
	qui gen double TE=.
	label var TE "Technical Efficiency"

	foreach v in `invars' `gopvars' `bopvars'{
	   qui gen double S_`v'=.
	   label var S_`v' `"Slack:`v'"'
	   local slackvars `slackvars' S_`v'

	}


    tempvar tvar dmu2


	if  `"`time'"'!="" {
	    qui egen `tvar'=group(`time')
		qui egen `dmu2'=group(`dmu')
	}
	else{
	    qui gen `tvar'=1
		qui gen `dmu2'=_n
	}

	sort `dmu2' `tvar' _Row
	/*
    if "`super'"!=""{
	  local sup "sup"
	}
	*/
	mata: sbmu(`"`invars'"',`"`gopvars'"',`"`bopvars'"',"`dmu2'","`tvar'",`rstype',"`techflag'","TE",`"`slackvars'"',`maxiter',`tol')



	order _Row `dmu' `time' TE `slackvars'
	keep _Row `dmu' `time' TE `slackvars'

	disp _n(2) " SBM Efficiency Results:"
	disp "    (_Row: Row # in the original data; TE: Efficiency Score;  S_X: Slack of X)"
	//disp "      S_X : Slack of X"
	list _Row `dmu' `time' TE `slackvars', sep(0)

	//disp _n
	if `"`saving'"'!=""{
	  save `saving'
	  gettoken filenames saving:saving, parse(",")
	  local filenames `filenames'.dta
	  disp _n `"Estimated Results are saved in `filenames'."'
	}
	//tempname resmat
	//mkmat _Row `dmu' `time' TE `slackvars', mat(`resmat')
	//matrix list `resmat', noblank nohalf  noheader f(%9.6g)
	//return mat results=`resmat'
	return local file `filenames'
	restore

	end

//////////////////////////////////////////////////////////////
capture program drop sbmeffnu
program define sbmeffnu, rclass
    version 16

    // disp "`0'"
    // get and check invarnames
	gettoken word 0 : 0, parse("=,")
    while ~("`word'" == ":" | "`word'" == "=") {
        if "`word'" == "," | "`word'" == "" {
                error 198
        }
        local invars `invars' `word'
        gettoken word 0 : 0, parse("=,")
        //disp "`word'"
    }
    unab invars : `invars'

    syntax varlist [if] [in], dmu(varname) [Time(varname) SEQuential VRS SAVing(string) maxiter(numlist integer >0 max=1) tol(numlist max=1)]

	if "`maxiter'"==""{
		local maxiter=-1
	}
	if "`tol'"==""{
		local tol=-1
	}
	if "`sequential'"!=""{
		if "`time'"==""{
		   disp as error "For sequential SBM model, time() should be specified."
		   error 498
		}
		else{
		   local techflag "<="
		}

	}

	preserve
	marksample touse
	markout `touse' `invars'
    //count if `touse'
	local opvars `varlist'

	local invars: list uniq invars
	local opvars: list uniq opvars


	confirm numeric var `invars' `opvars'

	local comvars: list invars & opvars
	if !(`"`comvars'"'==""){
		disp as error "`comvars' should not be specified as input and output simultaneously."
		error 498
	}


	local rstype=1
	if "`vrs'"!=""{
	   local rstype=0
	}


	qui keep if `touse'
	qui keep   `invars' `opvars' `dmu' `time'
	qui gen _Row=_n
	label var _Row "Row #"

	qui gen double TE=.
	label var TE "Technical Efficiency"

	foreach v in `invars' `opvars'{
	   qui gen double S_`v'=.
	   label var S_`v' `"Slack:`v'"'
	   local slackvars `slackvars' S_`v'

	}


    tempvar tvar dmu2


	if  `"`time'"'!="" {
	    qui egen `tvar'=group(`time')
		qui egen `dmu2'=group(`dmu')
	}
	else{
	    qui gen `tvar'=1
		qui gen `dmu2'=_n
	}

	sort `dmu2' `tvar' _Row
	/*
    if "`super'"!=""{
	  local sup "sup"
	}
	*/
	mata: sbm(`"`invars'"',`"`opvars'"',"`dmu2'","`tvar'",`rstype',"`techflag'","TE",`"`slackvars'"', `maxiter',`tol')



	order _Row `dmu' `time' TE `slackvars'
	keep _Row `dmu' `time' TE `slackvars'

	disp _n(2) " SBM Efficiency Results:"
    disp "    (_Row: Row # in the original data; TE: Efficiency Score;  S_X: Slack of X)"
	//disp "      S_X : Slack of X"
	list _Row `dmu' `time' TE `slackvars', sep(0)

	//disp _n
	if `"`saving'"'!=""{
	  save `saving'
	  gettoken filenames saving:saving, parse(",")
	  local filenames `filenames'.dta
	  disp _n `"Estimated Results are saved in `filenames'."'
	}
	//tempname resmat
	//mkmat _Row `dmu' `time' TE `slackvars', mat(`resmat')
	//matrix list `resmat', noblank nohalf  noheader f(%9.6g)
	//return mat results=`resmat'
	return local file `filenames'
	restore

	end


/*
make sbmeff, replace toc pkg title( Slacks-based Measure of Efficiency in Stata) ///
             version(1.0) author(Kerry Du) affiliation(Xiamen University) ///
			 email(kerrydu@xmu.edu.cn) install("sbmeff.ado;sbmeff.sthlp;lsbmeff.mlib")
*/