*! version 0.1.4v2 2012-08-17 08.09 fixed name within file
* version 0.1.4 2011-06-03 renamed statout1; eq name version now officialx
* version 0.1.4 2011-06-03 changed to statout
* version 0.1.3 2011-05-31 changed to x_statout
* version 0.1.2 2011-04-04 use _clct_ListMatrix.ado
* version 0.1.1 2011-04-01 gen stub fix
* version 0.1.0 2011-02-17 initial conversion
*  - scott long and jd wolfe: outputing matrices

*! bug: statout, rdrop(_all) list
*! bug: statout, ckeep(6-5)

capture clear programs
program define statout1

    version 10.1

//  #1 syntax

    syntax [anything] ,[    /// analysis matrix name in local MATname
                            /// Default name: StatSto<moutcome>
///
        ROWs(string)        /// was rownames (_all for all b's)
        blank               /// add a blank row
/// matrix utilities - subset of statout
        clear               /// reset matrix to null
        DECimals(numlist >-1 integer) /// digits when list matrix
        Format(string)      /// format for matrix
        list                /// list matrix
        LISTNew             /// list new ropws
        mv(string)          /// default missing value
        preview             /// preview changes but don't change matrix
        save(string)        /// save matrix to new matrix
        title(string)       /// title added when listing
        TRANspose           /// list/save transposed matrix
        WIDth(numlist >0 integer) /// width when listing matrix
///
        GENerate(string)  GENStub(string)       ///
        CDROp(string)   RDROp(string)   CKEEp(string) RKEEp(string) ///
        CORDer(string)  RORDer(string)  CNUMber       RNUMber       ///
        RREName(string) CREName(string) CALPha        RALPha        ///
        ROWNames COLNames ///
        debug debug2 debug3 ///
     ]

    tempname MATcolnull MATrownull Bvalues MATCOL NEWvals MAT_NEW
    tempname MATwork    tempmat

//  #1: decode syntax

    * preview turns on list
    if ("`preview'"=="preview") local list "list"

    * if transpose this implies list
    if ("`transpose'"=="transpose") local list "list"

    * doLIST: list or list new specified?
    local doLIST = 0
    if ("`list'"=="list" | "`listnew'"=="listnew") local doLIST = 1

    * doROWCOL: row column modifications?
    local doROWCOL = 0
    if "`cnumber'"=="cnumber" | "`corder'"!="" | "`cdrop'"!="" ///
      |"`rnumber'"=="rnumber" | "`rorder'"!="" | "`rdrop'"!="" ///
      |"`rrename'"!="" | "`calpha'"!="" | "`ckeep'"!="" ///
      |"`crename'"!="" | "`ralpha'"!="" | "`rkeep'"!="" {
        local doROWCOL = 1
    }

//  #2 trap errors

    local iserror = 0

    if "`corder'"!="" & "`cdrop'"!="" {
        di as error ///
        "Options corder() and cdrop() cannot be in the same command."
        local iserror = 1
    }

    if "`rorder'"!="" & "`rdrop'"!="" {
        di as error ///
        "Options rorder() and rdrop() cannot be in the same command."
        local iserror = 1
    }

    if "`corder'"!="" & "`ckeep'"!="" {
        di as error ///
        "Options corder() and ckeep() cannot be in the same command."
        local iserror = 1
    }

    if "`cdrop'"!="" & "`ckeep'"!="" {
        di as error ///
        "Options cdrop() and ckeep() cannot be in the same command."
        local iserror = 1
    }
    if "`rdrop'"!="" & "`rkeep'"!="" {
        di as error ///
        "Options rdrop() and rkeep() cannot be in the same command."
        local iserror = 1
    }

    if "`rorder'"!="" & "`rkeep'"!="" {
        di as error ///
        "You cannot used rorder() and rkeep() in the same snag command."
        local iserror = 1
    }

    if (`iserror'==1) exit

//  #3 format and missing values

    * same as in statsto.ado
    local mvis "."
    if "`mv'"!="" & "`mv'"!="." {
        if length("`mv'")>1 {
            di as error "mv() must be a period or a single letter."
            exit
        }
        local mv = lower("`mv'")
        local mvis ".`mv'"
    }
    local mv "`mvis'"

    * format for listing matrix
    if ("`decimals'"!="" | "`width'"!="") & "`format'"=="" {
        if ("`decimals'"=="")   local decimals "0"
        if ("`width'"=="")      local width "10"
        if (`decimals'>`width') local width = `decimals' + 1
        local format "%`width'.`decimals'f"
    }


    local mvis "."
    if "`mv'"!="" & "`mv'"!="." {
        if length("`mv'")>1 {
            di as error "mv() must be a period or a single letter."
            exit
        }
        local mv = lower("`mv'")
        local mvis ".`mv'"
    }
    local mv "`mvis'"

* does matrix exist
*    capture confirm matrix `matrixin'
*    if _rc>0 local MATRIXexists = 0
*      else  local MATRIXexists = 1

//  #6 set up matrices

* SS MATname == snag MATstart (name of matrix)
* SS CMAT    == snag MATwork

    tempname MATwork nullmat
    matrix `nullmat' = J(1,1,`mv')
    matrix colnames `nullmat' = _N_u_l_l_
    matrix rownames `nullmat' = _N_u_l_l_
    * name of matrix for results
    if ("`anything'"=="") local MATstart "StatSto"
    else                  local MATstart "`anything'"
    * does collection matrix exist?
    capture matrix list `MATstart'
    if _rc ~= 0 { // no matrix in memory
        matrix `MATwork' = `nullmat'
        matrix `MATstart' = `nullmat' // in case clear is used
    }
    else matrix `MATwork' = `MATstart'
    if ("`clear'"=="clear") matrix `MATwork' = `nullmat'

