# Author: Robert J. Hijmans
# Date :  June 2019
# Version 1.0
# License GPL v3


setMethod("dots", signature(x="SpatVector"),
	function(x, field, size,  ...) {
		reset.clip()

		n <- length(x)
		if (n < 1) return(NULL)
		#method <- match.arg(tolower(method), c("regular", "random"))
		if (is.character(field)) {
			stopifnot(field %in% names(x))
		} else {
			stopifnot(field > 0 && field <= ncol(x))
		}
		stopifnot(is.numeric(x[[field,drop=TRUE]]))
		field <- x[[field,drop=TRUE]]
		size <- size[1]
		stopifnot(size > 0)
		d <- round(field / size)
		d[d < 1 | is.na(d)] <- 0
		i <- d > 0;
		if (sum(i) == 0) {
			error("dots", "'size' is too small")
		}
		s <- spatSample(x[i], d[i], method="random")
		if (.Device  != "null device") {
			try(points(s, ...), silent=TRUE)
		}
		invisible(s)
	}
)



.plotLines <- function(x, out, lty=1, lwd=1, ...) {

	n <- nrow(x)
	if (n == 0) return(out)
#	cols <- out$cols
#	if (is.null(cols)) cols = rep("black", n)

#	g <- lapply(x@pntr$linesList(), function(i) { names(i)=c("x", "y"); i } )

#	g <- geom(x, df=TRUE)
#	g <- split(g, g[,1])
#	g <- lapply(g, function(x) split(x[,3:4], x[,2]))
#	n <- length(g)

	g <- x@pntr$linesList()
	lty <- rep_len(lty, n)
	lwd <- rep_len(lwd, n)
	for (i in 1:n) {
		if (!is.null(g[[i]])) {
			names(g[[i]]) = c("x", "y")
			graphics::plot.xy(g[[i]], type="l", lty=lty[i], col=out$main_cols[i], lwd=lwd[i], ...)
		}
	}

#	for (i in 1:n) {
#		for (j in 1:length(g[[i]])) {
#			lines(g[[i]][[j]], col=out$main_cols[i], lwd=lwd[i], lty=lty[i], ...)
#		}
#	}


	out$leg$lwd <- lwd
	out$leg$lty <- lty
	out
}

.plotPolygons <- function(x, out, lty=1, lwd=1, density=NULL, angle=45, ...) {


	n <- nrow(x)
	if (n == 0) return(out)
	if ((length(out$main_cols) == 0) && (length(out$main_border) <= 1) 
			&& (length(lty) <= 1) && (length(lwd) <= 1) && (is.null(density))) {
		if (is.null(out$leg$border)) out$leg$border <- "black"
		lines(x, col=out$leg$border, lty=lty, lwd=lwd, ...)
		return(out)
	}

#		cols <- .getCols(length(x), col, alpha)
#		out <- list(main_cols=cols)

	if (!is.null(out$leg$border)) {
		out$leg$border <- rep_len(out$leg$border, n)
	} else {
		out$leg$border <- NA
	}
	if (!is.null(density)) {
		out$leg$density <- rep_len(density, n)
		out$leg$angle <- rep_len(angle, n)
	}
	if (!is.null(lty)) out$leg$lty <- rep_len(lty, n)
	if (!is.null(lwd)) out$leg$lwd <- rep_len(lwd, n)

	if (!is.null(out$main_cols)) {
		out$main_cols <- rep_len(out$main_cols, n)
	}
	if (!is.null(out$main_border)) {
		out$main_border <- rep_len(out$main_border, n)
	}

#	g <- geom(x, df=TRUE)
#	g <- split(g, g[,1])
#	g <- lapply(g, function(y) split(y[,3:5], y[,2]))
#	w <- getOption("warn")
#	on.exit(options("warn" = w))
#	for (i in 1:length(g)) {
#		gg <- g[[i]]
#		for (j in 1:length(gg)) {
#			a <- gg[[j]]
#			if (any(is.na(a))) next
#			if (any(a[,3] > 0)) {
#				a <- split(a[,1:2,drop=FALSE], a[,3])
#				a <- lapply(a, function(i) rbind(i, NA))
#				a <- do.call(rbind, a )
#				a <- a[-nrow(a), ]
#				# g[[i]][[1]] <- a
#			}

	g <- x@pntr$polygonsList()
	if (is.null(out$leg$density)) {
		for (i in seq_along(g)) {
			for (j in seq_along(g[[i]])) {
				if (any(is.na(g[[i]][[j]]))) next
				graphics::polypath(g[[i]][[j]][[1]], g[[i]][[j]][[2]], col=out$main_cols[i], rule = "evenodd", border=out$main_border[i], lwd=out$leg$lwd[i], lty=out$leg$lty[i], ...)
			}
		}
	} else {
		for (i in 1:length(g)) {
			for (j in seq_along(g[[i]])) {
				if (any(is.na(g[[i]][[j]]))) next
				graphics::polygon(g[[i]][[j]][[1]], g[[i]][[j]][[2]], col=out$main_cols[i], density=out$leg$density[i], angle=out$leg$angle[i], border=NA, lwd=out$leg$lwd[i], lty=out$leg$lty[i], ...)
				graphics::polypath(g[[i]][[j]][[1]], g[[i]][[j]][[2]], col=NA, rule="evenodd", border=out$main_border[i], lwd=out$leg$lwd[i], lty=out$leg$lty[i], ...)
			}
		}
	}
	invisible(out)
}


