### This file is part of the 'foreign' package for R.

#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  A copy of the GNU General Public License is available at
#  http://www.r-project.org/Licenses/

write.foreign <-
    function(df, datafile, codefile, package = c("SPSS","Stata","SAS"), ...)
{
    do.call(paste("writeForeign", package, sep = ""),
            c(list(df = df, datafile = datafile, codefile = codefile), ...))
    invisible(NULL)
}

## we want ASCII quotes, not UTF-8 quotes here
adQuote <- function(x) paste("\"", x, "\"", sep = "")



## FIXME: 
# - Missing values
# - Date/Time
# - character variables > 255 chars
# - wrapper to write .sav directly

writeForeignSPSS <- function(df, datafile, codefile, varnames = NULL, maxchars = 32L)
{
    ## FIXME: re-write this to hold a connection open
    dfn <- lapply(df, function(x) if (is.factor(x)) as.numeric(x) else x)
    write.table(dfn, file = datafile, row.names = FALSE, col.names = FALSE,
                sep = ",", quote = FALSE, na = "", eol = ",\n")

    varlabels <- names(df)
    if (is.null(varnames)) {
        varnames <- abbreviate(names(df), maxchars)
        if (any(vapply(varnames, nchar, 0L) > maxchars))
            stop("I cannot abbreviate the variable names to 'maxchars' or fewer chars")
        if (any(varnames != varlabels))
            warning("some variable names were abbreviated")
    }

    varnames <- gsub("[^[:alnum:]_\\$@#]", "\\.", varnames)

    dl.varnames <- varnames
    chv <- vapply(df, is.character, NA)
    fav <- vapply(df, is.factor, NA)
    if (any(chv)) {
        lengths <- vapply(df[chv],function(v) max(c(nchar(v), 8L), na.rm=TRUE), 0L)                         
        lengths <- paste0("(A", lengths, ")")
        dl.varnames[chv] <- paste(dl.varnames[chv], lengths)
    }
    if (any(fav)) {
        dl.varnames[fav] <- paste(dl.varnames[fav], "(F8.0)")  # Factor-Format    
    }    
    if (any(chv) || any(fav)) {
        ## actually the rule is: prepend a star if a variable with type/size declaration
        ## follows on a variable without declaration; no star for first variable or variables 
        ## following other variables with declarations
        star <- ifelse(c(FALSE, diff(chv | fav) == 1)[chv | fav], " *", " ")
        dl.varnames[chv | fav] <- paste(star,  dl.varnames[chv | fav])
    }
  
    cat("SET DECIMAL=DOT.\n\n", file = codefile) # required if SPSS runs in a locale with DECIMAL=comma
    cat("DATA LIST FILE=", adQuote(datafile), " free (\",\")\n",
        file = codefile, append = TRUE)
    ## formerly ENCODING="Locale" was used, but now "UTF8" is default encoding on all supported platforms
    cat('ENCODING="UTF8"\n', file = codefile, append = TRUE)

    ## No line longer than 251 chars:
    cat("/", paste(strwrap(paste(dl.varnames, collapse=" "), width=70), "\n"), " .\n\n", 
        file = codefile, append = TRUE)
    cat("VARIABLE LABELS\n", file = codefile, append = TRUE)
    cat(paste(varnames, adQuote(varlabels),"\n"), ".\n",
        file = codefile, append = TRUE)
    if (any(fav)) {
        cat("\nVALUE LABELS\n", file = codefile, append = TRUE)
        for(v in which(fav)){
            cat("/\n", file = codefile, append = TRUE)
            cat(varnames[v]," \n", file = codefile, append = TRUE, sep = "")
            levs <- levels(df[[v]])
            cat(paste(seq_along(levs), adQuote(levs), "\n", sep = " "),
                file = codefile, append = TRUE)
        }
        cat(".\n", file = codefile, append = TRUE)
    }

    ord <- vapply(df, is.ordered, NA)
    if(any(ord)) 
      cat("VARIABLE LEVEL", 
        paste(strwrap(paste(varnames[ord], collapse = ", "), width=70), "\n"), 
        "(ordinal).\n", file = codefile, append = TRUE)
    
    num <- vapply(df, is.numeric, NA)
    if(any(num)) 
      cat("VARIABLE LEVEL", 
        paste(strwrap(paste(varnames[num], collapse = ", "), width=70), "\n"), 
        "(scale).\n", file = codefile, append = TRUE)
    
    cat("\nEXECUTE.\n", file = codefile, append = TRUE)
}


writeForeignStata <- function(df, datafile, codefile)
{
    write.table(df, file = datafile, row.names = FALSE, col.names = FALSE,
                sep = ",", quote = FALSE, na = ".")
    nms <- names(df)
    factors <- vapply(df, is.factor, NA) | vapply(df, is.character, NA)
    formats <- paste(nms, "fmt", sep = "_")
    nms <- ifelse(factors, paste(nms,formats, sep = ":"), nms)

    cat("infile", nms, " using ", datafile,", automatic\n", file = codefile)
}
