/*
*! version 1.2.0 # Ian White # 3jul2015
    prints warning if MNAR has been set
version 1.1 # Ian White # 8jun2015
28may2015
    improved output table column widths
<26may2015
    checks for evidence in the indirect studies; revised help file explains why this isn't the same as checking for identification
11may2015
    new tau option
version 1.0 # Ian White # 9Sep2014
version 0.6 # 6jun2014
    works for standard format
    fixed coding error for inco parameter
    drops metavars and records new ones
    reports direct and indirect estimates as well as difference
    rclass; stores output as matrices
4oct2013
    istrt.ado stored here
*/

prog def network_sidesplit, rclass

// LOAD NETWORK CHARS
if mi("`_dta[network_allthings]'") {
	di as error "Data are not in network format"
	exit 459
}
foreach thing in `_dta[network_allthings]' {
    local `thing' : char _dta[network_`thing']
}
if "`format'"=="pairs" {
    di as error "Sorry, network sidesplit currently only works for augmented or standard format"
    exit 498
}

// PARSE
syntax [anything] [if] [in], ///
    [double cformat(string) pformat(string) /// undocumented
    tau show * /// documented
    ]
if mi("`cformat'") local cformat `c(cformat)'
if mi("`cformat'") local cformat %9.0g
if mi("`pformat'") local pformat `c(pformat)'
if mi("`pformat'") local pformat %5.3f

if !mi("`MNAR'") di as error "Warning: data were computed under MNAR using options: " as error "`MNAR'"

marksample touse

// IF CALL IS -NETWORK SIDESPLIT ALL- THEN REPEATEDLY RE-CALL THIS PROGRAM
if "`anything'"=="all" {

    * Extra parsing
    if !mi("`show'") {
        di as error "network sidesplit all: show option ignored"
        local show
    }

    * Create "has" indicators
    foreach trt in `ref' `trtlistnoref' {
        tempvar has`trt'
        qui gen `has`trt'' = strpos(" "+`design'+" "," `trt' ")>0 if `touse'
    }

    * Choose output column widths
    local place 1
    forvalues i=1/8 {
        if `i'==1 local width 8
        else if `i'<=7 local width = max(10, length(string(-1/3,"`cformat'"))+2)
        else local width = max(5, length(string(-1/3,"`pformat'"))+2)
        local place = `place'+`width'
        local col`i' _col(`place')
    }

    * Print output column header
    di as text _new "Side" `col1' "Direct" `col3' "Indirect" `col5' "Difference" _c
    if !mi("`tau'") di `col8' "tau"_c
    di
    di as text `col1' "Coef." `col2' "Std. Err." `col3' "Coef." `col4' "Std. Err." ///
       `col5' "Coef." `col6' "Std. Err." `col7' "P>|z|"

    * Loop over pairs of treatments
    tempname b V ball Vall
    local no_outside_evidence 0
    foreach side1 in `ref' `trtlistnoref' {
        foreach side2 in `ref' `trtlistnoref' {
            if "`side1'" == "`side2'" continue
            if mi("`double'") & "`side1'" > "`side2'" continue
            qui count if `has`side1'' & `has`side2'' & `touse'
            if r(N)==0 continue
            * di as text _n "Splitting `side1' - `side2'" _c
            cap network sidesplit `side1' `side2' `if' `in', nof9 `options'
            if inlist(_rc,1,198) error _rc
            if !r(outside_evidence) local no_outside_evidence 1
            if !_rc {
                mat `b' = r(b)
                mat `V' = r(V)
            }
            else {
                mat `b'=J(1,3,.)
                mat `V'=J(3,3,.)
            }
            * output results
            di as text "`side1' `side2'" _c
            if !r(outside_evidence) di " *" _c
            di as result ///
                `col1' `cformat' `b'[1,1] `col2' `cformat' sqrt(`V'[1,1]) ///
                `col3' `cformat' `b'[1,2] `col4' `cformat' sqrt(`V'[2,2]) ///
                `col5' `cformat' `b'[1,3] `col6' `cformat' sqrt(`V'[3,3]) ///
                `col7' `pformat' chi2tail(1,(`b'[1,3])^2/`V'[3,3]) _c
            if !mi("`tau'") {
                local tauvalue .
                cap local tauvalue = abs([tau]_cons)
                di `col8' `cformat' `tauvalue' _c
            }
            di
            * store results
            mat rownames `b' = "y"
            mat roweq `b' = "`side1'-`side2'"
            mat roweq `V' = "`side1'-`side2'"
            mat `ball' = (nullmat(`ball') \ `b')
            mat `Vall' = (nullmat(`Vall') \ `V')

        }
    }

    * Finish
    if `no_outside_evidence' di as text _new "* Warning: all the evidence about these contrasts comes from the trials which directly compare them." _new "See {help network_sidesplit##no_indirect_evidence:help file} for more information."
    return matrix b = `ball'
    return matrix V = `Vall'
    exit
} // END OF CALL -NETWORK SIDESPLIT ALL-

