*! Version 1.0.1 11sep2020 MJC

/*
History
MJC 11sep2020: version 1.0.1 - enter() renamed to ltruncated() for consistency with survsim & predictms
MH 02mar2020: version 1.0.0  - restructured so calculations are all performed in mata (improved efficiency)
							 - bug fix: confidence intervals caused a conformability error and kronecker delta function incorrectly defined; now fixed
							 - removal of gen option
							 - id option no longer required due to restructure
							 - enter time option added
							 - exit time option added
							 - from state option added
							 - los option added
							 - se option added
							 - program now works for bi-directional models
							 - additional error checks
PCL 30apr2019: version 0.6.0 -
*/


program define msaj
	version 14.2
	syntax [if] [in] , 	[		TRANSMatrix(name)	///
								BY(varname) 		///
								LTruncated(real 0)	///
								EXIT(real -99)		///
								FROM(integer 1)		///
								CR					///
								LOS					///
								CI					///
								SE					///
				]

	marksample touse
	if "`by'" != "" {
		qui replace `touse' = 0 if `by' == .
		qui levelsof `by' if `touse', local(bylevels)
	}


	// Error checks

	cap confirm variable _t _d _st _t0, exact
	if _rc {
		di as error "Data must be stset (at least one variable of _st, _t, _t0 or _d missing)"
		exit 198
	}

	cap confirm variable _trans, exact
	if _rc {
		di as error "Data must be msset (_trans variable missing)"
		exit 198
	}

	cap confirm variable _to, exact
	if _rc & "`cr'"!="" {
		di as error "Data must be msset (_to variable missing, needed for CR option)"
		exit 198
	}

	cap confirm variable _to _from, exact
	if ("`ci'" != "" | "`se'" != "") & _rc {
		di as error "_from and _to variables must be specified for CI or SE option"
		exit 198
	}

	if ("`transmatrix'" == ""  & "`cr'" == "") | ("`transmatrix'" != ""  & "`cr'" != "") {
		di as error "You must specify either the transition matrix or use the cr option"
		exit 198
	}

	if "`transmatrix'" != "" {
		local Nstates = colsof(`transmatrix')

		if `Nstates' < 2 {
			di as error "Must be at least 2 possible states, including starting state"
			exit 198
		}

		if `from' < 1 | `from' > `Nstates' {
			di as error "From state must be between 1 and the maximum number of states"
			exit 198
		}
	}

	if "`cr'"!="" & `from'!=1 {
		di as error "If CR is specified then from must be 1"
		exit 198
	}

	if `ltruncated' < 0 {
		di as error "ltruncated() time must be positive"
		exit 198
	}


	// Set exit time if not given and check it is after ltruncated time

	summ _t if `touse', meanonly
	local max_t = `r(max)'
	summ _t if `touse' & _d ==1, meanonly
	local max_event = `r(max)'

	if `exit' == -99 local exit `max_event'

	if `exit' <= `ltruncated' {
		di as error "ltruncated() time (default 0) is greater than or equal to exit time (default max any event time)"
		exit 198
	}

	if `exit' > `max_event' & `exit' <= `max_t' {
		di as error "Warning: Exit time is greater than last event time"
	}

	if `exit' > `max_t' {
		di as error "Exit time is greater than the maximum time"
		exit 198
	}


	// Build the transition matrix if CR is specified

	if "`cr'" != "" {

		summ _to if `touse', meanonly
		local Nstates `r(max)'

		if `Nstates' < 2 {
			di as error "Must be at least 2 possible states, including starting state (max _to is 1)"
			exit 198
		}

		tempname transmatrix
		matrix `transmatrix' = J(`Nstates',`Nstates',.)
		forvalues i = 2/`Nstates' {
			local tmptrans = `i' - 1
			matrix `transmatrix'[1,`i'] = `tmptrans'
		}
	}


	// Prepare the output variables

	forvalues i = 1/`Nstates' {
		local newvars `newvars' P_AJ_`i'
		if "`ci'" != "" {
			local newvars `newvars' P_AJ_`i'_lci P_AJ_`i'_uci
		}
		if "`se'" != "" {
			local newvars_se `newvars_se' P_AJ_`i'_se
		}
		if "`los'" != "" {
			local newvars_LOS `newvars_LOS' LOS_AJ_`i'
		}
	}

	local Nnewvars = wordcount("`newvars'")
	forvalues i = 1/`Nnewvars' {
		local tmp = word("`newvars'",`i')
		qui gen double `tmp'=.
	}

	if "`se'" != "" {
		local Nnewvars_se = wordcount("`newvars_se'")
		forvalues i = 1/`Nnewvars_se' {
			local tmp = word("`newvars_se'",`i')
			qui gen double `tmp'=.
		}
	}

	if "`los'" != "" {
		local Nnewvars_LOS = wordcount("`newvars_LOS'")
		forvalues i = 1/`Nnewvars_LOS' {
			local tmp = word("`newvars_LOS'",`i')
			qui gen double `tmp'=.
		}
	}


	// Get the hazards

	tempvar Nrisk Nevents

	sts gen `Nrisk'=n if `touse', by(_trans `by')
	sts gen `Nevents'=d if `touse', by(_trans `by')


	// Call mata to apply AJ equations
	mata AJ()

end