
#setMethod("row.names", signature(x="SpatVector"),
#	function(x) {
#		1:nrow(x)
#	}
#)

setMethod("emptyGeoms", signature(x="SpatVector"),
	function(x) {
		x@pntr$nullGeoms() + 1
	}
)


setMethod("as.vector", signature(x="SpatVector"),
	function(x, mode="any") {
		if (nrow(x) > 0) {
			lapply(1:nrow(x), function(i) x[i,])
		} else {
			x
		}
	}
)

setMethod("vect", signature(x="missing"),
	function(x) {
		p <- methods::new("SpatVector")
		p@pntr <- SpatVector$new()
		messages(p, "vect")
	}
)

setMethod("vect", signature(x="SpatExtent"),
	function(x, crs="") {
		as.polygons(x, crs=crs)
	}
)

setMethod("vect", signature(x="SpatVectorCollection"),
	function(x) {
		vect(as.list(x))
	}
)


setMethod("vect", signature(x="SpatGraticule"),
	function(x) {
		v <- vect()
		v@pntr <- x@pntr
		v
	}
)


# Remote files may need  "/vsicurl/" and "/vsizip/" 
.vect_vsify <- function(x) {
	x <- enc2utf8(trimws(x[1]))
	if (grepl("^/vsizip/", x)) {
		inner <- sub("^/vsizip/+", "", x)
		if (grepl("^(https?|ftp)://", inner, ignore.case=TRUE) && !grepl("^vsicurl/", inner, ignore.case=TRUE)) {
			return(paste0("/vsizip//vsicurl/", inner))
		}
		return(x)
	}
	if (grepl("^(https?|ftp)://", x, ignore.case=TRUE) && grepl("\\.(kml|kmz)$", x, ignore.case=TRUE)) {
		return(paste0("/vsicurl/", x))
	}
	x
}

setMethod("vect", signature(x="character"),
	function(x, layer="", query="", dialect="", extent=NULL, filter=NULL, crs="", proxy=FALSE, what="", opts=NULL, kml.extended=NULL) {

		what <- trimws(tolower(what))
		if (what != "") what <- match.arg(trimws(tolower(what)), c("geoms", "attributes"))

		s <- substr(x[1], 1, 5)
		if (s %in% c("POINT", "MULTI", "LINES", "POLYG", "EMPTY")) {
			p <- methods::new("SpatVector")
	#		if (all(grepl("\\(", x) & grepl("\\)", x))) {
			p@pntr <- SpatVector$new(gsub("\n", "", x))
			messages(p, "vect")
			crs(p, warn=FALSE) <- crs
			return(p)
		} 

		if (substr(x[1], 1, 1) == "{") { # json
			if (length(x) > 1) x <- paste(x, collapse="")
		} else {			
			x <- x[1]
			nx <- try(normalizePath(x, mustWork=TRUE), silent=TRUE)
			if (!inherits(nx, "try-error")) { # skip html
				x <- nx
				if (grepl("\\.rds$", tolower(x))) {
					v <- unwrap(readRDS(x))
					if (!inherits(v, "SpatVector")) {
						error("vect", "the rds file does not store a SpatVector")
					}
					return(v)
				}
			} else if ((substr(x, 1, 4) == "http") & (grepl("\\.shp$", x) | grepl("\\.gpkg$", x))) {
				x <- paste0("/vsicurl/", x[1])
			}
			x <- .vect_vsify(x)
		}
		
		p <- methods::new("SpatVector")
		p@pntr <- SpatVector$new()
		proxy <- isTRUE(proxy)
			if ((what=="attributes") && proxy) {
			error("vect", "you cannot use 'what==attributes' when proxy=TRUE")
		}
		#if (proxy) query <- ""
		if (is.null(filter)) {
			filter <- SpatVector$new()
		} else {
			if (!inherits(filter, "SpatVector")) {
				error("vect", "'filter' must be a SpatVector")			
			}
			if (proxy) {
				error("vect", "you cannot use 'filter' when proxy=TRUE")
			}
			filter <- filter@pntr
		}
		if (is.null(extent)) {
			extent <- double()
		} else {
			extent <- as.vector(ext(extent))
		}
		if (is.null(opts)) opts <- ""[0]
		p@pntr$read(x, layer, query, extent, filter, proxy, what, dialect, opts)
		if (isTRUE(crs != "")) {
			crs(p, warn=FALSE) <- crs
		}
		if (proxy) {
			messages(p, "vect")
			pp <- methods::new("SpatVectorProxy")
			pp@pntr <- SpatVectorProxy$new()
			pp@pntr$v <- p@pntr
			return(pp)
		}
		p <- messages(p, "vect")
		p <- .vect_kml_merge_extended(p, x, kml.extended, proxy, what)
		if (what == "attributes") {
			p <- values(p)
		}
		p
	}
)


