*! version 1.0.0 2010-02-05 scott long and shawna rohrman

//  stata2pvd: take stata formatted data and save in pvd format
//  see www.indiana.edu\~jslsoc\pv.html

capture program drop stata2pvd
program define stata2pvd, rclass

    version 9.0

    syntax [varlist(default=none)]  ///  vars to extract
           [using/]                 ///  file to save results
           [if] [in]                ///  select obserations
           ,                        ///
           id(string)               ///  id variable
           CATlabels(string)        ///  string for category labels
           ITEMlabels(string)       ///  string for item labels
           [                        ///
           Miss                     ///  keep cases if they have missing data
           sort(string)             ///  sort data on specified variable or _all
           stable                   ///  use sort's stable option
           test                     ///  test mode on
           replace                  ///  replace if pvd file exists
           title(string)            ///  string for title
           ]

//  #1: decode variables to be kept and sorted

    if "`varlist'" == "" {
        display in red "error: you must specify variables to export."
        exit
    }
    unab varlist : `varlist'
    * remove the id variable from the varlist
    local varlist : subinstr local varlist "`id'" ""
    * number of non-id variables
    local nvars = wordcount("`varlist'")
    * varables to sort
    local nsort = length("`sort'") //
    if "`sort'"=="_all" {
        local sortvars "`varlist'"
        local nsort = `nvars'
    }

    * TEST
    if "`test'"=="test" {
        di "TEST 1"
        di "varlist:    `varlist'"
        di "sortvars:   `sortvars'"
        di "nvars:      `nvars'"
        di "# to sort:  `nsort'"
        di "ID var:     `id'"
    }

//  #2: select id variable

    capture confirm variable `id' // verify name is valid
    if !_rc { // variable is valid
    }
    else { // invalid id variable
        di in red "error: id variable `id' does not exist"
        exit
    }

//  #3: drop case with if and in

    if "`if'"!="" | "`in'"!="" {
        keep `if' `in'
    }

//  #4: drop missing

    if "`miss'"=="" {   // SLR 2009-11-23
        tempvar dropobs ismiss
        qui gen `dropobs' = 0 // drop this observation?
        qui gen `ismiss' = . // is missing for given variable?
        foreach v in `varlist' `id' {
        	qui destring `v', force replace
            qui replace `ismiss' = (`v'>=.) // test if missing
            qui sum `ismiss' // compute how many are missing
            local nmiss = r(N)* r(mean)
            qui replace `dropobs' = 1 if `ismiss'==1
        }
        qui sum `dropobs'
        drop if `dropobs'==1
        local totalmiss = r(N)* r(mean)
        di "Note: `totalmiss' cases dropped due to missing data."
    }
    else if "`miss'"=="miss" { // do nothing, keep missing
    }

//  #5 construct list of variables used for sorting

    if `nsort'>0 {
        if "`sort'"!="_all" { // if all, sortvars already created
            local i 1
            local sortvars ""
            * loop through sort options & build list of sort vars
            while `i' <= `nsort' {
                local sortstatus = substr("`sort'",`i',1)
                if "`sortstatus'"=="y" {
                    local addvar = word("`varlist'",`i')
                    local sortvars "`sortvars' `addvar'"
                }
                local ++i
            } // loop through sort variables
        }

        * TEST
        if "`test'"=="test" {
            di "sortvars: `sortvars'"
            di "pre-sort"
            list `varlist' in 1/5, nol compress clean
        }

        * sort the data
        sort `sortvars', `stable'
        di _n "Note: data is sorted by: `sortvars'"
        * TEST
        if "`test'"=="test" {
            di "post-sort"
            list `varlist' in 1/5, nol compress clean
        }
    }

//  #6 check labels

    local outl = wordcount("`catlabels'")
    local iteml = wordcount("`itemlabels'")
    if `iteml'!=`nvars' {
        di in red "error: number of item labels (now `iteml') must equal the"
        di in red "number of items (now `nvars')."
        exit
    }
    * determine how many outcome labels needed
    local maxout = 0
    foreach v in `varlist' {
        qui sum `v'
        local no = r(max)-r(min)+1
        if `no'>`maxout' {
            local maxout = `no'
            * TEST
            if "`test'"=="test" {
                di in red "For `v', # of categories is `maxout'."
            }
        }
    }
    if `outl'!=`maxout' {
        di in red "error: number of categories labels (now `outl') must equal the"
        di in red "number of categories in varaibles (`maxout')."
        exit
    }

//  #7 check label lengths

    local outok = 1
    foreach l in `catlabels' {
        local ln = length("`l'")
        if `ln'>11 {
            local outok = 0
        }
    }
    local itemok = 1
    foreach l in `itemlabels' {
        local ln = length("`l'")
        if `ln'>11 {
            local itemok = 0
        }
    }
    if `outok'==0 | `itemok'==0 {
        di
        if `outok'==0 {
            di in red "error: category labels must be 11 or fewer characters."
        }
        if `itemok'==0 {
            di in red "error: item labels must be 11 or fewer characters."
        }
        exit
    }

//  #8 outsheet data

    if "`using'"=="" {
        di in red "error: you must specify a dataset with the using option"
        exit
    }
    local myfile "`using'.pvd"
    if "`using'"!="" {
        capture file close myfile
        * number of rows
        local N = _N
        * open pvd file
        file open myfile using `using'.pvd, write replace
        if "`title'"!="" {
            file write myfile _col(1) "# `title'" _newline
        }
        file write myfile _col(1) "#" _newline
        file write myfile _col(1) "# Category labels" _newline
        file write myfile _col(1) "#" _newline
        file write myfile _col(1) "`catlabels'" _newline
        file write myfile _col(1) "#" _newline
        file write myfile _col(1) "# Item labels excluding id" _newline
        file write myfile _col(1) "#" _newline
        file write myfile _col(1) "`itemlabels'" _newline
        file write myfile _col(1) "#" _newline
        file write myfile _col(1) "# Data" _newline
        file write myfile _col(1) "#" _newline
        forvalues i = 1/`N' {
            local idv = `id'[`i']
            file write myfile _col(1) "`idv'"
            local c = 6
            foreach v in `varlist' {
                local c = `c' + 4
                local x = `v'[`i']
                file write myfile _col(`c') "`x'"
            }
            file write myfile _newline
        }
        file close myfile
    } // if using

    di _new "`myfile' written with header and `N' paths."

end
exit
*! version 0.3.1 2009-05-21 jsl
*! version 0.3.2 2009-11-23 slr Changes to missing