.vplot <- function(x, out, xlab="", ylab="", pch=16, lty=1, lwd=1, ...) {

	reset.clip()

	if (out$leg$geomtype == "points") {
		points(x, col=out$main_cols, cex=out$cex, pch=pch, ...)
		if (is.null(out$leg$pch)) out$leg$pch <- pch
		if (is.null(out$leg$pt.cex)) out$leg$pt.cex = out$cex
	} else if (out$leg$geomtype == "polygons") {
		out <- .plotPolygons(x, out, density=out$leg$density, angle=out$leg$angle, lty=lty, lwd=lwd, ...)
	} else {
		# out <- .plotLines(x, out, ...)
		lines(x, col=out$main_cols, lty=lty, lwd=lwd, ...)
		if (is.null(out$leg$lwd)) out$leg$lwd = lwd
		if (is.null(out$leg$lty)) out$leg$lty = lty
	}
	out
}


.apply_alpha <- function(cols, alpha) {
	if (!is.null(alpha)) {
		if (alpha[1] < 1 && alpha[1] >= 0) {
			cols <- grDevices::rgb(t(grDevices::col2rgb(cols)), alpha=alpha[1]*255, maxColorValue=255)
		}
	}
	cols
}

.getCols <- function(n, cols, alpha=NULL) {
	if (is.null(cols)) { 
		return(cols)
	}
	if (inherits(cols, "function")) {
		cols <- cols(n)
	} else {
		ncols <- length(cols)
		if (ncols > n) {
			steps <- ncols/n
			i <- round(seq(1, ncols, steps))
			cols <- cols[i]
		} else if (ncols < n) {
			cols <- rep_len(cols, n)
		}
	}
	.apply_alpha(cols, alpha)
}

.vect.legend.none <- function(out) {
	#if (out$leg$geomtype == "points") {
	#	out$main_cols <- .getCols(out$ngeom, out$cols, 1)
	#} else {
	#	out$cols <- .getCols(out$ngeom, out$cols)
	#}
	out$main_cols <- out$cols
	out$main_border <- out$leg$border
	out
}