setMethod("vect", signature(x="Spatial"),
	function(x) {
		methods::as(x, "SpatVector")
	}
)

setMethod("vect", signature(x="sf"),
	function(x) {
		methods::as(x, "SpatVector")
	}
)

setMethod("vect", signature(x="sfc"),
	function(x) {
		methods::as(x, "SpatVector")
	}
)

setMethod("vect", signature(x="XY"), #sfg
	function(x) {
		methods::as(x, "SpatVector")
	}
)



.checkXYnames <- function(x, warn=FALSE) {
	if (is.null(x)) return(TRUE)
	if (length(x) != 2) {
		error("vect", "coordinate matrix should have 2 columns")
	}
	z <- tolower(x[1:2])
	x <- substr(z, 1, 3)
	y <- substr(x, 1, 1)
	if ((y[1] == "x") && (y[2] == "y")) return(FALSE)
	if ((x[1] == "eas") && (x[2] == "nor")) return(FALSE)
	if ((x[1] == "lon") && (x[2] == "lat")) return(TRUE)
	if (grepl("lon", z[1]) && grepl("lat", z[2])) return(TRUE)

	if ((x[1] == "lat") && (x[2] == "lon")) {
		stop("vect", "longitude/latitude in the wrong order")
	} else if ((y[1] == "y") && (y[2] == "x")) {
		stop("vect", "x/y in the wrong order")
	} else if ((x[1] == "nor") && (x[2] == "eas")) {
		stop("vect", "easting/northing in the wrong order")
	} else if (warn) {
		warn("coordinate names not recognized. Expecting lon/lat, x/y, or easting/northing")
	}
	return(FALSE)
}

setMethod("vect", signature(x="matrix"),
	function(x, type="points", atts=NULL, crs="") {
		type <- tolower(type)
		type <- match.arg(tolower(type), c("points", "lines", "polygons"))
		stopifnot(NCOL(x) > 1)
		stopifnot(NCOL(x) < 7)

		crs <- character_crs(crs, "vect")
		p <- methods::new("SpatVector")
		p@pntr <- SpatVector$new()
		crs(p, warn=FALSE) <- crs

		nr <- nrow(x)
		if (nr == 0) {
			return(p)
		}
		nc <- ncol(x)
		z0 <- double(0)
		if (nc == 2) {
			lonlat <- .checkXYnames(colnames(x))
			if (type == "points") {
				p@pntr$setPointsXY(as.double(x[,1]), as.double(x[,2]))
			} else {
				p@pntr$setGeometry(type, rep(1, nr), rep(1, nr), x[,1], x[,2], rep(FALSE, nr), z0)
			}
			if (lonlat && isTRUE(crs=="")) crs <- "+proj=longlat"
		} else if (nc == 3) {
			p@pntr$setGeometry(type, x[,1], rep(1, nr), x[,2], x[,3], rep(FALSE, nr), z0)
		} else if (nc == 4) {
			p@pntr$setGeometry(type, x[,1], x[,2], x[,3], x[,4], rep(FALSE, nr), z0)
		} else if (nc == 5) {
			p@pntr$setGeometry(type, x[,1], x[,2], x[,3], x[,4], x[,5], z0)
		} else if (nc == 6) {
			# geom, part, x, y, hole, z (from geom() when has.z)
			p@pntr$setGeometry(type, x[,1], x[,2], x[,3], x[,4], x[,5], as.double(x[,6]))
		} else {
			error("vect", "not an appropriate matrix (too many columns)")
		}
		if (!is.null(atts)) {
			if ((nrow(atts) == nrow(p)) & (ncol(atts) > 0)) {
				values(p) <- atts
			}
		}
		messages(p, "vect")
	}
)


setMethod("$", "SpatVector",  function(x, name) {
	if (!(name %in% names(x))) {
		return(NULL)
		#error("$", paste(name, "is not a variable name in x"))
	}
	s <- .subset_cols(x, name, drop=TRUE)
	s[,1,drop=TRUE]
})