/* Not needed in statoutif `ANYis'==0 & `MATRIXis'==0 {

*! #6.1: why is MATrownum needed?
        local MATrownum = 1
        * list now if no collection so that statout doesn't have to be used
        if `LISTis' {
            _clct_ListMatrix, matprint(`MATwork') matname(`MATstart') ///
              matrownum(`MATrownum') `list' `transpose' `listnew' ///
              `preview' format(`format') title(`title')
        }
        * clear deletes matrix if nothing is being added
        if "`clear'"=="clear" capture matrix drop `MATstart'
        exit
    }
*/

* MATname == old MATstart
* CMAT    == old MATwork
//  name and information about results matrix
//      old `MATwork' is temporary matrix being modified
//      old `MATstart' is name of results matrix
//      old If preview option not used, `MATstart' is update to `MATwork'

    * does matrix exist?
    local MATstartexists = 1
    capture matrix list `MATstart'
    if (_rc ~= 0) local MATstartexists = 0
    if (`MATstartexists') matrix `MATwork' = `MATstart'

    * clear matrix
    if ("`clear'"=="clear") capture matrix drop `MATwork'

    * does matrix exist?
    local MATexists = 1
    capture matrix list `MATwork'
    if (_rc ~= 0) local MATexists = 0
    * matrix exists, but is it null
    else {
        local isnull = 0
        local rowsN = rowsof(`MATwork')
        local colsN = colsof(`MATwork')
        local colNMS : colnames `MATwork'
        local NULLcheck : word 1 of `colNMS'
        if `rowsN'==1 & `colsN'==1 & "`NULLcheck'"=="NULL" {
            local MATexists = 0
        }
    }

