program define epifix

version 14

* --- Guard: error if user typed an empty fullfix() ---
local __raw = lower("`0'")
if strpos("`__raw'", "fullfix()") {
    di as err "Option fullfix activates the complete-fix mode (no value needed)"
    exit 198
}


syntax varlist(min=1 max=6) , did(varlist) ///
    [ attrib(varlist) fullfix errorsonly QUIET]

	// ---- Activities from varlist ----
    local activities `varlist'
    local nact : word count `activities'

* --- Simple flag: fullfix (no parentheses) ---
local do_fullfix = 0
if "`fullfix'" != "" local do_fullfix = 1




* --- errorsonly: presence/absence flag ---
local do_errorsonly = 0
if "`errorsonly'" != "" local do_errorsonly = 1



local layer_names "pri sec ter quat fif six"

local need = `nact'
if (`need' > 6) local need = 6   // safety cap


    tokenize `activities'
    forvalues i = 1/6 {
        local act`i' ``i''   // act1, act2, ... act6 (some may be empty)
    }

* Save original variable labels (if any) — we will preserve names; labels are optional
forvalues i = 1/`nact' {
    local vlab`i' : variable label `act`i''
}

* Save original VALUE LABEL names and formats for activity vars
forvalues i = 1/`nact' {
    local vallab`i' : value label `act`i''
    local vfmt`i'   : format `act`i''
}


	// ---- Attributes from option (may be empty) ----
    local attribvars `attrib'
    local nattr : word count `attribvars'

    // Check and assign the diary ID
    if "`did'" == "" {
        di as err "Option did() is required"
        exit 198
    }


* ============================================================
* ERRORSONLY: restrict processing to diaries with any issue
* ============================================================
tempfile __orig __baddids



	quietly save "`__orig'", replace

if (`do_errorsonly'==1) {

    capture drop __flag_case __flag_diary

    * Always run epicheck quietly in errorsonly mode
    quietly epicheck, did(`did')   // (don’t let epicheck print its table here)

    preserve
        keep if __flag_diary == 1
        keep `did'
        quietly duplicates drop `did', force
        quietly save "`__baddids'", replace
    restore

    * Restrict to problem diaries quietly
    quietly merge m:1 `did' using "`__baddids'", gen(__m_bad)
    quietly keep if __m_bad==3
    quietly drop __m_bad

    quietly count
    if r(N) == 0 {
        quietly use "`__orig'", clear
        if "`quiet'" == "" di as txt "epifix: no problem diaries detected (errorsonly). No changes made."
        exit
    }
}


* ---- If onlyfor(yes), restrict to flagged diaries up front ----

quietly {


	local did `did'

	// Robust panel id even if did is string
    tempvar udid
    egen `udid' = group(`did')


	// ===== Initialize internal activity layers from act1..act6 =====
    // Decide storage type from act1 and enforce consistency across activities
    capture confirm string variable `act1'
    local _act_is_string = !_rc

foreach v in __pri __sec __ter __quat __fif __six {
    capture confirm variable `v'
    if !_rc {
        capture confirm string variable `v'
        if (`_act_is_string' != !_rc) {
            di as err "`v' type mismatch with activity vars. Drop __pri/__sec/... or start from a clean dataset."
            exit 198
        }
    }
}

    // (Optional but recommended) ensure all passed activity vars share same type
    forvalues i = 2/`nact' {
        local ai : word `i' of `activities'
        capture confirm string variable `ai'
        if (`_act_is_string' != !_rc) {
            di as err "All activity vars must be the same type (string vs numeric). Mismatch at: `ai'"
            exit 198
        }
    }

/* === Working layers (triple underscores) — no collision with existing __* === */