.vect.legend.classes <- function(out) {
	
	if (isTRUE(out$leg$sort)) {
		out$uv <- sort(out$uv) # done by legend: decreasing=out$leg$reverse)
	} else {
		out$uv <- out$uv[!is.na(out$uv)]
	}

	if (NCOL(out$cols) == 2) {
		i <- match(out$uv, out$cols[,1])
		out$cols <- .apply_alpha(out$cols[i,2], out$alpha)
	} else if (!is.null(names(out$cols))) {
		i <- match(out$uv, names(out$cols))
		out$cols <- .apply_alpha(out$cols[i], out$alpha)
	} else {
		out$cols <- .getCols(length(out$uv), out$cols, out$alpha)
	}
	
	i <- match(out$v, out$uv)
	out$main_cols <- out$cols[i]
	out$leg$border <- rep_len(out$leg$border, length(out$cols))
	out$main_border <- out$leg$border[i]

	if (!is.null(out$colNA)) {
		out$main_cols[is.na(out$main_cols)] <- out$colNA
	}

	out$levels <- out$uv
	out$leg$legend <- out$uv
	nlevs <- length(out$uv)

	cols <- out$cols
	ncols <- length(cols)
	if (nlevs < ncols) {
		i <- trunc((ncols / nlevs) * 1:nlevs)
		cols <- cols[i]
	} else {
		cols <- rep_len(cols, nlevs)
	}
	out$leg$fill <- cols
	out$legend_type <- "classes"

	if (is.null(out$leg$x)) { # && is.null(out$leg$ext)) {
		out$leg$x <- "default"
	}

	out
}


.vect.legend.continuous <- function(out) {

	z <- stats::na.omit(out$v)
	n <- length(z)
	if (n == 0) error("plot", "no values")
	if (!is.numeric(out$v)) {
		out$v <- as.integer(as.factor(out$v))
		z <- stats::na.omit(out$v)
		n <- length(z)
	}
	#out$range <- range(z)
	
	interval <- (out$range[2]-out$range[1])/(length(out$cols)-1)
	breaks <- out$range[1] + interval * (0:(length(out$cols)-1))
	
	out$legend_type <- "continuous"
	if (is.null(out$levels)) {
		out$levels <- 5
	}
	if (is.null(out$leg$digits)) {
		dif <- diff(out$range)
		if (dif == 0) {
			out$leg$digits <- 0;
		} else {
			out$leg$digits <- max(0, -floor(log10(dif/10)))
		}
	}

#	if (is.null(out$leg$loc)) out$leg$loc <- "right"

	brks <- seq(out$range[1], out$range[2], length.out = length(out$cols))
	grps <- cut(out$v, breaks = brks, include.lowest = TRUE)
	out$main_cols <- out$cols[grps]
	out$leg$border <- rep_len(out$leg$border, length(out$cols))
	out$main_border <- out$leg$border[grps]

	out
}


.vect.legend.interval <- function(out, dig.lab=3, ...) {

	nmx <- length(out$uv)
	if (!is.numeric(out$v)) {
		out$v <- as.integer(as.factor(out$v))
	}

	if (is.null(out$breaks)) {
		out$breaks <- min(5, nmx)
	}

	if (length(out$breaks) == 1) {
		out$breaks <- .get_breaks(out$v, out$breaks, out$breakby, out$range)
	}

	fz <- cut(out$v, out$breaks, include.lowest=TRUE, right=FALSE, dig.lab=dig.lab)
	out$vcut <- as.integer(fz)
	levs <- levels(fz)
	nlevs <- length(levs)

#	cols <- out$cols
#	ncols <- length(cols)
#	if (nlevs < ncols) {
#		i <- trunc((ncols / nlevs) * 1:nlevs)
#		cols <- cols[i]
#	} else {
#		cols <- rep_len(cols, nlevs)
#	}
	
	if (out$legend_type == "classes" && nlevs > length(out$cols)) {
		# more classes than colors: cycle from beginning
		cols_idx <- rep_len(out$cols, nlevs)
	} else {
		# else sample the colors
		cols_idx <- trunc(seq(1, length(out$cols), length.out = nlevs))
	}
	out$leg$fill <- out$cols <- out$cols[cols_idx]
	out$legend_type <- "classes"

	if (!is.null(out$leg$legend)) {
		if (length(out$leg$legend) != nlevs) {
			warn("plot", "legend does not match number of levels")
			out$leg$legend <- rep_len(out$leg$legend, nlevs)
		}
	} else {
		levs <- gsub("]", "", gsub(")", "", gsub("\\[", "", levs)))
		levs <- paste(levs, collapse=",")
		m <- matrix(as.numeric(unlist(strsplit(levs, ","))), ncol=2, byrow=TRUE)
		m <- apply(m, 1, function(i) paste(i, collapse=" - "))
		out$leg$legend <- m
	}

	if (is.null(out$leg$x)) { # && is.null(out$leg$ext)) {
		out$leg$x <- "default"
	}
	out$main_cols <- out$cols[out$vcut]
	out$leg$border <- rep_len(out$leg$border, length(out$cols))
	out$main_border <- out$leg$border[out$vcut]
	if (!is.null(out$colNA)) {
		out$main_cols[is.na(out$main_cols)] <- out$colNA
	}
	out
}