setMethod("[[", c("SpatVector", "numeric", "missing"),
function(x, i, j,drop=FALSE) {
	s <- .subset_cols(x, i, drop=TRUE)
	s[,,drop=drop]
})


setMethod("[[", c("SpatVector", "character", "missing"),
function(x, i, j, drop=FALSE) {
	if (!(any(i %in% names(x)))) {
		return(NULL)
	}
	s <- .subset_cols(x, i, drop=TRUE)
	s[,,drop=drop]
})



setReplaceMethod("[", c("SpatVector", "ANY", "ANY"),
	function(x, i, j, value) {
		v <- values(x)
		v[i,j] <- value
		if (nrow(v) != nrow(x)) {
			error("[<-", "this would create an invalid SpatVector")
		}
		values(x) <- v
		x
	}
)

setReplaceMethod("[", c("SpatVector", "ANY", "missing"),
	function(x, i, j, value) {
		v <- values(x)
		if (inherits(value, "SpatVector")) {
			value <- values(value)
		}
		v[i,] <- value
		if (nrow(v) != nrow(x)) {
			error("[<-", "this would create an invalid SpatVector")
		}
		values(x) <- v
		x
	}
)

setReplaceMethod("[", c("SpatVector", "missing", "ANY"),
	function(x, i, j, value) {
		v <- values(x)
		if (inherits(value, "SpatVector")) {
			value <- values(value)
		}
		v[,j] <- value
		if (nrow(v) != nrow(x)) {
			error("[<-", "this would create an invalid SpatVector")
		}
		values(x) <- v
		x
	}
)


setReplaceMethod("[[", c("SpatVector", "character"),
	function(x, i, value) {

		x@pntr <- x@pntr$deepcopy()
		if (is.null(value)) {
			for (name in i) {
				if (name %in% names(x)) {
					x@pntr$remove_column(name)
				}
			}
			return(x);
		} else if (length(value) == 0) {
			if (nrow(x) == 0) {
				d <- values(x)
				for (name in i) {
					d[[name]] <- value
				}
				values(x) <- d
				return(x)
			} else {
				values(x) <- NA
				#error("[[<-,SpatVector", "cannot use an empty value")
				return(x)
			}
		}
		if (inherits(value, "data.frame")) {
			if (ncol(value)	> 1) {
				warn("`[[<-`", "only using the first column")
			}
			value <- value[,1]
		} else if (inherits(value, "list")) {
			value <- sapply(value, function(x) if (is.null(x)) NA else x)
		}

		if (NCOL(value)	> 1) {
			warn("[[<-,SpatVector", "only using the first column")
			value <- value[,1]
		}
		name <- i[1]

		nr <- nrow(x)
		if (length(value) > nr) {
			error("$<-", paste("replacement has", length(value), "rows, data has", nr))
		}
		if ((nr %% length(value)) != 0) {
			warn("$<-", "replacement is not a multiple of the number of rows")
		}
		value <- rep(value, length.out=nrow(x))

		if (name %in% names(x)) {
			d <- values(x)
			if (all(is.na(value))) {
				#[] to keep type if NA is used
				d[[name]][] <- value
			} else {
				d[[name]] <- value			
			}
			values(x) <- d
		} else {
			if (inherits(value, "factor")) {
				v <- .makeSpatFactor(value)
				ok <- x@pntr$add_column_factor(v, name)
			} else if (inherits(value, "character")) {
				ok <- x@pntr$add_column_string(enc2utf8(value), name)
			} else if (inherits(value, "integer")) {
				# min long (should query what it is on the system?)
				value[is.na(value)] <- -2147483648
				ok <- x@pntr$add_column_long(value, name)
			} else if (inherits(value, "logical")) {
				v <- as.integer(value)
				v[is.na(v)] <- 2
				ok <- x@pntr$add_column_bool(v, name)
			} else if (inherits(value, "numeric")) {
				ok <- x@pntr$add_column_double(value, name)
			} else if (inherits(value, "Date")) {
				ok <- x@pntr$add_column_time(as.numeric(as.POSIXlt(value)), name, "days", "")
			} else if (inherits(value, "POSIXt")) {
				tz <- if (length(value) > 0) { attr(value[1], "tzone") } else { "" }
				if (is.null(tz)) tz <- ""
				ok <- x@pntr$add_column_time(as.numeric(value), name, "seconds", tz)
			} else {
				v <- try(as.character(value))
				if (!inherits(v, "try-error")) {
					ok <- x@pntr$add_column_string(enc2utf8(v), name)
				} else {
					ok <- FALSE
				}
			}
			if (!ok) {
				error("[[<-,SpatVector", "cannot add these values")
			}
		}
		x
	}
)