//  #6 change rows and columns

    * rename
    if "`rrename'"!="" & `MATexists' {
         RowColRename, list(`rrename') row_col(row) matnm(`MATwork')
    }
    if "`crename'"!="" & `MATexists' {
         RowColRename, list(`crename') row_col(col) matnm(`MATwork')
    }

    * change row or column names by numbering them
    if ("`rnumber'"=="rnumber" | "`cnumber'"=="cnumber") ///
         & `MATexists' {
        local rowNMS : rownames `MATwork'
        local colNMS : colnames `MATwork'
        if "`rnumber'"=="rnumber" {
            local newrowNMS ""
            local i = 0
            foreach nm in `rowNMS' {
                local ++i
                local newrowNMS "`newrowNMS' `i'_`nm'"
            }
            matrix rownames `MATwork' = `newrowNMS'
        }
        if "`cnumber'"=="cnumber" {
            local newcolNMS ""
            local i = 0
            foreach nm in `colNMS' {
                local ++i
                local newcolNMS "`newcolNMS' `i'_`nm'"
            }
            matrix colnames `MATwork' = `newcolNMS'
        }
    }

    * drop rows
    if "`rdrop'"!="" & `MATexists' {
        RowColList, rclist(`rdrop') matnm(`MATwork') row_col(row)
        local dropindex `s(RCindex)'
        local error = s(error)
        if (`error'==1) exit
        RowColList, rclist(_all) matnm(`MATwork') row_col(row)
        local MATindex `s(RCindex)'
        local rowskeep : list MATindex - dropindex
        RowReorder, order(`rowskeep') matrix(`MATwork')
    }

    * drop columns
    if "`cdrop'"!="" & `MATexists' {
        RowColList, rclist(`cdrop') matnm(`MATwork') row_col(col)
        local dropindex `s(RCindex)'
        local error = s(error)
        if (`error'==1) exit
        RowColList, rclist(_all) matnm(`MATwork') row_col(col)
        local MATindex `s(RCindex)'
        local colskeep : list MATindex - dropindex
        ColReorder, order(`colskeep') matrix(`MATwork')
    }

    * keep columns
    if "`ckeep'"!="" & `MATexists' {
        RowColList, rclist(`ckeep') matnm(`MATwork') row_col(col)
        local keepindex `s(RCindex)'
        local error = s(error)
        if (`error'==1) exit
        ColReorder, order(`keepindex') matrix(`MATwork')
    }

    * keep rows
    if "`rkeep'"!="" & `MATexists' {
        RowColList, rclist(`rkeep') matnm(`MATwork') row_col(row)
        local keepindex `s(RCindex)'
        local error = s(error)
        if (`error'==1) exit
        RowReorder, order(`keepindex') matrix(`MATwork')
    }

    * rearrange columns
    if "`corder'"!="" & `MATexists'==1 {
        RowColList, rclist(`corder') matnm(`MATwork') row_col(col)
        local corder `s(RCindex)'
        local error = s(error)
        if (`error'==1) exit
        ColReorder, order(`corder') matrix(`MATwork')
    }

    * rearrange rows
    if "`rorder'"!="" & `MATexists'==1 {
        RowColList, rclist(`rorder') matnm(`MATwork') row_col(row)
        local rorder `s(RCindex)'
        local error = s(error)
        if (`error'==1) exit
        RowReorder, order(`rorder') matrix(`MATwork')
    }

    * alphabetize rows
    if "`ralpha'"!="" & `MATexists'==1 {
        local rowalpha : rownames `MATwork'
        local rowalpha : list sort rowalpha
        foreach nm in `rowalpha' {
            GetRowIndex, name(`nm') matrix(`MATwork')
            local MATrownum `s(MATrownum)'
            matrix `tempmat' = nullmat(`tempmat') \ `MATwork'[`MATrownum',1...]
        }
        matrix `MATwork' = `tempmat'
    }

    * alpha ordering of columns
    if "`calpha'"!="" & `MATexists'==1 {
        local colalpha : colnames `MATwork'
        local colalpha : list sort colalpha
        foreach nm in `colalpha' {
            GetColIndex, name(`nm') matrix(`MATwork')
            local MATcolnum `s(MATcolnum)'
            matrix `tempmat' = nullmat(`tempmat') , `MATwork'[1...,`MATcolnum']
        }
        matrix `MATwork' = `tempmat'
    }

//  #12b: add a blank row to matrix

    if "`blank'"!="" {
        local MATcolsN = colsof(`MATwork')
        matrix `MATrownull' = J(1,`MATcolsN',`mv')
        matrix rownames `MATrownull' = "- - - -"
        matrix `MATwork' = (`MATwork') \ (`MATrownull')
    }

//  #13: list matrix

    *! if null say so and don't list; if no added, no listnew
* 0.1.2 2011-04-04
    _clct_ListMatrix, matprint(`MATwork') matname(`MATstart') ///
        `list' `transpose' `listnew' ///
        format(`format') matrownum(`MATrownum') title(`title') ///
        `preview'

//  #14: generate variables

    if "`generate'"!="" {
        local MATgen "`MATwork'"
        tempname MATtran
        if "`transpose'"=="transpose" {
            matrix `MATtran' = `MATwork''
            local MATgen "`MATtran'"
        }
        * replace _all with 1-Max#
        if "`generate'"=="_all" {
            local Ncol = colsof(`MATgen')
            local generate "1-`Ncol'"
        }
        *GenerateVars, gen(`generate') stub("`stub'") matnm(`MATgen')
        GenerateVars, gen(`generate') matnm(`MATgen') stub(`genstub')
    }

//  #16: save matrix

    if "`save'"!="" {
        capture matrix list `save'
        if _rc==0 {
            di as error ///
            "The matrix `save' already exists. Chose another name."
            di as error ///
            "Use -matrix drop <name> to delete an existing matrix."
        }
        else {
            if ("`transpose'"=="transpose") matrix `save' = `MATwork''
            else matrix `save' = `MATwork'
            di as result "Matrix `save' was created."
        }
    }