.plot.vect.map <- function(x, out, ...) {

	if ((!out$add) & (!out$legend_only)) {
		if (out$zebra) {
			width <- rep(min(diff(out$lim[1:2]), diff(out$lim[3:4])) / 100, 2) * out$zebra.cex
			if (out$lonlat) {
				asp <- 1/cos((mean(out$lim[3:4]) * pi)/180)
				width[2] <- width[2] / asp
			}
			out$lim[1:2] <- out$lim[1:2] + c(-width[1], width[1])
			out$lim[3:4] <- out$lim[3:4] + c(-width[2], width[2])
		}
		if (!any(is.na(out$mar))) { graphics::par(mar=out$mar) }
		plot(out$lim[1:2], out$lim[3:4], type="n", xlab="", ylab="", asp=out$asp, xaxs="i", yaxs="i", axes=FALSE, main="")
		if (!is.null(out$background)) {
			graphics::rect(out$lim[1], out$lim[3], out$lim[2], out$lim[4], col=out$background, border=x$box)
		}
	} else {
		x$zebra <- FALSE
	}
	if (isTRUE(out$blank)) return(out)
	
	nuq <- length(out$uv)
	if (out$legend_type == "none") {
		out <- .vect.legend.none(out)
	} else if (out$legend_type == "classes") {
		out <- .vect.legend.classes(out)
	} else if (out$legend_type == "interval") {
		if (nuq < 2) {
			out <- .vect.legend.classes(out, ...)
		} else {
			out <- .vect.legend.interval(out, dig.lab=out$dig.lab)
		}
	} else if (out$legend_type == "depends") {
		if (!is.null(out$breaks)) {
			out <- .vect.legend.interval(out, dig.lab=out$dig.lab)			
		} else if (nuq < 11) {
			out <- .vect.legend.classes(out)
		} else if (!is.numeric(out$uv)) {
			#if (nuq < 21)
			out <- .vect.legend.classes(out)
		} else {
			out <- .vect.legend.interval(out, dig.lab=out$dig.lab)
		}
	} else {
		if (nuq == 1) {
			out <- .vect.legend.classes(out)
		} else {
			out <- .vect.legend.continuous(out)
			out$leg$density <- NULL
		}
	}
	if (!out$legend_only) {
		if (!out$add) {
			try(set.clip(out$lim, out$lonlat))
		}
		out <- .plot.axes(out)
		out <- .vplot(x, out, ...)
	}


	if (out$legend_draw) {
		if (out$legend_type == "continuous") {
			out$legpars <- do.call(.plot.cont.legend, list(x=out))
		} else {
			if (out$add) {
				if (out$clip) {
					out$leg$plotlim <- unlist(get.clip()[1:4])
				} else {
					out$leg$plotlim <- graphics::par("usr")
				}
				if (is.null(out$leg$plotlim)) {
					out$leg$plotlim <- out$lim			
				}
			} else {
				if (out$clip) {
					out$leg$plotlim <- out$lim
				} else {
					out$leg$plotlim <- graphics::par("usr")
				}
			}
			out$legpars <- do.call(.plot.class.legend, out$leg)
		}
	}

	if (out$zebra) {
		zebra(width=width, x=out$axs$xat, y=out$axs$yat, col=out$zebra.col)
		out$lim[1:2] <- out$lim[1:2] + c(width[1], -width[1])
		out$lim[3:4] <- out$lim[3:4] + c(width[2], -width[2])
	}

	if (isTRUE(out$box)) { 
		if (out$clip) {
			lines(ext(out$lim))	
		} else {
			lines(ext(graphics::par("usr")))		
		}
	}
	
	plot_main(out)

#	if (out$main != "") {
#		posx <- out$lim[1] + diff(out$lim[1:2])/2
#		text(posx, out$lim[4], out$main, pos=3, offset=out$line.main, cex=out$cex.main, 
#			font=out$font.main, col=out$col.main, xpd=TRUE)
#	}

	if (!out$add) {
		try(set.clip(out$lim, out$lonlat))
	}
	out
}


