*! version 1.0.0  23oct1997  statalist
program define _ttest
        version 5.0
/*
    This command consists of a group of helper commands for ttest and sdtest.

    _ttest one
    _ttest two
    _ttest by
    _ttest check
    _ttest header
    _ttest table
    _ttest center
*/
        local cmd "`1'"
        macro shift

        if "`cmd'"=="center" {
                _center "`1'" "`2'" "`3'"
        }
        else _`cmd' `*'
end

program define _one
/*
   Computes #obs, mean, sd of a variable for a one-sample test.
   Then calls -ttesti- or -sdtesti-.

   Syntax:

           _one {ttesti|sdtesti} level touse xvar Ho

   The first group is defined to be the lesser value of the -by- variable.
*/
        local cmd   "`1'"
        local level "`2'"
        local touse "`3'"
        local xvar  "`4'"
        local Ho    "`5'"

        quietly summarize `xvar' if `touse'
        local n = _result(1)
        local m = _result(3)
        local s = sqrt(_result(4))

        `cmd' `n' `m' `s' `Ho', xname(`xvar') level(`level')
end

program define _two
/*
   Computes #obs, mean, sd of variable1 and variable2 for a two-sample test.
   Then calls -ttesti- or -sdtesti-.

   Syntax:

           _two {ttesti|sdtesti} level touse xvar1 xvar2 [options]
*/
        local cmd   "`1'"
        local level "`2'"
        local touse "`3'"
        local xvar1 "`4'"
        local xvar2 "`5'"
        macro shift 5
        local options "`*'"

        quietly summarize `xvar1' if `touse'
        local n1 = _result(1)
        local m1 = _result(3)
        local s1 = sqrt(_result(4))

        unabbrev `xvar2'
        local xvar2 "$S_1"
        quietly summarize `xvar2' if `touse'
        local n2 = _result(1)
        local m2 = _result(3)
        local s2 = sqrt(_result(4))

        `cmd' `n1' `m1' `s1' `n2' `m2' `s2', xname(`xvar1') yname(`xvar2') /*
        */      level(`level') `options'
end

program define _by
/*
   Computes #obs, mean, sd of a variable for two groups defined by a -by-
   variable.  Then calls -ttesti- or -sdtesti-.

   Syntax:

           _by {ttesti|sdtesti} level touse xvar by [options]

   The first group is defined to be the lesser value of the -by- variable.
*/
        local cmd   "`1'"
        local level "`2'"
        local touse "`3'"
        local xvar  "`4'"
        local by    "`5'"
        macro shift 5
        local options "`*'"

/* Markout `xvar'. */

        markout `touse' `xvar'

/* If `by' is a string variable, create a numeric one. */

        capture confirm string variable `by'
        if _rc == 0 {
                ByString `n1' `m1' `s1' `n2' `m2' `s2' `touse' `xvar' `by'
                exit
        }

/* Here only if `by' is numeric. */

        markout `touse' `by'

        tempname val1 val2

        quietly {
                summarize `by' if `touse'
                if _result(1) == 0 { noisily error 2000 }

                scalar `val1' = _result(5)
                scalar `val2' = _result(6)

        /* Check that there are exactly 2 groups. */

                if `val1' == `val2' {
                        di in red "1 group found, 2 required"
                        exit 420
                }

                count if `by'!=`val1' & `by'!=`val2' & `touse'
                if _result(1) != 0 {
                        di in red "more than 2 groups found, only 2 allowed"
                        exit 420
                }

        /* Get #obs, mean, and sd for first group. */

                summarize `xvar' if `by'==`val1' & `touse'
                local n1 = _result(1)
                local m1 = _result(3)
                local s1 = sqrt(_result(4))

        /* Get #obs, mean, and sd for second group. */

                summarize `xvar' if `by'==`val2' & `touse'
                local n2 = _result(1)
                local m2 = _result(3)
                local s2 = sqrt(_result(4))

        /* Get group labels. */

                local lab1 = `val1'
                local lab2 = `val2'

                local bylab : value label `by'

                if "`bylab'"!="" {
                        local lab1 : label `bylab' `lab1'
                        if "`lab1'"=="" {
                                local lab1 = `val1'
                        }
                        local lab2 : label `bylab' `lab2'
                        if "`lab2'"=="" {
                                local lab2 = `val2'
                        }
                }

                local lab1 = substr("`lab1'",1,8)
                local lab2 = substr("`lab2'",1,8)
        }

        `cmd' `n1' `m1' `s1' `n2' `m2' `s2', xname(`lab1') yname(`lab2') /*
        */ level(`level') `options'
end

program define ByString
        local n1    "`1'"
        local m1    "`2'"
        local s1    "`3'"
        local n2    "`4'"
        local m2    "`5'"
        local s2    "`6'"
        local touse "`7'"
        local xvar  "`8'"
        local by    "`9'"

/* Markout. */

        markout `touse' `by', strok

        tempvar obs

        quietly {

        /* Get `by' groups without sorting (which is unnecessarily slow!). */

                gen long `obs' if `touse'
                summarize `obs', meanonly
                if _result(1) = 0 { noisily error 2000 }

                local val1 = `by'[_result(5)]

                replace `obs' = . if `by'=="`val1'"
                summarize `obs', meanonly
                if _result(1) = 0 {
                        di in red "1 group found, 2 required"
                        exit 420
                }

                local val2 = `by'[_result(5)]

                replace `obs' = . if `by'=="`val2'"
                summarize `obs', meanonly
                if _result(1) != 0 {
                        di in red "more than 2 groups found, only 2 allowed"
                        exit 420
                }

        /* Make it so that "`val1'" < "`val2'". */

                if "`val1'" > "`val2'" {
                        local temp "`val1'"
                        local val1 "`val2'"
                        local val2 "`temp'"
                }

        /* Get #obs, mean, and sd for first group. */

                summarize `xvar' if `by'=="`val1'" & `touse'
                scalar `n1' = _result(1)
                scalar `m1' = _result(3)
                scalar `s1' = sqrt(_result(4))

        /* Get #obs, mean, and sd for second group. */

                summarize `xvar' if `by'=="`val2'" & `touse'
                scalar `n2' = _result(1)
                scalar `m2' = _result(3)
                scalar `s2' = sqrt(_result(4))

        /* Put group labels in global macros. */

                global S_1 = substr("`val1'",1,8)
                global S_2 = substr("`val2'",1,8)
end

program define _check
/*
   This program checks sense of #obs, mean, and standard deviation for
   -ttesti- and -sdtesti-.

   Syntax:

           _check {ttest|sdtest} {one|first|second} #1 #2 #3 [#4]

   where one, first, or second refers to, respectively, a one-sample test,
   first sample of a two-sample test, or second sample of a two-sample test,
   and #1 = #obs, #2 = mean, #3 = standard deviation, and #4 = hypothesized
   value.
*/
        local cmd    "`1'"  /* ttest or sdtest
        */
        local sample "`2'"  /* one, first, or second
        */
        local n      "`3'"  /* #obs
        */
        local m      "`4'"  /* mean
        */
        local s      "`5'"  /* standard deviation
        */
        local h      "`6'"  /* hypothesized value (only if `sample' is "one")
        */

/* Check `n' number of observations. */

        if "`n'"=="." {
                if "`sample'"!="one" {
                        di in red "number of observations of `nsamp' sample" /*
                        */ " is missing"
                }
                else di in red "number of observations is missing"
                exit 416
        }

        confirm integer number `n'

        if `n' < 0 {
                if "`sample'"!="one" {
                        di in red "number of observations in `nsamp' sample" /*
                        */ " is negative"
                }
                else di in red "number of observations is negative"
                exit 411
        }

        if `n' == 0 {
                if "`sample'"!="one" {
                        di in red "`nsamp' sample has no observations"
                        exit 2000
                }
                error 2000
        }