// CALL IS -NETWORK SIDESPLIT TRT1 TRT2-
syntax [anything] [if] [in], [show noSYmmetric tau /// documented
    Level(cilevel) nof9 bscov(passthru) /// trivial but undocumented
    * /// mvmeta options
    ]
tokenize "`anything'"
local side1 `1' // trt at start of split edge
local side2 `2' // trt at end of split edge
local error 0
if mi("`2'") | !mi("`3'") {
    di as error "Syntax: network sidesplit [all|trt1 trt2]"
    exit 198
}
istrt `side1'
istrt `side2'

if mi("`bscov'") local bscov bscov(exch 0.5)

// SET UP
preserve // -restore, not- later
cap drop `metavars' // drop previous derived variables
local metavars
tempvar has
foreach trt in `ref' `trtlistnoref' { // Create "has" indicators
    qui gen `has'`trt' = strpos(" "+`design'+" "," `trt' ")>0 if `touse'
    local droplist `droplist' `has'`trt'
}

// IS THERE EVIDENCE OUTSIDE THE DIRECT TRIALS?
/* ("Direct trial": one containing side1 and side2.)
With two-arm trials, this is the same as asking if there is indirect evidence.
With multi-arm trials, the sidesplit model can estimate the indirect effect
using the multi-arm direct trials (but not of course using their side1-side2 comparisons).
*/
network_components if !(`has'`side1' & `has'`side2')
local outside_evidence = r(ncomponents)==1
if  !`outside_evidence' di as error "Warning: there is no evidence about the `side1'-`side2' contrast outside trials containing `side1' and `side2'"