.prep.vect.data <- function(x, y, type=NULL, cols=NULL, mar=NULL, legend=TRUE,
	legend.only=FALSE, levels=NULL, add=FALSE, range=NULL, fill_range=FALSE, breaks=NULL, breakby="eqint",
	xlim=NULL, ylim=NULL, colNA=NA, alpha=NULL, axes=TRUE, buffer=TRUE, background=NULL,
	pax=list(), plg=list(), ext=NULL, grid=FALSE, zebra=FALSE, zebra.cex=1, zebra.col=c("black", "white"), 
	las=0, sort=TRUE, reverse=FALSE, values=NULL,
	box=TRUE, xlab="", ylab="", cex.lab=0.8, line.lab=1.5, yaxs="i", xaxs="i", 
	main="", cex.main=1.2, line.main=0.5, font.main=graphics::par()$font.main, col.main = graphics::par()$col.main, loc.main=NULL, 
    sub = "", font.sub=1, cex.sub=0.8*cex.main, line.sub =1.75,  col.sub=col.main, loc.sub=NULL,
	halo=FALSE, hc="white", hw=0.1, 
	density=NULL, angle=45, border="black", dig.lab=3, cex=1, clip=TRUE, leg_i=1, asp=NULL, xpd=NULL, 
#catch and kill
	decreasing=FALSE, font=NULL,
	...) {

	# backwards compatibility
	reverse <- isTRUE(reverse) || isTRUE(decreasing)

	out <- list()
	out$blank <- FALSE
	if ((y == "") && (is.null(values))) {
		if (is.null(type)) type <- "none"
		if (type == "n") {
			out$blank <- TRUE
		}
		type <- "none"
		plg <- list()
	}
	
	e <- as.vector(ext(x))
	if (any(is.na(e))) {
		error("plot", "SpatVector has no valid geometries")
	}
	if (e[1] == e[2]) {
		e[1] = e[1] - 0.5
		e[2] = e[2] + 0.5
	}
	if (e[3] == e[4]) {
		e[3] = e[3] - 0.5
		e[4] = e[4] + 0.5
	}
	
	out$lim <- out$ext <- e
	if ((!is.null(ext)) || (!is.null(xlim)) || (!is.null(ylim))) {
		if (!is.null(ext)) {
			ext <- ext(ext)
			if (!is.null(xlim) | !is.null(ylim)) {
				x <- crop(x, ext)
			} else {
				x <- x[ext, ]
			}
			out$ext <- as.vector(ext(x))
			out$lim <- as.vector(ext)
		}
		if (!is.null(xlim)) {
			stopifnot(length(xlim) == 2)
			out$lim[1:2] <- sort(xlim)
		}
		if (!is.null(ylim)) {
			stopifnot(length(ylim) == 2)
			out$lim[3:4] <- sort(ylim)
		}
	} else if ((!add) && is.null(xpd)) {
		xpd <- TRUE
	}
	out$ngeom <- nrow(x)
	out$clip <- isTRUE(clip)

	if (buffer) {
		dx <- diff(out$lim[1:2]) / 50
		dy <- diff(out$lim[3:4]) / 50
		out$lim[1:2] <- out$lim[1:2] + c(-dx, dx)
		out$lim[3:4] <- out$lim[3:4] + c(-dy, dy)
	}
	
	out$main <- main
#	if ((!is.expression(main)) && (is.null(out$main) || any(is.na(out$main)))) out$main <- ""

	out$halo.main <- halo
	out$halo.main.hc <- hc
	out$halo.main.hw <- hw

	out$cex.main  <- cex.main
	out$loc.main  <- loc.main
	out$font.main <- font.main
	out$col.main  <- col.main
	out$line.main <- line.main

	out$sub <- sub
	out$loc.sub <- loc.sub
	out$cex.sub <- cex.sub
	out$font.sub <- font.sub
	out$col.sub <- col.sub
	out$line.sub <- line.sub

	out$dig.lab <- dig.lab

	out$box <- isTRUE(box)
	out$zebra <- isTRUE(zebra)
	out$zebra.cex <- zebra.cex
	out$zebra.col <- zebra.col
	
	out$add <- isTRUE(add)
	out$axes <- isTRUE(axes)
	out$xlab <- xlab
	out$ylab <- ylab
	out$axs <- as.list(pax)
	out$cex <- cex
	if (is.null(out$axs$las)) out$axs$las <- las
	if (is.null(out$axs$cex.lab)) out$axs$cex.lab <- cex.lab
	if (is.null(out$axs$line.lab)) out$axs$line.lab <- line.lab
	
	out$draw_grid <- isTRUE(grid)
	out$leg <- as.list(plg)
	out$leg$geomtype <- geomtype(x)
	
	out$leg$density <- density
	out$leg$angle <- angle
	out$leg$border <- border
	
	
	if (is.null(asp)) {
		out$lonlat <- is.lonlat(x, perhaps=TRUE, warn=FALSE)
		if (out$lonlat) {
			out$asp <- 1/cos((mean(out$ext[3:4]) * pi)/180)
		} else {
			out$asp <- 1
		}
	} else {
		out$asp <- asp
		out$lonlat <- FALSE
	}
	
	out$breaks <- breaks
	out$breakby <- breakby
	out$background <- background
	if (is.null(values)) {
		v <- unlist(x[, y, drop=TRUE], use.names=FALSE)
	} else {
		if (inherits(values, "data.frame")) {
			if (ncol(values) == 2) {
				xname = names(values)[1]
				if (xname %in% names(x)) {
					i <- match(x[[xname,drop=TRUE]], values[[1]])
					v <- values[[2]][i]
				} else {
					error("plot", paste(xname, "is not a name in x"))
				}
			} else {
				values <- values[[1]]
			}
		} else {
			v <- as.vector(values)
		}
		v <- rep_len(v, nrow(x))
	}
	if (is.factor(v)) v <- as.character(v)
	if (is.numeric(v)) {
		v[!is.finite(v)] <- NA
	}
	out$fill_range <- isTRUE(fill_range)
	out$range_filled <- c(FALSE, FALSE)
	if (!is.null(range)) {
		range <- sort(range)
		if (out$fill_range) {
			i <- v < range[1]
			if (any(i)) {
				v[i] <- range[1]
				out$range_filled[1] <- TRUE
			}
			i <- v > range[2]
			if (any(i)) {
				v[i] <- range[2]
				out$range_filled[2] <- TRUE
			}
		} else {
			v[v < range[1]] <- NA
			v[v > range[2]] <- NA
		}
		if (all(is.na(v))) {
			v <- NULL
			y <- ""
			type = "none"
		} else {
			out$range <- range
		}
		out$range_set <- TRUE
	} else {
		if (!is.null(v)) {
			out$range <- range(v, na.rm=TRUE)
		}
		out$range_set <- FALSE
		out$fill_range <- FALSE
	}
	out$v <- v

	if (!is.logical(sort)) {
		out$uv <- unique(sort)
		out$leg$sort <- FALSE
		out$leg$reverse <- FALSE
	} else {
		out$uv <- unique(out$v)
		if (is.factor(out$v)) {
			out$uv <- levels(out$v)[levels(out$v) %in% out$uv]
		}
		out$leg$sort <- isTRUE(sort)
		out$leg$reverse <- isTRUE(reverse)
	}

	if (is.null(type)) {
		type <- "depends"
	} else {
		type <- match.arg(type, c("continuous", "classes", "interval", "depends", "none"))
	}
	out$levels <- levels
	
	if (type=="none") {
		legend <- FALSE
		legend_only <- FALSE
	}
	out$legend_type <- type

	if (is.null(cols)) {
		if (type == "none") {
			if (out$leg$geomtype %in% c("lines", "points")) {
				cols <- "black"
			}
		} else {
			cols <- .default.pal()
#			cols <- rev(grDevices::rainbow(100, start=.1, end=0.9))
		}
	}
	if (!is.null(alpha)) {
		alpha <- clamp(alpha[1], 0, 1)
		cols <- grDevices::rgb(t(grDevices::col2rgb(cols)), alpha=alpha*255, maxColorValue=255)
	} else {
		alpha <- 1
	}

	out$alpha <- alpha
	out$cols <- cols
	out$legend_draw <- isTRUE(legend)
	out$legend_only <- isTRUE(legend.only)
	out$leg$leg_i <- leg_i

	out$mar <- mar
	out <- get_mar(out)

#	if (is.null(mar)) {
#		if (out$legend_draw) {
#			mar=c(3.1, 3.1, 2.1, 7.1)
#		} else {
#			mar=c(3.1, 3.1, 2.1, 2.1)
#		}
#	}
#	out$mar <- rep_len(mar, 4)
	out$skipNA <- TRUE
	if (!is.null(colNA)) {
		if (!is.na(colNA)) {
			out$colNA <- grDevices::rgb(t(grDevices::col2rgb(colNA)), alpha=alpha*255, maxColorValue=255)
			out$r[is.na(out$r)] <- out$colNA
			out$skipNA <- FALSE
 		} else {
			out$colNA <- NULL
		}
	}

	.plot.vect.map(x, out, xpd=xpd, ...)
}


