/* version 2, October 25, 2003, allen buxton*/
	/*capture program drop tarow*/
	program define tarow, rclass
	version 7.0

	syntax varlist [if] [in] [, Options_tabulate(string) Row_options_tabulate(string)]

	tempvar touse
	mark `touse' `if' `in'
	qui count if `touse'
	if r(N)==0 {
		error 2000 			/* no observations */
		} 

	local varlstA  `"`varlist'"'
	local tabopts  `"`options_tabulate'"'
	local rtabopts `"`row_options_tabulate'"'

	local opt_missing_flag = 0
	foreach Opt in `tabopts' {
		/*display `"=====!!!====="'*/
		/*display `"option: `Opt'"'*/
		local Option_i = lower(`"`Opt'"')
		/* I am assumming that single "m" stands for missing, provided that "m" is not "mat..." */
		if index(`"`Option_i'"',`"mat"') ==0  {
			if substr(`"`Option_i'"',1,1) == `"m"' {
				local opt_missing_flag = 1
				}
			}
		}

	tokenize `varlstA'
	local n_var : word count `varlstA'
	if `n_var' == 2 {
		local twovarentered=1
		}
		else if `n_var' ~= 2 {
			local twovarentered=0
			}
		if `n_var' == 1 {
			error 102		/* too few variables entered */
			}
		else if `n_var' >= 3 {
			error 103		/* too many variables entered */
			}
	local var1 `1'	/* row variable */
	local var2 `2'	/* column variable */
	local typ1 : type `var1'
	local typ2 : type `var2'
	if `"`typ1'"' == `"byte"' {
		local typ1ok = 1
		}
	else if `"`typ1'"' == `"int"' {
		local typ1ok = 1
		}
	else if `"`typ1'"' == `"long"' {
		local typ1ok = 1
		}
	else if `"`typ1'"' == `"float"' {
		local typ1ok = 1
		}
	else if `"`typ1'"' == `"double"' {
		local typ1ok = 1
		}
	else {
		local typ1ok=0
	}
	if `"`typ2'"' == `"byte"' {
		local typ2ok = 1
		}
	else if `"`typ2'"' == `"int"' {
		local typ2ok = 1
		}
	else if `"`typ2'"' == `"long"' {
		local typ2ok = 1
		}
	else if `"`typ2'"' == `"float"' {
		local typ2ok = 1
		}
	else if `"`typ2'"' == `"double"' {
		local typ2ok = 1
		}
	else {
		local typ2ok=0
	}

	if `typ1ok'==0 | `typ2ok'==0 {
		display `"currently, only numeric variables are required"' 
		error 459
		}

tempvar rowvar
tempvar colvar
		
	*display `"   variable list: "' `"`varlstA'"'
	*display `"   variable list: "' `"`var1'"'
	*display `"   variable type: "' `"`typ1'"'
	*display `"   variable type: "' `"`typ1ok'"'
	*display `"   variable list: "' `"`var2'"'
	*display `"   variable type: "' `"`typ2'"'
	*display `"   variable type: "' `"`typ2ok'"'
	*display `"      num of var: "' `"`n_var'"'
	*display `"Tabulate options: "' `"`tabopts'"'
	*display `"Row tabulate opt: "' `"`rtabopts'"'

	tempvar otherrow
	tempvar tempA
	tempvar tempB
	tempvar tempC
	tempname m1 
	tempname m2
	tempname m3

	if `"`tabopts'"' == `""' {
		tabulate `var1' `var2' if `touse'
		}
	else {
		tabulate `var1' `var2' if `touse', `tabopts'
		}
	display `""'

	/* I shall unconditionally do the following to get the matricies of the main table */
	/* yet, if options_tabulate contains missing then I need that one option here */
	/* this is the purpose of this ex */
	if `opt_missing_flag'==1 {
		qui tabulate `var1' `var2' if `touse',missing matrow(`m1') matcol(`m2') matcell(`m3')
		}
	else if `opt_missing_flag'==0  {
		qui tabulate `var1' `var2' if `touse',matrow(`m1') matcol(`m2') matcell(`m3')
		}

	/*matrix list `m1'*/
	/*matrix list `m2'*/
	/*matrix list `m3'*/

	local valLabelA : value label `var1'				/* row: value label name */
	/*display `"value label name for `var1' is: `valLabelA'"'*/	/* display it */
	local varLabelA : variable label `var1'				/* row: variable label */
	/*display `"variable label name for `var1' is: `varLabelA'"'*/	/* display it */
	local valLabelB : value label `var2'				/* col: value label name */
	/*display `"value label name for `var2' is: `valLabelB'"'*/	/* display it */
	local varLabelB : variable label `var2'				/* col: variable label */
	/*display `"variable label name for `var2' is: `varLabelB'"'*/	/* display it */

/* bgn by matrix */
	tempname X 
	tempname a 
	tempname b 
	tempname rX 
	tempname mX 
	tempname bX 
	tempname aX 

	tempname rXdim

	tempname otherrow
	
	tempvar rX1
	tempvar rX2
	tempvar rX3
	tempvar rXdim_row

matrix `X' = `m3'		/* from matcell() option done quietly above */

local d_row = rowsof(`X')
local d_col = colsof(`X')

/* create the _a_ & _b_ vector */
matrix `a' = J(`d_row',1,0)
matrix `b' = J(`d_row',1,1)

/* 2 by col tables loop */
foreach l of numlist 1/`d_row' { 
	matrix `a'[`l',1]=1
	matrix `b'[`l',1]=0
	
	matrix `aX' = `a''*`X'
	matrix `bX' = `b''*`X'
			/*matrix list `aX'*/
			/*matrix list `bX'*/
	
	matrix `mX' = `aX' \ `bX'
	/*matrix list `mX'*/
	
	local rows = 2 * `d_col'
	matrix `rXdim'=J(`rows',1,0)
	qui svmat `rXdim' , names(`"`rXdim_row'"')
	foreach i of numlist 1/3 {
	qui gen `rX`i''=.
	}
	matrix `rX'=J(`rows',3,0)
		foreach i of numlist 1/2 {
			foreach j of numlist 1/`d_col' {
				local r_i=`d_col'*(`i'-1)+`j'			
			 	qui replace `rX1'=`i' if _n==`r_i'
			 	qui replace `rX2'=`j' if _n==`r_i'
			 	qui replace `rX3'=`mX'[`i',`j'] if _n==`r_i'
			}
		}
		/*list `rX1' `rX2' `rX3' if `rXdim_row'==0*/	/* temp list variables for debug */

	/* handle orginal row levels vs other rows */
		if `m1'[`l',1] ~= . {
			local numeric_lvl = `m1'[`l',1]
			local lplusone=`numeric_lvl'+1
			qui recode `rX1' 1=`numeric_lvl' 2=`lplusone'
			local missing_row_flag = 0
			}
		else if `m1'[`l',1] == . {
			local numeric_lvl = `l'
			local lplusone=`numeric_lvl'+1
			qui recode `rX1' 1=`l' 2=`lplusone'
			local missing_row_flag = 1
			/*display `" here we are!! : missing_row_flag == `missing_row_flag' "'*/
			}
		else { 
			error 109
			}
		/*list `rX1' `rX2' `rX3' if `rXdim_row'==0*/	/* temp list variables for debug */

		if `"`valLabelA'"' ~= `""' {
			if `missing_row_flag'==0 {
				local valNameA : label `valLabelA' `numeric_lvl'  /* row: value label for level `l', from natural levels */
				display `"--> `valNameA' = : value level(`numeric_lvl')"'
				label define `otherrow' `numeric_lvl' `"`valNameA'"' `lplusone' `"all others"'
				}
			else {
				display `"--> _null_ = : value level(missing)"'
				label define `otherrow' `numeric_lvl' `"missing"' `lplusone' `"all others"'
				}
			label val `rX1' `otherrow'
			}
		else {
			if `missing_row_flag'==0 {
				display `"--> row `numeric_lvl' = : value level(`numeric_lvl')"'
				label define `otherrow' `numeric_lvl' `"row==`numeric_lvl'"' `lplusone' `"all others"'
				}
			else {
				display `"--> _null_ = : value level(missing)"'
				label define `otherrow' `numeric_lvl' `"missing"' `lplusone' `"all others"'
				}
			label val `rX1' `otherrow'			
			}


	/* handle orginal column levels each time `rX2' is defined, once for each row value */
		local recode_string = `""'

	if `"`valLabelB'"' ~= `""' {
		foreach j of numlist 1/`d_col' {
		if `m2'[1,`j'] ~= . {
			local numeric_col=`m2'[1,`j']
			local recode_string = `"`recode_string' `j'=`numeric_col'"'
 			local valNameB : label `valLabelB' `numeric_col'
			label define `rX2' `numeric_col' `"`valNameB'"',modify
			local prior_col_code = `numeric_col'	/* keep prior code for potential missing as stata missing is last */
			local missing_col_flag = 0
			}
		else if `m2'[1,`j'] == . {
			local numeric_col=`prior_col_code'+1
			local recode_string = `"`recode_string' `j'=`numeric_col'"'
			label define `rX2' `numeric_col' `"missing"',modify
			local missing_col_flag = 1
			/*display `" here we are!! : missing_col_flag == `missing_col_flag' "'*/
			}
		}
	}
	else {
		foreach j of numlist 1/`d_col' {
		if `m2'[1,`j'] ~= . {
			local numeric_col=`m2'[1,`j']
			local recode_string = `"`recode_string' `j'=`numeric_col'"'
			label define `rX2' `numeric_col' `"col==`numeric_col'"',modify
			local prior_col_code = `numeric_col'	/* keep prior code for potential missing as stata missing is last */
			local missing_col_flag = 0
			}
		else if `m2'[1,`j'] == . {
			local numeric_col=`prior_col_code'+1
			local recode_string = `"`recode_string' `j'=`numeric_col'"'
			label define `rX2' `numeric_col' `"missing"',modify
			local missing_col_flag = 1
			/*display `" here we are!! : missing_col_flag == `missing_col_flag' "'*/
			}
		}
	}

	qui recode `rX2' `recode_string'


	/*if `"`valLabelB'"' ~= `""' {*/
		label val `rX2' `rX2'
		/*}*/

	/* handle row variable name */
	if `"`varLabelA'"' ~= `""' {
		label var `rX1' `"`varLabelA'"'
		}
	else {
		label var `rX1' `"row"'
		}

	/* handle col variable name */
	if `"`varLabelB'"' ~= `""' {
		label var `rX2' `"`varLabelB'"'
		}
	else {
		label var `rX2' `"col"'
		}

	/* do the tabulate command for each row */
	if `"`rtabopts'"' == `""' {
		tabulate `rX1' `rX2' [freq=`rX3'] if `rXdim_row'==0
		}
	else {
		tabulate `rX1' `rX2' [freq=`rX3'] if `rXdim_row'==0, `rtabopts'
		local exactp = r(p_exact)			/* save the exact p*/
		return scalar exactp`l' = `exactp'
		}
	display `""'
	label drop `otherrow'
	capture noi label drop `rX2'
	drop `rX1' `rX2' `rX3' `rXdim_row' 
	/* reset the _a_ & _b_ vector */
	matrix `a' = J(`d_row',1,0)
	matrix `b' = J(`d_row',1,1)
} /* 2 by col tables loop */

matrix drop `X' `a' `b' `rX' `mX' `bX' `aX' `rXdim'
/* end by matrix */

end /* tarow */