foreach v in ___pri ___sec ___ter ___quat ___fif ___six {
    capture drop `v'
    if `_act_is_string' gen strL `v' = ""
    else                 gen double `v' = .
}

/* Copy input activity vars into working layers (only those provided) */
if "`act1'" != "" replace ___pri = `act1'
if "`act2'" != "" replace ___sec = `act2'
if "`act3'" != "" replace ___ter = `act3'
if "`act4'" != "" replace ___quat = `act4'
if "`act5'" != "" replace ___fif = `act5'
if "`act6'" != "" replace ___six = `act6'

    // Convenience list
    local _layers "___pri ___sec ___ter ___quat ___fif ___six"

    * ------------------------------------------------------------
    * Ensure flag variables exist; if not, run epicheck internally
    * ------------------------------------------------------------
    capture confirm variable __flag_case
    local has_flag_case = !_rc

    capture confirm variable __flag_diary
    local has_flag_diary = !_rc

    if (!`has_flag_case' | !`has_flag_diary') {
        if "`quiet'" != "" quietly epicheck, did(`did')
        else              epicheck, did(`did')
    }

    * If flags still do not exist after epicheck, dataset is clean
    capture confirm variable __flag_case
    local has_flag_case = !_rc

    capture confirm variable __flag_diary
    local has_flag_diary = !_rc

    if (!`has_flag_case' | !`has_flag_diary') {
        noi di as txt "epifix: no issues detected. Nothing to fix."

        if (`do_errorsonly'==1) {
            use "`__orig'", clear
            if "`quiet'" == "" di as txt "epifix: errorsonly active; returning original dataset unchanged."
        }
        exit 0
    }

    /* ===== EARLY EXIT (aware of fullfix()) ===== */
    quietly count if inlist(__flag_case,2,3,4,5,6,7,8)
    local __c28 = r(N)




if (`do_fullfix'==1) {
    quietly count if __flag_case==1
    local __c1 = r(N)

    if (!`__c1' & !`__c28') {
        noi di as txt "No issues to fix (including full overlaps via fullfix(yes))."

        // --- EARLY EXIT FIX (errorsonly): restore full dataset before leaving ---

		if (`do_errorsonly'==1) {
            use "`__orig'", clear
            if "`quiet'" == "" di as txt "epifix: errorsonly active; returning original dataset unchanged."
        }
        exit 0
    }
}
else {
    if (!`__c28') {
        noi di as txt "No issues to fix."
        *noi di as txt "Note: full overlaps (__flag_case==1) are handled by {cmd:epitrans}."

        // --- EARLY EXIT FIX (errorsonly): restore full dataset before leaving ---

		if (`do_errorsonly'==1) {
            use "`__orig'", clear
            if "`quiet'" == "" di as txt "epifix: errorsonly active; returning original dataset unchanged."
        }
        exit 0
    }
}



/* === PART A: Capture case 1 counts (only once) if fullfix(yes) === */
if (`do_fullfix'==1) {
    // Only create the scalars if they don't already exist
    capture confirm scalar __pre_cases1
    if _rc {
        count if __flag_case==1
        scalar __pre_cases1 = r(N)
    }

    capture confirm scalar __pre_diaries1
    if _rc {
        tempvar __tag1
        egen `__tag1' = tag(`did') if __flag_case==1
        count if `__tag1'==1
        scalar __pre_diaries1 = r(N)
        drop `__tag1'
    }
}


if (`do_fullfix'==1) {
    // Block id on (did,start,end)
    tempvar __blk __bsize __rank __keep __isfull
    egen `__blk' = group(`did' start end)

    // Blocks flagged as full overlaps
    bys `__blk': egen byte `__isfull' = max(__flag_case==1)

    // Size & rank within block (stable on current sort)
    bys `__blk': gen int `__bsize' = _N if `__isfull'
    bys `__blk': gen int `__rank'  = _n if `__isfull'

    // Survivor row (rank==1) in each full-overlap block
    gen byte `__keep' = (`__isfull' & `__rank'==1)

    // Clear internal layers in full-overlap blocks
    foreach L in ___pri ___sec ___ter ___quat ___fif ___six {
        capture confirm variable `L'
        if !_rc {
            if `_act_is_string' replace `L' = "" if `__isfull'
            else                  replace `L' = .  if `__isfull'
        }
    }