setReplaceMethod("[[", c("SpatVector", "numeric"),
	function(x, i, value) {
		stopifnot(i > 0 && i <= ncol(x))
		vn <- names(x)[i]
		x[[vn]] <- value
		x
	}
)



setMethod("$<-", "SpatVector",
	function(x, name, value) {
		x[[name]] <- value
		x
	}
)




setMethod("vect", signature(x="data.frame"),
	function(x, geom=NULL, crs=NULL, keepgeom=FALSE, quiet=FALSE) {
		
		guessed_geom <- FALSE; lonlat <- FALSE
		if (!is.null(geom)) {
			if (!all(geom %in% names(x))) {
				error("vect", "the variable name(s) in argument `geom` are not in `x`")
			}
		} else {
			if (all(c("lon", "lat") %in% names(x))) { 
				# backwards compatibility
				geom <- c("lon", "lat")
				# guessed_geom <- TRUE	
			} else {
				if (ncol(x) <= 2) { 
					geom <- names(x)				
				} else {
					nms <- tolower(names(x))
					m <- rbind(	match(c("longitude", "latitude"), nms),
                                match(c("decimallongitude", "decimallatitude"), nms),
								match(c("long", "lati"), nms),
								match(c("long", "lat"), nms),								
                                match(c("lon", "lat"), nms),
                                match(c("location.lon", "location.lat"), nms),
                                match(c("location.long", "location.lat"), nms),
                                match(c("location.longitude", "location.latitude"), nms),
                                match(c("location_lon", "location_lat"), nms),
                                match(c("location_long", "location_lat"), nms),
                                match(c("location_longitude", "location_latitude"), nms),
                                match(c("location-lon", "location-lat"), nms),
                                match(c("location-long", "location-lat"), nms),
                                match(c("location-longitude", "location-latitude"), nms),
								match(c("easting", "northing"), nms),
								match(c("xcoord", "ycoord"), nms),
                                match(c("x.coord", "y.coord"), nms),
                                match(c("x_coord", "y_coord"), nms),
                                match(c("x", "y"), nms))
					test <- !apply(is.na(m), 1, any) 
					if (sum(test) == 1) {
						m <- m[test, ]
						geom <- names(x)[m]
						lonlat <- which(test) < 6
					} else if (sum(test) == 0) {
						lon <- which(sapply(nms, function(n) grepl(n, "longitude")))
						lat <- which(sapply(nms, function(n) grepl(n, "latitude")))
						if ((length(lon) == 0) && (length(lat) == 0)) {
							lon <- which(sapply(nms, function(n) grepl(n, "lon")))
							lat <- which(sapply(nms, function(n) grepl(n, "lat")))
						}
						if ((length(lon) == 1) && (length(lat) == 1)) {
							geom <- names(x)[c(lon, lat)]
							lonlat <- TRUE
						} 
					} 
					if (is.null(geom) && (ncol(x) == 2) && all(sapply(x, is.numeric))) { 
						geom <- names(x)
					}
					guessed_geom <- TRUE
				}
			}
			if (is.null(geom)) {
				error("vect", "geom=NULL and no unique lon/lat or x/y variable name pairs detected")
			}
		}
		
		guessed_crs <- FALSE
		if (is.null(crs)) {
			crs <- ""
			if ((guessed_geom && lonlat) || ((!guessed_geom) && grepl("lon", geom[1]) && grepl("lat", geom[2]))) {
				xr <- range(x[,geom[1]], na.rm=TRUE)
				yr <- range(x[,geom[2]], na.rm=TRUE)
				if ((xr[1] > -181) && (xr[2] < 361)  && (yr[1] > -90.01) && (yr[2] < 90.01)) {
					guessed_crs <- TRUE
					crs <- "+proj=longlat"
				}
			}
		} else {
			crs <- character_crs(crs, "vect")
		}
		if (length(geom) == 2) {
			geom <- match(geom[1:2], names(x))
			if (inherits(x[,geom[1]], "integer")) {
				x[,geom[1]] <- as.numeric(x[,geom[1]])
			}
			if (inherits(x[,geom[2]], "integer")) {
				x[,geom[2]] <- as.numeric(x[,geom[2]])
			}
			p <- methods::new("SpatVector")
			p@pntr <- terra:::SpatVector$new()
			x <- terra:::.makeSpatDF(x)

			p@pntr$setPointsDF(x, geom-1, crs, keepgeom)

			p <- messages(p, "vect")
			if (!quiet) {
				if (guessed_geom & guessed_crs) {
					warn("vect", "guessed geom variables and crs")
				} else if (guessed_geom) {
					warn("vect", "guessed geom variables")
				} else if (guessed_crs) {
					warn("vect", "guessed crs")
				}			
			}
			return(p)
		} else if (length(geom) == 1) {
			v <- vect(unlist(x[,geom]), crs=crs)
			if (!keepgeom) {
				x[[geom]] <- NULL
			}
		} else {
			error("vect", "the length of 'geom' must be 1 or 2")
		}
		values(v) <- x
		v
	}
)