//  #17: post matrix change

    if ("`preview'"=="") matrix `MATstart' = `MATwork'

//  #xx list names

    if "`colnames'"=="colnames" {
        local colnms : colnames `MATstart'
        di "Column names:"
        di "`colnms'"
    }
    if "`rownames'"=="rownames" {
        local rownms : rownames `MATstart'
        di "Row names:"
        di "`rownms'"
    }

end // END of SNAG

//  AUXILLARY ADO FILES ====================================================

//SO  ColReorder
//SO  RowColRename
//SO  GetColIndex
//SO  GetRowIndex
//SO  RowColList
//SO  RowReorder

/*
* 0.1.2 use _clct_ListMatrix
//  SO ListMatrix
//
//  2010-07-24 test option added

program ListMatrix, sclass

    syntax , matprint(string) matstart(string) ///
            [ preview list transpose listnew format(string) ///
            matrownum(string) title(string) ]

    if ("`preview'"=="preview") local Ltitle "Preview of `matstart': "
    else                  local Ltitle "Results matrix `matstart': "

    if "`list'"=="list" {
        if "`transpose'"=="transpose" {
            matrix `matprint' = `matprint''
            if ("`title'"=="") local Ltitle "`Ltitle'Transposed matrix"
            else               local Ltitle "`title'"
            di _newline "`Ltitle'" // _continue
            matrix list `matprint', title(`Ltitle') ///
                format(`format') nohalf noheader
            matrix `matprint' = `matprint''
        }
        else {
            if ("`title'"=="") local Ltitle "`Ltitle'"
            else               local Ltitle "`title'"
            di _newline "`Ltitle'" // _continue
           matrix list `matprint', title(`title') ///
                format(`format') nohalf noheader
        }
    }

//  list current row

    if "`listnew'"=="listnew" {
        matrix SNAG_current_row = `matprint'[`matrownum',1...]
        if ("`preview'"=="preview") local title "`Ltitle'Preview of row changes"
        else                  local title "`Ltitle'Modified row"
        di _newline "`title'"
        matrix list SNAG_current_row, title(`title') ///
                format(`format') noheader
        matrix drop SNAG_current_row
    }

end
*/

//  SO ColReorder: rearrange columns in a matrix
//
//  input:  matrix(name of matrix)
//          order(new column order): numbers corresponding to columns; numbers
//              larger than max column are ignored; duplicates allowed.
//  output: revised matrix with same name
//
//  2010-08-25 renamed to reoder; corder() to order

program ColReorder, sclass

    syntax , matrix(string) order(string)
    tempname MATnew
    local MATnm "`matrix'"
    local MATcolsN  = colsof(`MATnm')
    local MATcolNMS : colnames `MATnm'
    local NEWcolN   : word count `order'
    local NEWcolNMS ""

    local isfirst = 1
    foreach icol in `order' {
        * ignore values that are too large
        if `icol'<=`MATcolsN' {
            local nm : word `icol' of `MATcolNMS'
            local NEWcolNMS "`NEWcolNMS' `nm'"
            if `isfirst'==1 {
                matrix `MATnew' = `MATnm'[1...,`icol']
                local isfirst = 0
            }
            else matrix `MATnew' = `MATnew',`MATnm'[1...,`icol']
        }
    }
    matrix `MATnm' = `MATnew'
    *di "NEWcolNMS: `NEWcolNMS'"

end

//  SO RowColRename: rename rows or columns
//
//  input:   list(string)       oldname=newname... or newnames....
//           row_col(string)    is row or col
//           matnm(string)      name of matrix
//           s(error)
//
//  2010-07-19