// Map rank→slot on survivor
forvalues k=1/6 {
    if (`k'<=`nact') {
        local layer = cond(`k'==1,"___pri", cond(`k'==2,"___sec", ///
                         cond(`k'==3,"___ter", cond(`k'==4,"___quat", ///
                         cond(`k'==5,"___fif","___six")))))
        bys `__blk' (start end): replace `layer' = `act1'[_n+`k'-1] ///
            if `__keep' & `__bsize'>=`k'
    }
}


    // Clear case-1 flag on survivor, drop the rest
    replace __flag_case = 0 if `__keep' & `__isfull'
    drop if `__isfull' & !`__keep'

    // Re-index after collapse
    tempvar epnum
    bysort `did' (start end): gen `epnum' = _n
    //tsset `udid' `epnum'
}

* Per-issue rows & diaries (7)
tempvar __tag7
count if __flag_case==7
scalar __drop7_rows = r(N)
egen `__tag7' = tag(`did') if __flag_case==7
count if `__tag7'==1
scalar __drop7_diaries = r(N)
drop `__tag7'

* Per-issue rows & diaries (8)
tempvar __tag8
count if __flag_case==8
scalar __drop8_rows = r(N)
egen `__tag8' = tag(`did') if __flag_case==8
count if `__tag8'==1
scalar __drop8_diaries = r(N)
drop `__tag8'

* Snapshot of total diaries with ANY EpiFix-relevant issue (2..8) BEFORE drop
tempvar __d_any __tag_any
egen `__d_any' = max(inlist(__flag_case,2,3,4,5,6,7,8)), by(`did')
egen `__tag_any' = tag(`did') if `__d_any'==1
count if `__tag_any'==1
scalar __pre_total_diaries_any = r(N)
drop `__tag_any' `__d_any'

* Also compute union across 1..8 BEFORE any fixes (needed when fullfix(yes))
if (`do_fullfix'==1) {
    tempvar __tag_all
    egen `__tag_all' = tag(`did') if inlist(__flag_case,1,2,3,4,5,6,7,8)
    count if `__tag_all'==1
    scalar __pre_total_diaries_all = r(N)
    drop `__tag_all'
}
else {
    scalar __pre_total_diaries_all = __pre_total_diaries_any
}

* Finally drop 7/8 rows
drop if inlist(__flag_case,7,8)

* Combined counts for reporting
capture scalar drop __drop78_rows __drop78_diaries
scalar __drop78_rows    = cond(missing(__drop7_rows),0,__drop7_rows) + cond(missing(__drop8_rows),0,__drop8_rows)
scalar __drop78_diaries = cond(missing(__drop7_diaries),0,__drop7_diaries) + cond(missing(__drop8_diaries),0,__drop8_diaries)

capture scalar drop __pre_cases2 __pre_cases3 __pre_cases4 __pre_cases5 __pre_cases6 ///
                     __pre_total_cases __pre_diaries2 __pre_diaries3 __pre_diaries4 __pre_diaries5 __pre_diaries6 ///
                     __pre_total_diaries
tempvar __tagpre

/* Per-case rows & diaries for 2–6 (unchanged) */
forvalues i = 2/6 {
    count if __flag_case == `i'
    scalar __pre_cases`i' = r(N)

    egen `__tagpre' = tag(`did') if __flag_case == `i'
    count if `__tagpre' == 1
    scalar __pre_diaries`i' = r(N)
    drop `__tagpre'
}

/* Totals & union of diaries */
if (`do_fullfix'==1) {

    capture scalar drop __pre_cases1_safe __pre_diaries1_safe
    scalar __pre_cases1_safe   = cond(missing(__pre_cases1),   0, __pre_cases1)
    scalar __pre_diaries1_safe = cond(missing(__pre_diaries1), 0, __pre_diaries1)

    /* Total cases including case 1 */
    scalar __pre_total_cases = __pre_cases1_safe
    forvalues i = 2/6 {
        scalar __pre_total_cases = __pre_total_cases + __pre_cases`i'
    }

    /* Union of diaries including case 1 */
    tempvar __tagpre_all
    egen `__tagpre_all' = tag(`did') if inlist(__flag_case,1,2,3,4,5,6)
    count if `__tagpre_all' == 1
    scalar __pre_total_diaries = r(N)
    drop `__tagpre_all'
}
else {
    /* Original behaviour: totals over 2–6 only */
    scalar __pre_total_cases = 0
    forvalues i = 2/6 {
        scalar __pre_total_cases = __pre_total_cases + __pre_cases`i'
    }

    egen `__tagpre' = tag(`did') if inlist(__flag_case,2,3,4,5,6)
    count if `__tagpre' == 1
    scalar __pre_total_diaries = r(N)
    drop `__tagpre'
}



/* Nested episodes - __flag_case==2 */

capture drop `epnum'
tempvar epnum

tempvar newobs   // <-- ADD THIS LINE (this is the fix)

bysort `did' (start end): gen long `epnum' = _n
expand 2 if __flag_case[_n-1]==2, gen(`newobs')
bysort `did' (start end `newobs'): replace `epnum' = _n


bysort `did' (start end): ///
    replace end = start[_n+1] if __flag_case==2 & _n < _N
bysort `did' (start end): ///
    replace ___sec = ___pri if __flag_case[_n-1]==2 & _n>1
bysort `did' (start end): ///
    replace ___pri = ___pri[_n-1] if __flag_case[_n-1]==2 & _n>1
bysort `did' (start end): ///
    replace ___pri = ___pri[_n-2] if __flag_case[_n-2]==2 & _n>2
bysort `did' (start end): ///
    replace start = end[_n-1] if __flag_case[_n-2]==2 & _n>2
bysort `did' (start end): ///
    replace end = start[_n+1] if __flag_case[_n-2]==2 & _n<_N

/* 3. partial overlap of episodes */

gen byte __f3a = 0
bysort `did' (start end): replace __f3a = 1 if __flag_case==3 ///
    & _n < _N ///
    & start < . & end < . ///
    & start[_n+1] < . & end[_n+1] < . ///
    & start <  start[_n+1] ///
    & end   >  start[_n+1] ///
    & end   <  end[_n+1]

gen byte __f3b = 0
bysort `did' (start end): replace __f3b = 1 if __flag_case==3 ///
    & _n < _N ///
    & start < . & end < . ///
    & start[_n+1] < . & end[_n+1] < . ///
    & start == start[_n+1] ///
    & end   <  end[_n+1]

gen byte __f3c = 0
bysort `did' (start end): replace __f3c = 1 if __flag_case==3 ///
    & _n < _N ///
    & start < . & end < . ///
    & start[_n+1] < . & end[_n+1] < . ///
    & end   == end[_n+1] ///
    & start <  start[_n+1]

/* Fixing 3a */
capture drop `newobs'
tempvar newobs
expand 2 if __f3a==1, gen(`newobs')
bysort `did' (start end `newobs'): replace __f3a=0 if `newobs'==1 // keep only ONE flagged row per case (clear flag on the inserted copy)

bysort `did' (start end): replace end=start[_n+2] if __f3a==1 & _n <= _N-2
bysort `did' (start end): replace start=end[_n-1] if __f3a[_n-1]==1 & _n>1
bysort `did' (start end): replace ___sec=___pri[_n+1] if __f3a[_n-1]==1 & _n>1
bysort `did' (start end): replace start=end[_n-1] if __f3a[_n-2]==1 & _n>2

/* Fixing 3b */
bysort `did' (start end): replace ___sec=___pri[_n+1] if __f3b==1 & _n < _N & !missing(___pri[_n+1])
bysort `did' (start end): replace start = end[_n-1] if _n > 1 & __f3b[_n-1]==1 & end[_n-1] < .

/* Fixing 3c */
bysort `did' (start end): replace end=start[_n+1] if __f3c==1 & _n < _N & !missing(start[_n+1]) & end > start[_n+1]
bysort `did' (start end): replace ___sec=___pri if _n>1 & __f3c[_n-1]==1 & !missing(___pri)
bysort `did' (start end): replace ___pri= ___pri[_n-1] if _n>1 & __f3c[_n-1]==1 & !missing(___pri[_n-1])

* clean up
drop __f3a __f3b __f3c


/* 4. Gaps at beginning of diary */

* Duplicate first row when flagged; mark inserted copy
tempvar newobs
expand 2 if __flag_case == 4, gen(`newobs')

* For inserted (new) rows: set [start,end] = [0, old first start]
bysort `did' (start): replace start = 0               if `newobs'
bysort `did' (start): replace end   = start[_n+1]     if `newobs'

* Clear INTERNAL activity layers for inserted rows (type-aware)
foreach L in ___pri ___sec ___ter ___quat ___fif ___six {
    if `_act_is_string' replace `L' = "" if `newobs'
    else                  replace `L' = .  if `newobs'
}

* Clear attribute variables for inserted rows (type-aware; attrib() may be empty)
foreach attr of local attribvars {
    capture confirm string variable `attr'
    if !_rc replace `attr' = "" if `newobs'
    else    replace `attr' = .  if `newobs'
}

* Only the inserted rows carry the A-flag
replace __flag_case = 0 if __flag_case == 4 & !`newobs'
//egen __flag_case = max(`__flagA'), by(`did')

