*! version 3.1.5  12oct2024 by alexis.dinno@pdx.edu
*! perform two one-sided tests for stochastic equivalence in paired data

* Syntax:  tostmcc varname [if exp] [in range] [fweight exp], [
*          eqvtype(type) eqvlevel(#) uppereqvlevel(#) yates edwards alpha(#)
*          relevance]

program define tostmcc, rclass byable(recall)

  syntax varlist(min=2 max=2) [if] [in] [fw] [, EQVType(string) /*
  */     EQVLevel(real 1) UPPEReqvlevel(real 0) YAtes EDwards Alpha(real 0.05) /*
  */     RELevance]

  if int(_caller())<8 {
    di in r "tostmcc- does not support this version of Stata." _newline
    di as txt "All requests for specific version support are welcome and will be considered."
    exit
  }

  if int(_caller())<14 {
    version 8.0, missing
    }
   else {
    version 14.0, missing
    }

* Validate eqvtype
  if lower("`eqvtype'") == "" {
    local eqvtype = "delta"
    }

  if !(lower("`eqvtype'") == "delta" | lower("`eqvtype'") == "epsilon") {
    noisily: di as err "option eqvtype() must be one of: delta, or epsilon"
    exit 198
    }

* Validate eqvlevel
  if (lower("`eqvtype'") == "delta") & (`eqvlevel' == 1 & `uppereqvlevel'==0) {
    local eqvlevel = 0.1
    }

  if (lower("`eqvtype'") == "epsilon") & (`eqvlevel' == 1 & `uppereqvlevel'==0) {
    local eqvlevel = 2
    }

  if (lower("`eqvtype'") == "delta" || lower("`eqvtype'") == "epsilon") & (`eqvlevel' <= 0 & `uppereqvlevel' != abs(`eqvlevel')) {
    noisily: di as err "option eqvlevel() incorrectly specified" _newline "the tolerance must be a positive real value"
    exit 198
    }

  if lower("`eqvtype'") == "delta" & (`eqvlevel' >= 1 | `uppereqvlevel' >= 1) {
    noisily: di as err "option eqvlevel() incorrectly specified" _newline "you are likely to find all proportions equivalent within an interval of plus or minus 1 or more"
    exit 198
    }

* Validate uppereqvlevel
  if (`uppereqvlevel'<0) {
    noisily: di as err "option uppereqvlevel() must be a positive real value"
    exit 198
    }

  if (`uppereqvlevel'==0 | `uppereqvlevel' == abs(`eqvlevel')) {
    local upper = abs(`eqvlevel')
    local lower = abs(`eqvlevel')
    }

  if (`uppereqvlevel'>0) {
    local upper = abs(`uppereqvlevel')
    local lower = abs(`eqvlevel')
    }

* Validate continuity correction option
  if ("`yates'" != "" & "`edwards'" != "") {
    noisily di as err "continuity correction options must be either yates or edwards, but not both"
    exit 198
    }

* Validate alpha
  if (`alpha' < 0 | `alpha' > 1) {
    noisily: di as err "option alpha() must be between 0 and 1 inclusive"
    exit 198
    }

  tokenize `varlist'
  local excas `1'
  local excon `2'

  marksample use
  tempvar WGT one
  quietly {
    if "`weight'"!="" {
      gen double `WGT' `exp' if `use'
      local w "[fweight=`WGT']"
    }
  }

  quietly {
    gen byte `one'=1
    safesum `one' `w' if `excas' & `excon' & `use'
    local a=r(sum)
    safesum `one' `w' if `excas' & `excon'==0 & `use'
    local b=r(sum)
    safesum `one' `w' if `excas'==0 & `excon' & `use'
    local c=r(sum)
    safesum `one' `w' if `excas'==0 & `excon'==0 & `use'
    local d=r(sum)
  }
  tostmcci `a' `b' `c' `d', eqvtype(`eqvtype') eqvlevel(`eqvlevel') uppereqvlevel(`upper') `yates' `edwards' alpha(`alpha') `relevance'
  ret add   /* return the r() values from tostmcci call */
  end