.packageName <- "gmt"
"deg2num" <-
function(x)
{
  is.digit <- function(x)
  {
    !is.na(as.numeric(x))
  }

  if(length(x) > 1)
    sapply(x, deg2num)  # recursive solution, to support different formats for different elements
  else
  {
    ## 1 Determine sign (positive or negative)
    first.char <- substring(x, first=1, last=1)
    if(first.char == "-")
      sign <- -1
    else if(is.digit(first.char))
      sign <- 1
    else
      stop("First character must be \"-\" or number.")

    ## 2 Look at last character: cut it off if W|E|S|N and change sign if W|S
    last.char <- substring(x, first=nchar(x), last=nchar(x))
    if(last.char=="W" || last.char=="E" || last.char=="S" || last.char=="N")
    {
      string <- substring(x, first=1, last=nchar(x)-1)
      if(last.char=="W" || last.char=="S")
        sign <- -sign
    }
    else if(is.digit(last.char))
      string <- as.character(x)
    else
      stop("Last character must be W, E, S, N, or number")

    ## 3 Split string at colons, convert to decimals, and catch split errors
    splits <- unlist(strsplit(string, ":"))
    if(length(splits)==1 && all(is.digit(splits)))
      value <- sign * abs(as.numeric(splits[1]))
    else if(length(splits)==2 && all(is.digit(splits)))
      value <- sign * (abs(as.numeric(splits[1])) + as.numeric(splits[2])/60)
    else if(length(splits)==3 && all(is.digit(splits)))
      value <- sign * (abs(as.numeric(splits[1])) + as.numeric(splits[2])/60 + as.numeric(splits[3])/3600)
    else
      stop("Unable to interpret geographic coordinates. See Appendix B.1.1 in GMT manual for correct formats.")

    return(value)
  }
}

"geodist" <-
function(Nfrom, Efrom, Nto, Eto, units="km")
{
  units <- match.arg(units, c("km","nm"))

  rad <- 180 / pi

  N1 <- Nfrom / rad
  E1 <- Efrom / rad
  N2 <- Nto   / rad
  E2 <- Eto   / rad

  duplicates <- N1==N2 & E1==E2
  N1[duplicates] <- 0            # When origin and destination are the same,
  E1[duplicates] <- 0            #   set them both to 0, 0
  N2[duplicates] <- 0            # Without this, geodist(48.535, 48.535, 124, 124) returns NaN,
  E2[duplicates] <- 0            #   but geodist(0, 0, 0, 0) seems to return 0 on all machines

  radians <- acos(sin(N1)*sin(N2)+cos(N1)*cos(N2)*cos(E1-E2))

  if(units == "km")
    distance <- 60 * rad * radians * 1.852
  else
    distance <- 60 * rad * radians

  return(distance)
}

"gmt" <-
function(par, style="s", file="map.eps", quiet=FALSE)
{
  if(!missing(par))
  {
    gmt.system(paste("gmtdefaults -D",style,sep=""), file=".gmtdefaults4")
    if(is.character(par) && nchar(par)>0)
      gmt.system(paste("gmtset",gsub("="," = ",par)))  # add extra spacing around equal signs
  }
  options(gmt.file=file)

  if(!quiet)
  {
    gmtdefaults <- gmt.system("gmtdefaults -L")
    cat(paste(gmtdefaults,collapse="\n"), "\n\n")
    print(options("gmt.file"))
  }
  invisible(options("gmt.file"))
}

"gmt.system" <-
function(cmd, file=NULL, append=FALSE)
{
  output <- if("invisible" %in% names(formals(system))) system(cmd,intern=TRUE,invisible=TRUE) else system(cmd,intern=TRUE)
  open <- if(append) "a" else "w"  # append or write

  if(is.character(file))
  {
    con <- file(file, open)
    writeLines(output, con)
    close.connection(con)
  }

  invisible(output)
}