sort `did' start
bysort `did': replace `epnum' = _n


/* 5. Gaps at end of diary */

* Identify the last episode's end per diary (one-liner, no propagation needed)
tempvar last_end
bysort `did' (start): gen `last_end' = end[_N]

* Duplicate the row(s) that need the end-gap fill (your flag==5)
tempvar newobs
expand 2 if __flag_case==5, gen(`newobs')


* Assign [start,end] on the inserted row
replace start = `last_end' if __flag_case==5 & `newobs'==1
replace end   = 1440       if __flag_case==5 & `newobs'==1

* Clear INTERNAL activity layers for inserted rows (type-aware)
foreach L in ___pri ___sec ___ter ___quat ___fif ___six {
    capture confirm variable `L'
    if !_rc {
        if `_act_is_string' replace `L' = "" if `newobs'
        else                  replace `L' = .  if `newobs'
    }
}

* Clear attribute variables for inserted rows (type-aware; attrib() may be empty)
if `"`attribvars'"' != "" {
    foreach attr of local attribvars {
        capture confirm variable `attr'
        if !_rc {
            capture confirm string variable `attr'
            if !_rc replace `attr' = "" if `newobs'
            else    replace `attr' = .  if `newobs'
        }
    }
}


* Keep/assign the flag safely: only mark the new row as case 5; leave others unchanged
//replace __flag_case = 0 if __flag_case==5 & `newobs'==1
replace __flag_case = 0 if __flag_case==5 & `newobs'==0


/* 6. Other Gaps between episodes */

tempvar newobs
expand 2 if __flag_case==6, gen(`newobs')