/* Check `m' mean. */

        if "`m'"=="." {
                if "`cmd'"=="ttest" {
                        if "`sample'"!="one" {
                                di in red "mean of `nsamp' sample is missing"
                        }
                        else di in red "mean is missing"
                        exit 416
                }
        }
        else confirm number `m'

/* Check `s' standard deviation. */

        if "`s'"=="." {
                if `n' != 1 {
                        if "`sample'"!="one" {
                                di in red "standard deviation of `nsamp' " /*
                                */ "sample is missing"
                        }
                        else di in red "standard deviation is missing"
                        exit 416
                }
        }
        else {
                confirm number `s'

                if `s' < 0 {
                        if "`sample'"!="one" {
                                di in red "`nsamp' sample has a negative " /*
                                */ "standard deviation"
                        }
                        else di in red "standard deviation is negative"
                        exit 411
                }

                if `n' == 1 & `s' != 0 {
                        if "`sample'"!="one" {
                                di in red "`nsamp' sample has only one " /*
                                */ "observation, but positive standard " /*
                                */ "deviation"

                        }
                        else di in red "only one observation, but positive " /*
                        */ "standard deviation"
                        exit 499
                }
        }

/* Check next number if `sample' is "one". */

        if "`sample'"!="one" { exit }

        if "`h'"=="." {
                di red "hypothesized value is missing"
                exit 416
        }

        confirm number `h'

        if "`cmd'"=="sdtest" & `h' < 0 {
                di in red "hypothesized standard deviation is negative"
                exit 411
        }