"psbar" <-
function(x, cmd="-JM -R -W1p -G180 -O -K", file=options("gmt.file"), ref=0, digits=options("digits"))
{
  write.each.bar <- function(bar.row)
  {
    left   <- bar.row[1]  #  2----3
    right  <- bar.row[2]  #  |    |
    bottom <- bar.row[3]  #  |    |
    top    <- bar.row[4]  # 1+5---4
    bar.corners <- rbind(c(left,bottom), c(left,top), c(right,top), c(right,bottom), c(left,bottom))
    r2gmt(bar.corners, "lastBAR.gmt", append=TRUE)
  }

  if(is.list(file)) file <- unlist(file)[1]
  if(is.null(file)) stop("Please pass a valid 'file' argument, or run gmt(file=\"myfile\").")
  if(is.list(digits)) digits <- unlist(digits)[1]

  ## 1 Parse user data and define directories
  x.matrix <- as.matrix(r2gmt(x,"lastBAR.gmt"))
  lon <- deg2num(x.matrix[,1])   # longitude at bar center
  lat <- deg2num(x.matrix[,2])   # latitude at bar base
  w   <- x.matrix[,3]            # bar width in degrees
  h   <- x.matrix[,4]            # bar height in user units (1 degree high at refN/S)
  n   <- nrow(x.matrix)          # number of bars

  ##   Y = log(tan(pi/4+LAT*pi/360))
  ##   LAT = (atan(exp(Y))-pi/4) / (pi/360)
  ##   Y'(LAT) = (pi/360) / (tan(pi/4+LAT*pi/360)*cos(pi/4+LAT*pi/360)^2)

  ##   LAT      0     10    20    30    40    50    60    70    80    90
  ##   Y        0.000  0.175  0.356  0.549  0.763  1.011  1.317  1.735  2.436  37.332
  ##   Y'(LAT)  0.017  0.018  0.019  0.020  0.023  0.027  0.035  0.051  0.101  Inf

  ## 2 Create bar.frame containing coordinates
  dYlat <- (pi/360) / (tan(pi/4+lat*pi/360)*cos(pi/4+lat*pi/360)^2)  # derivative of Mercator Y at each latitude
  dYref <- (pi/360) / (tan(pi/4+ref*pi/360)*cos(pi/4+ref*pi/360)^2)  # derivative of Mercator Y at refN/S
  h.deg <- h * round(dYref/dYlat, digits)                            # bar height in degrees
  left      <- lon - w/2                                             # left bar edge
  right     <- lon + w/2                                             # right bar edge
  bottom    <- lat                                                   # bottom bar edge
  top       <- lat + h.deg                                           # top bar edge
  bar.frame <- data.frame(left=left, right=right, bottom=bottom, top=top)

  ## 3 Write bar coordinates into multiple segment file and add bars to map
  file.create("lastBAR.gmt")
  apply(bar.frame, 1, write.each.bar)
  safe.cmd <- paste(cmd, "-A -M")  # ensure lines are straight and multiple-file is expected
  gmt.system(paste("psxy lastBAR.gmt",safe.cmd), file=file, append=TRUE)

  invisible(NULL)
}

"psclose" <-
function(file=options("gmt.file"))
{
  if(is.list(file)) file <- unlist(file)[1]
  if(is.null(file)) stop("Please pass a valid 'file' argument, or run gmt(file=\"myfile\").")

  file.create("emptyfile")
  gmt.system("psxy emptyfile -JM -R -O", file=file, append=TRUE)  # larger file than -O in last cmd
  file.remove("emptyfile")

  invisible(NULL)
}

"pscoast" <-
function(cmd, file=options("gmt.file"))
{
  if(is.list(file)) file <- unlist(file)[1]
  if(is.null(file)) stop("Please pass a valid 'file' argument, or run gmt(file=\"myfile\").")

  gmt.system(paste("pscoast",cmd), file=file)

  invisible(NULL)
}

"pstext" <-
function(x, cmd="-JM -R -O -K", file=options("gmt.file"))
{
  if(is.list(file)) file <- unlist(file)[1]
  if(is.null(file)) stop("Please pass a valid 'file' argument, or run gmt(file=\"myfile\").")

  r2gmt(x, "lastTEXT.gmt")
  gmt.system(paste("pstext lastTEXT.gmt",cmd), file=file, append=TRUE)

  invisible(NULL)
}

"psxy" <-
function(x, cmd="-JM -R -Scp -W2p -O -K", file=options("gmt.file"))
{
  if(is.list(file)) file <- unlist(file)[1]
  if(is.null(file)) stop("Please pass a valid 'file' argument, or run gmt(file=\"myfile\").")

  r2gmt(x, "lastXY.gmt")
  gmt.system(paste("psxy lastXY.gmt",cmd), file=file, append=TRUE)

  invisible(NULL)
}

"r2gmt" <-
function(x, outfile, append=FALSE)
{
  is.digit <- function(x) suppressWarnings(!is.na(as.numeric(x)))

  ## 1  Import x if it's a file
  if(is.character(x) && file.exists(x))
  {
    first.char <- substring(scan(x,what="",n=1,quiet=TRUE), 1, 1)  # assume one-line header if first non-whitespace char
    header <- all(first.char!="-", first.char!=".", !is.digit(first.char))  # is not minus, point, or number
    sep <- if(length(grep(",",readLines(x,n=1)))>1) "," else ""  # assume comma separator if first line has comma
    x <- read.table(x, sep=sep, header=header)
  }

  ## 2  Now that x is a data object, export it
  if(append)
    write(">", outfile, append=TRUE)
  write.table(x, outfile, sep="\t", quote=FALSE, row.names=FALSE, col.names=FALSE, append=append)

  invisible(x)
}