sort `did' start `newobs'
bysort `did': replace `epnum' = _n
tsset `udid' `epnum'

replace start = l1.end   if __flag_case==6 & `newobs'==1
replace end   = f1.start if __flag_case==6 & `newobs'==1

* Clear INTERNAL activity layers for inserted rows (type-aware)
foreach L in ___pri ___sec ___ter ___quat ___fif ___six {
    if `_act_is_string' replace `L' = "" if __flag_case==6 & `newobs'==1
    else                  replace `L' = .  if __flag_case==6 & `newobs'==1
}

* Clear attributes for inserted rows (type-aware; attrib() may be empty)
foreach attr of local attribvars {
    capture confirm string variable `attr'
    if !_rc replace `attr' = "" if __flag_case==6 & `newobs'==1
    else    replace `attr' = .  if __flag_case==6 & `newobs'==1
}


* Flag for reporting (keep the flag on the inserted row)
replace __flag_case = 0   if __flag_case==6 & `newobs'==0


*----------------------------------------------------------------*
* Enforce exclusivity across issue flags (1 > 2 > 3 > 4 > 5)     *
*----------------------------------------------------------------*

/* Diary-level flag */
capture drop __flag_diary
egen __flag_diary = max(inlist(__flag_case,2,3,4,5,6)), by(`did')
label variable __flag_diary "Diary contained issue(s) fixed by epifix"

/* capture drop __flag_diary
egen __flag_diary = max(__flag_case > 0), by(`did') */

* Diaries affected by any issue (unique)
tempvar __tagTotal
quietly egen `__tagTotal' = tag(`did') if __flag_diary == 1
quietly count if `__tagTotal' == 1
scalar __total_diaries = r(N)


* ------------------------------------------------------------ *
* Drop unused activity slots at the end if they are fully empty
* ------------------------------------------------------------ *

* Sort & (best-effort) order: ignore any vars that might be absent
sort `did' start
capture order `did' start end ___pri ___sec ___ter ___quat ___fif ___six `attribvars' __flag_case __flag_diary