program RowColRename, sclass

    syntax , list(string) row_col(string) matnm(string)
    sreturn clear

    if "`row_col'"=="row" {
        local nownames : rownames `matnm'
        local RCnm "row"
        local RCNm "Row"
        local RCname "row"
        local RCName "Row"
        local RCodd "rrename()"
    }
    else if "`row_col'"=="col" {
        local nownames : colnames `matnm'
        local RCnm "col"
        local RCNm "Col"
        local RCname "column"
        local RCName "Column"
        local RCodd "crename()"
    }
    else {
        di as error "RowColRename requires row_col(row|col)."
        sreturn local error = 1
        exit
    }

//  does list have = in it

    local list : subinstr local list "=" " = ", all
    local isEqual : list posof "=" in list
    local isEqual = `isEqual'>0

//  no equal sign

    if `isEqual'==0 {
        local listN : word count `list'
        local nowN  : word count `nownames'
        if `listN'!=`nowN' {
            di as error ///
"You must have one name for each `RCname' or have oldname=newname pairs."
            sreturn local error = 1
            exit
        }
        * change the names
        matrix `RCnm'names `matnm' = `list'
    }

// decode oldname=newname list

    if `isEqual'==1 {
        * get rid of =
        local list : subinstr local list "=" " ", all
        local listN : word count `list'
        * must have even number of items
        local listpairsN = `listN'/2
        capture confirm integer number `listpairsN'
        if _rc>0 {
            di as error ///
        "`RCodd' using = must have matched pairs of names."
            sreturn local error = 1
            exit
        }
        * get two sets of names
        local Nminus1 = `listN'-1
        local oldnames ""
        local newnames ""
        forvalues i = 1(2)`Nminus1' {
            local oldnm : word `i' of `list'
            local j = `i' + 1
            local newnm : word `j' of `list'
* 0.0.2b            _snag_Find`RCNm', name(`oldnm') matrix(`matnm')
            * 0.0.3
            Get`RCNm'Index, name(`oldnm') matrix(`matnm')
            local rcnum `s(MAT`RCnm'num)'
*? di "rcnum: `rcnum'"
            if `rcnum'==0 {
                di as error ///
                "`oldnm' is not a current `RCname' name."
                sreturn local error = 1
                exit
            }
            else {
                * 0.0.4 (add option, word)
                local nownames : subinstr local nownames "`oldnm'" "`newnm'", word
            }
        }
        matrix `RCnm'names `matnm' = `nownames'
    } // has equals

    sreturn local error = 0

end

//  EstStatCompute: compute statistics from estimate and Var(estimate)
//
//  input:  b(estimate)
//          v(variance of estimate)
//
//  output: Matrix:   _MAT_eststats
//          Column:   1 2  3 4 5  6 7  8  9
//          Contains: b se z t df p lb ub level
//
//  2010-07-07

program EstStatCompute, sclass

    syntax , b(real) v(real)
    tempname zlevel z df ub lb level B se p zlevel

    * matrix to hold results
    matrix _MAT_eststats = J(1,9,.m)
    matrix colnames _MAT_eststats = b se z t df p lb ub level

    * grab information needed for computations
    local cmd = e(cmd)
    scalar `B' = `b'
    matrix _MAT_eststats[1,1] = `B'
    local df = .
    capture local df = e(df_r) // df for t-test
    local level = $S_level // level for CI

    * compute and store results
    matrix _MAT_eststats[1,5] = `df'
    matrix _MAT_eststats[1,9] = `level'
    local plevel = ( 1 - (`level'/100) )/2  // corresponding p-value

    * zlevel for CI's
    if ("`cmd'"=="regress") scalar `zlevel' = abs(invttail(`df',`plevel'))
    else                    scalar `zlevel' = abs(invnormal(`plevel'))

    * test estimate is 0
    scalar `se' = sqrt(`v')
    matrix _MAT_eststats[1,2] = `se'
    scalar `z' = `B'/`se'
    if "`cmd'"=="regress" {
        scalar `p' = 2*ttail(`df',abs(`z'))
        matrix _MAT_eststats[1,6] = `p'
        matrix _MAT_eststats[1,4] = `z' // is t-test
    }
    else {
        scalar `p' = 2*(1-normal(abs(`z')))
        matrix _MAT_eststats[1,6] = `p'
        matrix _MAT_eststats[1,3] = `z'
    }

    * bounds
    scalar `lb' = `B' - (`zlevel'*`se')
    matrix _MAT_eststats[1,7] = `lb'
    scalar `ub' = `B' + (`zlevel'*`se')
    matrix _MAT_eststats[1,8] = `ub'