setMethod("vect", signature(x="list"),
	function(x, type="points", crs="") {
	
		v <- methods::new("SpatVector")
		if (inherits(x[[1]], "raw")) {
			v@pntr <- SpatVector$new()
			v@pntr$addWKB(x)
		} else {
			x <- lapply(x, function(i) {
				if (inherits(i, "SpatVector")) return(i)
				vect(i, type=type)
			})
			x <- svc(x)
			v@pntr <- x@pntr$append()
		}
		if (crs != "") {
			crs(v) <- crs
		}
		messages(v, "vect")
	}
)




setMethod("query", signature(x="SpatVectorProxy"),
	function(x, start=1, n=nrow(x), vars=NULL, where=NULL, extent=NULL, filter=NULL, sql=NULL, dialect="", what="") {
		f <- x@pntr$v$source
		slayer <- x@pntr$v$layer
		#1058
		layer <- paste0("\"", slayer, "\"")

		e <- x@pntr$v$read_extent
		if (is.null(extent)) {
			if (length(e) == 4) {
				extent = ext(e);
			}
		} else {
			if (length(e) == 4) {
				extent = intersect(ext(e), extent);
				if (is.null(extent)) {
					error("query", "extent does not intersect with x")
				}
			}
		}
		if (is.null(vars)) {
			vars <- "*"
		} else {
			vars <- stats::na.omit(unique(vars))
			nms <- names(x)
			if (!all(vars %in% nms)) {
				error("query", "not all vars are variable names")
			} else if (length(vars) < length(nms))  {
				vars <- paste(vars, collapse=", ")
			}
		}

		if (!is.null(sql)) {
			qy <- as.character(sql)
		
		} else {
			qy <- ""
			if (!is.null(where)) {
				qy <- paste("SELECT", vars, "FROM", layer, "WHERE", where[1])
			} else {
				qy <- paste("SELECT", vars, "FROM", layer)
			}
			nr <- nrow(x)
			start <- start-1
			if (start > 0) {
				if (n >= (nr-start)) {
					qy <- paste(qy, "OFFSET", format(start, scientific=FALSE))
				} else {
					n <- min(n, nr-start)
					qy <- paste(qy, layer, "LIMIT", n, "OFFSET", format(start, scientific=FALSE))
				}
			} else if (n < nr) {
				n <- min(n, nr)
				qy <- paste(qy, "LIMIT", n)
			}
		}
		
		if (qy != "") {
			if (x@pntr$v$read_query != "") {
				error("query", "A query was used to create 'x'; you can only subset it with extent or filter")
			}
		} else {
			layer <- slayer
		}

		p <- vect(f, layer, query=qy, extent=extent, filter=filter, crs="", FALSE, what=what, dialect=dialect)
		if (what == "attributes") {
			p <- values(p)
		}
		p
	}
)


vector_layers <- function(filename, delete="", return_error=FALSE) {
	p <- SpatVector$new()
	if (any(delete != "")) {
		delete <- trimws(delete)
		ok <- p$delete_layers(filename, delete, return_error[1])
		messages(p, "vector_layers")
		invisible(ok)
	} else {
		out <- p$layer_names(filename)
		messages(p, "vector_layers")
		out
	}
}