* Remove trailing empty layers only (string "" or numeric . both count as missing())
foreach act in ___six ___fif ___quat ___ter ___sec {
    capture confirm variable `act'
    if !_rc {
        quietly count if !missing(`act')
        if r(N)==0 capture drop `act'
    }
}

/* === Finalize: rebuild official activity columns and copy from working === */

/* === Finalize (EpiFix): rebuild official columns, then copy from working if present === */

/* __pri */
capture drop __pri
if `_act_is_string' gen strL __pri = ""
else                gen double __pri = .
capture confirm variable ___pri
if !_rc replace __pri = ___pri

* Reattach value label + format from act1 (only if numeric)
if !`_act_is_string' {
    if "`vallab1'" != "" label values __pri `vallab1'
    if "`vfmt1'"   != "" format __pri `vfmt1'
}

/* __sec */
capture drop __sec
if `_act_is_string' gen strL __sec = ""
else                gen double __sec = .
capture confirm variable ___sec
if !_rc replace __sec = ___sec

if !`_act_is_string' {
    if "`vallab2'" != "" label values __sec `vallab2'
    if "`vfmt2'"   != "" format __sec `vfmt2'
}

/* __ter */
capture drop __ter
if `_act_is_string' gen strL __ter = ""
else                gen double __ter = .
capture confirm variable ___ter
if !_rc replace __ter = ___ter

if !`_act_is_string' {
    if "`vallab3'" != "" label values __ter `vallab3'
    if "`vfmt3'"   != "" format __ter `vfmt3'
}

/* __quat */
capture drop __quat
if `_act_is_string' gen strL __quat = ""
else                gen double __quat = .
capture confirm variable ___quat
if !_rc replace __quat = ___quat

if !`_act_is_string' {
    if "`vallab4'" != "" label values __quat `vallab4'
    if "`vfmt4'"   != "" format __quat `vfmt4'
}

/* __fif */
capture drop __fif
if `_act_is_string' gen strL __fif = ""
else                gen double __fif = .
capture confirm variable ___fif
if !_rc replace __fif = ___fif

if !`_act_is_string' {
    if "`vallab5'" != "" label values __fif `vallab5'
    if "`vfmt5'"   != "" format __fif `vfmt5'
}

/* __six */
capture drop __six
if `_act_is_string' gen strL __six = ""
else                gen double __six = .
capture confirm variable ___six
if !_rc replace __six = ___six

if !`_act_is_string' {
    if "`vallab6'" != "" label values __six `vallab6'
    if "`vfmt6'"   != "" format __six `vfmt6'
}

/* Optional labels */
capture label var __pri  "Primary activity"
capture label var __sec  "Secondary activity"
capture label var __ter  "Tertiary activity"
capture label var __quat  "Quaternary activity"
capture label var __fif  "Fifth activity"
capture label var __six  "Sixth activity"

/* Optional: drop working columns */
capture drop ___pri
capture drop ___sec
capture drop ___ter
capture drop ___quat
capture drop ___fif
capture drop ___six

/* Drop official activity columns beyond what we actually need */
forvalues j = `= `need' + 1' / 6 {
    local L : word `j' of `layer_names'
    capture drop __`L'
}

/* (optional) also drop unused working columns beyond need, or drop them all */
forvalues j = `= `need' + 1' / 6 {
    local L : word `j' of `layer_names'
    capture drop ___`L'
}


order `did' start end __pri `varlist' __flag_case __flag_diary
capture order `did' start end __pri __sec `varlist' __flag_case __flag_diary
capture order `did' start end __pri __sec __ter `varlist' __flag_case __flag_diary
capture order `did' start end __pri __sec __ter __quat `varlist' __flag_case __flag_diary
capture order `did' start end __pri __sec __ter __quat __fif `varlist' __flag_case __flag_diary
capture order `did' start end __pri __sec __ter __quat __fif __six `varlist' __flag_case __flag_diary

sort `did' start end


* ------------------------------------------------------------
* Write results back into the original user-supplied variables
* and cap the number of layers to min(napi, nact).
* ------------------------------------------------------------

local nkeep = `nact'

* Count if we would lose information above nkeep (for warning)
tempname __lost
scalar `__lost' = 0
forvalues j = `= `nkeep' + 1' / 6 {
    local L = cond(`j'==1,"__pri", cond(`j'==2,"__sec", cond(`j'==3,"__ter", ///
                cond(`j'==4,"__quat", cond(`j'==5,"__fif","__six")))))
    capture confirm variable `L'
    if !_rc {
        quietly count if !missing(`L')
        if r(N)>0 scalar `__lost' = `__lost' + r(N)
    }
}

* Overwrite the user's original variables with finalized layers (preserves names)
forvalues i = 1/`nkeep' {
    local L = cond(`i'==1,"__pri", cond(`i'==2,"__sec", cond(`i'==3,"__ter", ///
                cond(`i'==4,"__quat", cond(`i'==5,"__fif","__six")))))
    capture confirm variable `L'
    if !_rc {
        * Ensure type compatibility already handled in build step
        quietly replace `act`i'' = `L'
        * Optionally restore the original variable label
        capture label var `act`i'' "`vlab`i''"
    }
}