end

program define _header
        local level "`1'"
        local xname "`2'"

        if "`xname'"!="" {
                capture confirm variable `xname'
                if _rc == 0 {
                        local col1 "Variable"
                }
                else    local col1 "   Group"
        }

        di _n in gr _dup(78) "-" _n "`col1'" _col(10) "|" _col(16) "Obs" /*
        */ _col(27) "Mean" _col(35) "Std. Err." _col(47) "Std. Dev."     /*
        */ _col(59) "[`level'% Conf. Interval]" _n _dup(9) "-" "+" _dup(68) "-"
end
/*
    5   10   15   20   25   30   35   40   45   50   55   60   65   70   75
    80
++++|++++|++++|++++|++++|++++|++++|++++|++++|++++|++++|++++|++++|++++|++++|++++
|
Variable |     Obs        Mean    Std. Err.   Std. Dev.   [95% Conf. Interval]
- ---------+--------------------------------------------------------------------
     mpg | 1234567   123456789   123456789   123456789   123456789   123456789
*/

program define _table
/*
    This program displays table with information about mean, etc.

    Syntax:
            _table level name #obs mean sd [se] [df]

    Note: expressions without blanks are OK.
*/
        local level  "`1'"
        local name   "`2'"
        local n      "(`3')"
        local mean   "(`4')"
        local sd     "(`5')"
        local se     "`6'"
        local df     "`7'"

        if `n' == 1 | `n' == . {
                local sd = .
                local se = .
        }

        if "`se'"=="" {
                local se = `sd'/sqrt(`n')
        }

        if "`df'"=="" {
                local df = `n' - 1
        }

        local q = invt(`df',`level'/100)

        local begin = 9 - length("`name'")

        #delimit ;
        di in gr _col(`begin') "`name'"
                 _col(10) "|" in ye
                 _col(12) %7.0f `n'
                 _col(22) %9.0g `mean'
                 _col(34) %9.0g `se'
                 _col(46) %9.0g `sd'
                 _col(58) %9.0g `mean'-`q'*(`se')
                 _col(70) %9.0g `mean'+`q'*(`se') ;
        #delimit cr
end

program define _center
/*
   Syntax:

   _center "string"                        [displays centered "string"]

   _center "string1" "string2" "string3"   [displays centered in 3 columns]

   @ character in string toggles color from green to yellow (or from yellow
   to green); green is the default and initial color.

   Example: "green @yellow@ green @yellow@"

*/
        local left  12  /* columns centered about these values */
        local mid   39
        local right 66

        if "`2'"=="" {
                Display "`1'" `mid' 0
                di /* newline */
                exit
        }

        Display "`1'" `left'  0
        Display "`2'" `mid'   $S_1
        Display "`3'" `right' $S_1
        di /* newline */
end

program define Display
        local string "`1'"
        local center "`2'" /* value to center about */
        local last   "`3'" /* column of last character printed */

        Length "`string'"
        local length $S_1

        local skip = max((`last'!=0), `center' - int(`length'/2) - 1 - `last')

        di _skip(`skip') _c /* skip spaces */

        Print "`string'" /* print out string */

        global S_1 = `last'+`skip'+`length' /* last character printed */
end

program define Length
        local length 0
        local string "`1'"
        while "`string'"!="" {
                local i = index("`string'","@")
                if `i' == 0 {
                        local length = `length' + length("`string'")
                        local string
                }
                else {
                        local length = `length' + `i' - 1
                        Substr "`string'" `i'+1 .
                        local string "$S_1"
                }
        }
        global S_1 `length'
end

program define Print
        local string "`1'"
        local color "gr"
        while "`string'"!="" {
                local i = index("`string'","@")
                if `i' == 0 {
                        di in `color' "`string'" _c
                        local string
                }
                else {
                        Substr "`string'" 1 `i'-1
                        di in `color' "$S_1" _c

                        if "`color'"=="gr" { local color ye }
                        else local color gr

                        Substr "`string'" `i'+1 .
                        local string "$S_1"
                }
        }
end

program define Substr
        local string "`1'"
        local a = `2'
        local b = `3'

        if `b' == . { local b = length("`string'") - `a' + 1 }

        local sub = substr("`string'",`a',`b')

        local lsub = length("`sub'")

        if `lsub' < `b' {
                local nblank = `b' - `lsub'
                local blanks : di _dup(`nblank') " "
                local sub "`blanks'`sub'"
        }

        global S_1 "`sub'"
end
exit