setMethod("plot", signature(x="SpatVector", y="character"),

function(x, y, col=NULL, type=NULL, mar=NULL, legend=TRUE, axes=!add, plg=list(), pax=list(), 
	main="", range=NULL, fill_range=FALSE, breaks=NULL, breakby="eqint", fun=NULL, colNA=NA, alpha=NULL,
	grid=FALSE, zebra=FALSE, ext=NULL, sort=TRUE, reverse=FALSE, nr, nc, add=FALSE, buffer=TRUE, background=NULL,
	box=axes, clip=TRUE, ...) {


		old.mar <- graphics::par()$mar
		on.exit(graphics::par(mar=old.mar))

		if (nrow(x) == 0) {
			error("plot", "SpatVector has zero geometries")
		}
		if (add) reset.clip()

		y <- trimws(y)
		if (any(is.na(match(y, c("", names(x)))))) {
			i <- is.na(match(y, names(x)))
			error("plot", paste(paste(y[i], collapse=",")), " is not a name in x")
		}
		nrnc <- c(1,1)
		if (length(y) > 1) {
			nrnc <- .get_nrnc(nr, nc, length(y))
			old.par <- graphics::par(no.readonly =TRUE)
			on.exit(graphics::par(old.par))
			graphics::par(mfrow=nrnc)
		}
		if (is.character(legend)) {
			plg$x <- legend
			legend <- TRUE
		}


		for (i in 1:length(y)) {
			if (length(y) > 1) {
				if (missing("main")) {
					main <- y
				} else {
					main <- rep_len(main, length(y))
				}
				newrow <- (nrnc[2] == 1) | ((i %% nrnc[2]) == 1)
				lastrow <- i > (prod(nrnc) - nrnc[2])
				if (lastrow) {
					if (newrow) {
						pax$side <- 1:2
					} else {
						pax$side <- 1
					}
				} else if (newrow) {
					pax$side <- 2
				} else {
					pax$side <- 0
				}
			} else if (missing("main")) {
				main <- ""
			}

			if (missing(col)) col <- NULL

			out <- .prep.vect.data(x, y[i], type=type, cols=col, mar=mar, plg=plg, pax=pax, legend=isTRUE(legend), add=add, axes=axes, main=main[i], range=range, fill_range=fill_range, breaks=breaks, breakby=breakby, buffer=buffer, background=background,
			grid=grid, zebra=zebra, ext=ext, sort=sort, reverse=reverse, colNA=colNA, alpha=alpha, box=box, clip=clip, leg_i=i,  ...)

			add_more(fun, i)

		}
		invisible(out)
	}
)