* Drop any extra standardized layers above nkeep
forvalues j = `= `nkeep' + 1' / 6 {
    local L = cond(`j'==1,"__pri", cond(`j'==2,"__sec", cond(`j'==3,"__ter", ///
                cond(`j'==4,"__quat", cond(`j'==5,"__fif","__six")))))
    capture drop `L'
}

* Always drop working columns
capture drop ___pri ___sec ___ter ___quat ___fif ___six


* Optional: warn if information was discarded due to layer cap
if (scalar(`__lost') > 0) {
    noi di as res "Note: Additional parallel activities existed above layer " `nkeep' ///
        " and were not preserved in the output (rows: " %9.0f `__lost' ")."
    noi di as txt "      Consider using {cmd:epitrans} first, or rerun with more activity variables."
}

}   // end quietly (main work)

* ============================================================
* ERRORSONLY: reassemble full dataset (drop bad diaries, append fixed)
* ============================================================

if (`do_errorsonly'==1) {

    tempfile __fixed_subset
    quietly save "`__fixed_subset'", replace

    quietly use "`__orig'", clear

    * Drop original bad diaries quietly (suppress merge table)
    quietly merge m:1 `did' using "`__baddids'", gen(__m_bad) keep(1 3)
    quietly drop if __m_bad == 3
    quietly drop __m_bad

    * Append quietly, and suppress “label ... already defined”
    quietly append using "`__fixed_subset'", nolabel

    * Fill standardized layers quietly (suppress “missing values generated” / “real changes made”)
    quietly {
        capture confirm string variable `act1'
        local _act_is_string = !_rc

        foreach v in __pri __sec __ter __quat __fif __six {
            capture confirm variable `v'
            if _rc {
                if `_act_is_string' gen strL `v' = ""
                else                 gen double `v' = .
            }
        }

        if "`act1'" != "" replace __pri  = `act1' if missing(__pri)
        if "`act2'" != "" replace __sec  = `act2' if missing(__sec)
        if "`act3'" != "" replace __ter  = `act3' if missing(__ter)
        if "`act4'" != "" replace __quat = `act4' if missing(__quat)
        if "`act5'" != "" replace __fif  = `act5' if missing(__fif)
        if "`act6'" != "" replace __six  = `act6' if missing(__six)

        capture confirm variable start
        if !_rc sort `did' start end
        else    sort `did'
    }
}


 * ============================================================
* FINAL CLEANUP (must be AFTER errorsonly reassembly)
* ============================================================
foreach v in __six __fif __quat __ter __sec {
    capture confirm variable `v'
    if !_rc {
        quietly count if !missing(`v')
        if (r(N) == 0) drop `v'
    }
}

// --- Clean summary table output for epifix ---

*---------------------------------------------*
* Count total number of unique diaries
*---------------------------------------------*
tempvar __tagdiary
quietly egen `__tagdiary' = tag(`did')
quietly count if `__tagdiary' == 1
scalar __n_diaries = r(N)

*---------------------------------------------*
* Use pre-fix snapshot for reporting (cases 2–6)
*---------------------------------------------*

scalar __cases2 = cond(missing(__pre_cases2), 0, __pre_cases2)
scalar __cases3 = cond(missing(__pre_cases3), 0, __pre_cases3)
scalar __cases4 = cond(missing(__pre_cases4), 0, __pre_cases4)
scalar __cases5 = cond(missing(__pre_cases5), 0, __pre_cases5)
scalar __cases6 = cond(missing(__pre_cases6), 0, __pre_cases6)
scalar __cases7 = cond(missing(__drop7_rows), 0, __drop7_rows)
scalar __cases8 = cond(missing(__drop8_rows), 0, __drop8_rows)

scalar __total_cases = __cases2 + __cases3 + __cases4 + __cases5 + __cases6 + __cases7 + __cases8

if (`do_fullfix'==1) {
    scalar __cases1   = cond(missing(__pre_cases1),   0, __pre_cases1)
    scalar __diaries1 = cond(missing(__pre_diaries1), 0, __pre_diaries1)
    scalar __total_cases = __total_cases + __cases1
}


if (scalar(__total_cases) == 0) {
    di as txt "No issues detected by epifix."
    if (scalar(__drop78_rows) > 0) {
        di as txt ""
        di as txt "Additionally, dropped " %9.0f __drop78_rows " row(s) with Issue 7/8 (start==end or missing start/end)"
        di as txt "across " %9.0f __drop78_diaries " diary(ies) before applying fixes."
    }
    exit 0
}

scalar __diaries2 = cond(missing(__pre_diaries2), 0, __pre_diaries2)
scalar __diaries3 = cond(missing(__pre_diaries3), 0, __pre_diaries3)
scalar __diaries4 = cond(missing(__pre_diaries4), 0, __pre_diaries4)
scalar __diaries5 = cond(missing(__pre_diaries5), 0, __pre_diaries5)
scalar __diaries6 = cond(missing(__pre_diaries6), 0, __pre_diaries6)


* Union of diaries that had any issue 2..8 BEFORE the drop
scalar __total_diaries = cond(missing(__pre_total_diaries_all), 0, __pre_total_diaries_all)

* Avoid divide-by-zero in % calculations
scalar __den = cond(__n_diaries>0, __n_diaries, .)


*---------------------------------------------*
* Display formatted summary table (Explorer-style)
*---------------------------------------------*

local w1 28   // width for first column with labels
local w2 8
local w3 8
local w4 9

* Title
di as txt "Summary of fixes"
di as txt "---------------------------------------------------------------"

* Header row
di as txt "  " %-`w1's "Issue type"  ///
    " |" %`w2's "Cases"        ///
    " |" %`w3's "Diaries"      ///
    " |" %`w4's "Diaries (%)"

* Header underline
di as txt "-------------------------------+---------+---------+-----------"

* Body (EpiFix scope = cases 2–6 only)
if (`do_fullfix'==1) {
    scalar __cases1   = cond(missing(__pre_cases1),   0, __pre_cases1)
    scalar __diaries1 = cond(missing(__pre_diaries1), 0, __pre_diaries1)

    di as result "  " %-`w1's "Full overlap" ///
        " |" %`w2'.0f __cases1   " |" %`w3'.0f __diaries1   " |" %`w4'.1f (100 * __diaries1 / __n_diaries)
}

di as result "  " %-`w1's "Nested episode"       ///
    " |" %`w2'.0f __cases2   " |" %`w3'.0f __diaries2   " |" %`w4'.1f (100 * __diaries2 / __n_diaries)

di as result "  " %-`w1's "Partial overlap"      ///
    " |" %`w2'.0f __cases3   " |" %`w3'.0f __diaries3   " |" %`w4'.1f (100 * __diaries3 / __n_diaries)

di as result "  " %-`w1's "Gap at min 0"         ///
    " |" %`w2'.0f __cases4   " |" %`w3'.0f __diaries4   " |" %`w4'.1f (100 * __diaries4 / __n_diaries)

di as result "  " %-`w1's "Gap at end of diary"  ///
    " |" %`w2'.0f __cases5   " |" %`w3'.0f __diaries5   " |" %`w4'.1f (100 * __diaries5 / __n_diaries)

di as result "  " %-`w1's "Gap between episodes" ///
    " |" %`w2'.0f __cases6   " |" %`w3'.0f __diaries6   " |" %`w4'.1f (100 * __diaries6 / __n_diaries)

di as result "  " %-`w1's "Row start==end (dropped)" ///
    " |" %`w2'.0f __cases7   " |" %`w3'.0f __drop7_diaries   " |" %`w4'.1f (100 * __drop7_diaries / __n_diaries)

di as result "  " %-`w1's "Missing start/end (dropped)" ///
    " |" %`w2'.0f __cases8   " |" %`w3'.0f __drop8_diaries   " |" %`w4'.1f (100 * __drop8_diaries / __n_diaries)

* Footer underline
di as txt "-------------------------------+---------+---------+-----------"

* Total row
di as result "  " %-`w1's "Total" ///
    " |" %`w2'.0f __total_cases ///
    " |" %`w3'.0f __total_diaries ///
    " |" %`w4'.1f (100 * __total_diaries / __n_diaries)

di as txt "---------------------------------------------------------------"

* ------------------------------------------------------------
* User message: where to find the fixed activity variables
* ------------------------------------------------------------
if "`quiet'" == "" {

    * Build a list of the fixed (standardized) activity-layer vars that exist
    local fixedlayers ""
    foreach v in __pri __sec __ter __quat __fif __six {
        capture confirm variable `v'
        if !_rc local fixedlayers "`fixedlayers' `v'"
    }

    * Build a list of the original activity vars passed in (if they still exist)
    local origvars ""
    foreach v of local varlist {
        capture confirm variable `v'
        if !_rc local origvars "`origvars' `v'"
    }

    di as txt ""

    if "`fixedlayers'" != "" {
        di as txt "Fixed activity layers are stored in:" as res "`fixedlayers'"
    }
    else {
        di as err "Warning: no fixed activity-layer variables (__pri, __sec, ...) were found."
    }

    if "`origvars'" != "" & "`fixedlayers'" != "" {
        di as txt "Note: the original activity variables you supplied (" as res "`origvars'" as txt ///
                  ") are still in the dataset."
    }
}

end