end

//  SO GetColIndex: find column number given column label
//
//  input:  name(name of column label)
//          matrix(name of matrix)
//
//  output: s(MATcolnum): column number in matrix
//
//  2010-07-10 GetColIndex.ado

program GetColIndex, sclass

    syntax , name(string) matrix(string)
    sreturn clear
    local MATcolNMS : colnames `matrix'
    local MATcolnum : list posof "`name'" in MATcolNMS
    sreturn local MATcolnum `"`MATcolnum'"'

end

// SO  GetRowIndex: find row number given row label
//
//  input:  name(name of row label)
//          matrix(name of matrix)
//
//  output: s(MATrownum): row number in matrix
//          s(MATaddrow): 1 if new row needed, else 0
//
//  0.1.2 2010-07-10 GetRowIndex.ado

program GetRowIndex, sclass

    syntax , name(string) matrix(string)
    sreturn clear
    local MATaddrow = 1
    local MATrowNMS : rownames `matrix'
    * position in rownames
    local MATaddrow = 0
    local MATrownum : list posof "`name'" in MATrowNMS

*di in red "MATrowNMS: |`MATrowNMS'|"
*di "MATrownum: `MATrownum'"

    if (`MATrownum'==0) local MATaddrow = 1
    sreturn local MATaddrow `"`MATaddrow'"'
    sreturn local MATrownum `"`MATrownum'"'

end

//  SO GenerateVars: create variables from columns of SNAG matrix
//
//  input:  matnm(string): name of matrix
//          gen(string)  : SNAG style list of columns to be generated
//  output: s(Gvarnames) : names of geneated variables
//          s(Gcolnames) : column names from results matrix
//          s(Gcolindex) : column indices from results matrix
//          s(error)     : 0 or 1
//
//  2010-07-21 stub in gen string
//  2011-04-01 fix how stub is added

program GenerateVars, sclass
    syntax , matnm(string) gen(string) [ stub(string) ]
    sreturn clear

*    local stub `s(optpost)' // stub string
*    local stub : subinstr local stub "stub(" "", all
*    local stub : subinstr local stub ")" "", all
*    local stub : subinstr local stub " " "", all
*    if ("`stub'"==".") local stub ""

// parse inputs selecting varaibles to generats

    RowColList, rclist("`gen'") matnm(`matnm') row_col(col)
    local error = s(error)
    if `error'==1 {
        sreturn local error = 1
        exit
    }
    local Gcolindex `s(RCindex)'
    local Gcolnames `s(RCnames)'

    * add stub to variables names
    if "`stub'"!="" {
        local Gvarnames ""
        foreach nm in `Gcolnames' {
            local Gvarnames "`Gvarnames' `stub'`nm'"
        }
    }
    else local Gvarnames "`Gcolnames'"

    * temporary matrix with data to be generated
    tempname MATgen
    local Nrow = rowsof("`matnm'")
    local Ncol = wordcount("`Gvarnames'")
    local cnum = 0
    foreach col in `Gcolindex' {
        local ++cnum
        matrix `MATgen' = nullmat(`MATgen') , `matnm'[1...,`col']
    }

    * change columns to variables names and create variables from matrix
    matname `MATgen' "`Gvarnames'", col(1...) explicit
    qui svmat `MATgen', names(col)
    if _rc>0 {
        di as error ///
    "svmat encountered problems with matrix `MATgen'"
        local error = 1
        exit
    }

    sreturn local Gcolindex `"`Gcolindex'"'
    sreturn local Gcolnames `"`Gcolnames'"'
    sreturn local Gvarnames `"`Gvarnames'"'
    sreturn local error = `error'

end

//  SO RowColList: decode row and columun selection
//
//  input:   rclist(string) : list of rows and columns
//           row_col(string): row or column
//           matnm(string)  : name of matrix
//
//  output:  s(RCindex)     : index numbers of selected rows or columns
//           s(RCnames)     : names of selected rows or columns
//           s(error)       : 0 or 1
//
//  syntax of list: # name #-# name-name #-name name-#
//
//  2010-07-24 allow _all

program RowColList, sclass

    syntax , rclist(string) row_col(string) matnm(string)
    local error 0

    if "`row_col'"!="row" & "`row_col'"!="col" {
        di as error "row_col() must be either row or col."
        sreturn local error = 1
        exit
    }
    if ("`row_col'"=="row") local RCname "Row"
    if ("`row_col'"=="col") local RCname "Column"
    if ("`row_col'"=="row") local rcname "row"
    if ("`row_col'"=="col") local rcname "column"

    * get row or column information
    local matnames : `row_col'names `matnm'
    local matnamesN : word count `matnames'

    if ("`rclist'"=="_all") local rclist "1-`matnamesN'"

    * make - a seperate word
    local rclist : subinstr local rclist "  " " ", all
    local rclist : subinstr local rclist "-" " - ", all
    local rclist : subinstr local rclist "  " " ", all

    local RCnames ""    // names of selected columns or rows
    local RCindex ""    // index of selected rows or columns

    * change words to numbers in list
    local numlist ""
    local wordsN : word count `rclist'
    foreach w in `rclist' {
        capture confirm integer number `w'
        if _rc==0 {
            if `w'<=`matnamesN' {
                local numlist "`numlist' `w'"
            }
            else {
                di as error "`RCname' number is too large given matrix's dimensions."
                local error =1
                continue, break
            }
        }
        else {
            local iloc : list posof "`w'" in matnames
            if (`iloc'>0) local numlist "`numlist' `iloc'"
            else if ("`w'"=="-") local numlist "`numlist' -"
            else {
                di as error "`RCname' name `w' is not in matrix."
                local error = 1
                continue, break
            }
        }
    }
    if `error'==1 {
        sreturn local error = 1
        exit
    }

// parse # and #-#

    local iword = 1
    local nextword = 1
    while `iword' <= `wordsN' {

        * note: L-R corresonds to Wleft Wminus Wright
        local Wleft : word `iword' of `numlist'
        local Wleftword = `iword'

        * get word that will be = if entery is of form a=b
        if `iword' < `wordsN' {
            local ++iword
            local Wminus : word `iword' of `numlist'
        }
        else local Wminus "dog" // it isn't minus!

        * if -, get word on right
        if "`Wminus'"=="-" {
            local nextword = `iword' + 2 // plus 2 since Wminus and Wright used
            local ++iword
            if (`iword' <= `wordsN') local Wright : word `iword' of `numlist'
            else {
                di as error "A name or value must follow - in list."
                local error =1
                continue, break
            }
            forvalues i = `Wleft'(1)`Wright' {
                local RCindex "`RCindex' `i'"
            }
        } // is - sign

        * is not - sign
        else {
            local nextword = `Wleftword' + 1 // only one word used to specify value
            local RCindex "`RCindex' `Wleft'"
        }

        local iword = `nextword'

    } // loop through option words

    if `error'==1 {
        sreturn local error = 1
        exit
    }

    foreach i in `RCindex' {
        local nm : word `i' of `matnames'
        local RCnames "`RCnames' `nm'"
    }

    sreturn local RCindex `"`RCindex'"'
    sreturn local RCnames `"`RCnames'"'
    sreturn local error = `error'

end

//  SO RowReorder: reorder rows in a matrix
//
//  input:  matrix(name of matrix)
//          order(new row order): numbers corresponding to rows; numbers
//              larger than max row are ignored; duplicates allowed.
//
//  output: revised matrix with same name
//
//  2010-07-07 renamed to reorder; rorder() to order()

program RowReorder, sclass

    syntax , matrix(string) order(string)
    tempname MATnew
    local MATnm "`matrix'"
    local MATrowsN  = rowsof(`MATnm')
    local MATrowNMS : rownames `MATnm'
    local NEWrowN   : word count `order'
    local NEWrowNMS ""

    local isfirst = 1
    foreach irow in `order' {
        * ignore values that are too large
        if `irow'<=`MATrowsN' {
            local nm : word `irow' of `MATrowNMS'
            local NEWrowNMS "`NEWrowNMS' `nm'"
            if `isfirst'==1 {
                matrix `MATnew' = `MATnm'[`irow',1...]
                local isfirst = 0
            }
            else matrix `MATnew' = `MATnew' \ `MATnm'[`irow',1...]
        }
    }
    matrix `MATnm' = `MATnew'

end

// End of statout
exit