// FORM SIDESPLIT MODEL
if "`format'"=="augmented" {
    local firsteq 1
    qui gen `trtdiff'one=1 if `touse'
    qui gen `trtdiff'zero=0 if `touse'
    local metavars `metavars' `trtdiff'one `trtdiff'zero
    foreach trt in `trtlistnoref' { // build equation for outcome `trt'
        * consistency model
        local eq`trt' `y'_`trt':
        foreach trt2 in `trtlistnoref' { // need one term for each treatment
            if `firsteq' {
                if "`trt2'"=="`trt'" qui gen  `trtdiff'`trt2'=1 if `touse'
                else                 qui gen  `trtdiff'`trt2'=0 if `touse'
                local metavars `metavars' `trtdiff'`trt2'
                local eq`trt' `eq`trt'' `trtdiff'`trt2'
                if "`trt2'"=="`side1'" local indirect `indirect' - [`y'_`trt']`trtdiff'`trt2'
                if "`trt2'"=="`side2'" local indirect `indirect' + [`y'_`trt']`trtdiff'`trt2'
            }
            else {
                if "`trt2'"=="`trt'" local eq`trt' `eq`trt'' `trtdiff'one
                else                 local eq`trt' `eq`trt'' `trtdiff'zero
            }
        }
        * side-splitting (inconsistency) term
        if mi("`symmetric'") qui gen `trtdiff'inco`trt' =         /// new symmetric version
            0.5 * (("`side2'"=="`trt'") - ("`side2'"=="`ref'"))   /// `side2' is delta/2 more...
            - 0.5 * (("`side1'"=="`trt'") - ("`side1'"=="`ref'")) /// `side1' is delta/2 less...
            if `touse'
        else qui gen `trtdiff'inco`trt' =                         /// asymmetric version of Dias++10
            (("`side2'"=="`trt'") - ("`side2'"=="`ref'"))         /// `side2' is delta more...
            if `touse'
        qui replace `trtdiff'inco`trt' = `trtdiff'inco`trt' * `has'`side1' * `has'`side2' if `touse'
                                                            // ... in trials with side1 & side2
        if `firsteq' local diff [`y'_`trt']`trtdiff'inco`trt'
        local metavars `metavars' `trtdiff'inco`trt'
        local eq`trt' `eq`trt'' `trtdiff'inco`trt'
        * finish off
        if mi("`eqs'") local eqs `eq`trt''
        else           local eqs `eqs', `eq`trt''
        local firsteq 0
    }
}
else if "`format'"=="standard" { // taken from network_meta.ado
    tempvar thistrt base narms
    qui gen `thistrt' = ""
    qui gen `base' = word(`design',1) if `touse'
    local maxdim = `maxarms'-1
    qui gen `narms' = wordcount(`design') if `touse'
    forvalues r=1/`maxdim' {
        qui replace `thistrt' = word(`design',`r'+1) if `touse'
        * consistency model
        local eq`r' `y'_`r':
        foreach trt in `trtlistnoref' {
            qui gen `trtdiff'`r'`trt' = ("`trt'"==`thistrt') - ("`trt'"==`base') if `narms'>`r' & `touse'
            qui replace `trtdiff'`r'`trt' = 0 if `narms'<=`r' & `touse'
            local metavars `metavars' `trtdiff'`r'`trt'
            local eq`r' `eq`r'' `trtdiff'`r'`trt'
            * nlcom expressions
            if "`trt'"=="`side1'" & `r'==1 {
                local indirect `indirect' - [`y'_`r']`trtdiff'`r'`trt'
            }
            if "`trt'"=="`side2'" & `r'==1 {
                local indirect `indirect' + [`y'_`r']`trtdiff'`r'`trt'
            }
        }
        * side-splitting (inconsistency) term
        if mi("`symmetric'") qui gen `trtdiff'inco`r' =        /// new symmetric version
            0.5 * (("`side2'"==`thistrt') - ("`side2'"==`base'))   /// `side2' is delta/2 more...
            - 0.5 * (("`side1'"==`thistrt') - ("`side1'"==`base')) /// `side1' is delta/2 less...
            if `touse'
        else qui gen `trtdiff'inco`r' =                        /// asymmetric version of Dias++10
            (("`side2'"==`thistrt') - ("`side2'"==`base'))     /// `side2' is delta more...
            if `touse'
        qui replace `trtdiff'inco`r' = `trtdiff'inco`r' * `has'`side1' * `has'`side2' if `touse'
                                                            // ... in trials with side1 & side2
        local metavars `metavars' `trtdiff'inco`r'
        local eq`r' `eq`r'' `trtdiff'inco`r'
        if `r'==1 local diff [`y'_`r']`trtdiff'inco`r'
        * finish off
        if mi("`eqs'") local eqs `eq`r''
        else           local eqs `eqs', `eq`r''
    }
}

local mvmetacmd mvmeta `y' `S' `if' `in', `bscov' `options' eq(`eqs') commonparm noconst network(sidesplit) suppress(uv mm)
if substr("`indirect'",1,1)=="+" local indirect : subinstr local indirect "+" ""
local direct `indirect' + `diff'

// FIT SIDESPLIT MODEL
if !mi("`show'") {
    di as text "(fitting model splitting side `side1' `side2')"
    di as input `"Command is: `mvmetacmd'"'
    `mvmetacmd'
    di as text _n "Results splitting `side1' `side2':" _c
}
else qui `mvmetacmd'

* lincom expressions
nlcom (direct:`direct') (indirect:`indirect') (difference:`diff'), noheader
if !mi("`tau'") {
    cap local tauvalue = abs([tau]_cons)
    if !_rc di as text "tau = " as result `tauvalue'
}
tempname b V
mat `b' = r(b)
mat `V' = r(V)
mat rowname `b' = "`measure'"

// FINISH OFF
drop `droplist'
char _dta[network_metavars] `metavars'
restore, not
return matrix b=`b'
return matrix V=`V'
return local side `side1' `side2'
return scalar outside_evidence = `outside_evidence'
if "`f9''"!="nof9" global F9 `mvmetacmd'
end

*==============================================================================

prog def istrt, rclass
* determines whether `1' is a valid treatment
if !mi("`2'") {
    di as error "istrt.ado: too many candidate treatments specified"
    exit 498
}
local test `1'
local istrt 0
foreach trt in `_dta[network_ref]' `_dta[network_trtlistnoref]' {
    if "`test'"=="`trt'" local istrt 1
}
if !`istrt' {
    di as error "`test' is not a valid treatment"
    exit 198
}
end