setMethod("plot", signature(x="SpatVector", y="numeric"),
	function(x, y, ...)  {
		y <- round(y)
		if (any(y > ncol(x))) {
			error("plot", paste("x only has", ncol(x), " columns"))
		}
		y[y<0] <- 0
		y <- c("", names(x))[y+1]
		out <- plot(x, y, ...)
		invisible(out)
	}
)


#setMethod("plot", signature(x="SpatVector", y="data.frame"),
#	function(x, y, values=NULL, ...)  {
#		out <- plot(x, "", values=y, ...)
#		invisible(out)
#	}
#)

setMethod("plot", signature(x="SpatVector", y="missing"),
	function(x, y, values=NULL, ...)  {
		invisible( plot(x, "", values=values, ...) )
	}
)


setMethod("plot", signature(x="SpatVectorProxy", y="missing"),
	function(x, y, ...)  {
		plot(ext(x), ...)
	}
)



setMethod("plot", signature(x="SpatVectorCollection", y="missing"),
	function(x, y, main, mar=NULL, nc, nr, maxnl=16, col=NULL, ...) {
		nl <- max(1, min(length(x), maxnl))

		if (nl==1) {
			if (missing(main)) main = ""
			out <- plot(x[1], main=main[1], mar=mar, ...)
			return(invisible(out))
		}

		nrnc <- .get_nrnc(nr, nc, nl)
		old.par <- graphics::par(no.readonly = TRUE)
		on.exit(graphics::par(old.par))
		if (is.null(mar)) {
			mar=c(1.5, 1, 2.5, 3)
		}
		graphics::par(mfrow=nrnc)

		if (missing("main")) {
			main <- names(x)
		} else {
			main <- rep_len(main, nl)
		}
		if (is.list(col)) {
			col <- rep_len(col, nl)
			for (i in 1:nl) {
				plot(x[i], main=main[i], mar=mar, col=col[[i]], ...)
			}
		} else {
			for (i in 1:nl) {
				plot(x[i], main=main[i], mar=mar, ...)
			}
		}
	}
)

setMethod("plot", signature(x="SpatVectorCollection", y="numeric"),
	function(x, y, main, mar=NULL, ext=NULL, ...) {
		y <- round(y)
		if ((y > 0) && (y <= length(x))) {
			if (is.null(ext)) ext <- ext(x)
			plot(x[y], main=main, mar=mar, ext=ext, ...)
		} else {
			error("plot", "y should be between 1 and length(x)")
		}
	}
)

