.packageName <- "gmaps"
#Color functions for gmaps package
reds<-function(level)rgb(level,0,0)
greens<-function(level)rgb(0,level,0)
blues<-function(level)rgb(0,0,level)
#Gradient Legends
#by Andrew Redd
#C 2007

#TODO
#1. make width Calculation
#2. make magrin calculation more presice for longer tick marks
#3. Add Valid Details function

gradientLegendGrob<-function(
	at=seq(0,1,length=5), 	#where to place tick marks 
	axis.min=min(at),		#to specify minimun
	axis.max=max(at),		#to specify maximum
	gradient.range=c(0,1),
	labels=as.character(at),#specify labels for tick marks
	col.fun=grey,		#function to specify gradient
	delta=.01,			#defines level of precicion of gradient 
	vertical=F,			#controls orientation
	reverse=F,			#controls which side to put the axis on
	name=NULL,
	gp=NULL,
	vp=NULL,
	...
){	
	#generate Rectangles
	if(delta<=0||delta>=1)stop("delta must be between 0 and 1.")
	if(length(at)!=length(labels))stop("labels and at must be of the same length")
	z<-(seq(gradient.range[1],gradient.range[2],by=delta)-delta/2)[-1]
	y<-if(vertical) unit(z,"npc") else unit(0.5,"npc")
	x<-if(!vertical)unit(z,"npc") else unit(0.5,"npc")
	height<-if(vertical)  delta else unit(1.5,"char")
	width	<-if(!vertical) delta else unit(1.5,"char")
	just<-if(vertical)
		if(reverse) c("right","center") else c("left","center") else
	 	if(reverse) c("center","top") else c("center","bottom") 
	cols<-col.fun(z)
	gp1<-do.call(gpar,append(list(col=NA,fill=cols),gp))
	#make Gradient
	legvp<-viewport(name="legvp",width=unit(1,"npc")-unit(1,"char"),height=unit(1,"npc")-unit(1,"char"))
	#make Gradient Border
	rectangles<-rectGrob(name="gradient",x=x,y=y,height=height,width=width,just=just,gp=gp1,vp=legvp)
	border<-if(vertical)rectGrob(name="gradBorder",x=x,width=width,just=just,vp=legvp)
			else	  rectGrob(name="gradBorder",y=y,height=height,just=just,vp=legvp)
	#Make Ticks
	ticks<-if(is.numeric(at)){
		w<- (at-axis.min)/(axis.max-axis.min)
		x0<-if(!vertical)  unit(w,"npc") else unit(.5,"npc")
		x1<-if(!vertical)  unit(w,"npc") else unit(.5,"npc")+if(reverse) unit(.4,"lines") else unit(-.4,"lines")
		y0<-if(vertical) unit(w,"npc") else unit(.5,"npc")
		y1<-if(vertical) unit(w,"npc") else unit(.5,"npc")+if(reverse) unit(.4,"lines") else unit(-.4,"lines")
		segmentsGrob(x0=x0,x1=x1,y0=y0,y1=y1,vp=legvp,name="ticks")
	} else NULL
	#Make Labels
	axis.labels<-if(all(!is.na(labels))){
		w<- (at-axis.min)/(axis.max-axis.min)
		x<-if(!vertical) unit(w,"npc") else if(reverse) unit(.5,"npc")+unit(.5,"lines") else unit(.5,"npc")-unit(.5,"lines")
		y<-if(vertical)  unit(w,"npc") else if(reverse) unit(.5,"npc")+unit(.5,"lines") else unit(.5,"npc")-unit(.5,"lines")
		just<-if(vertical) if(reverse)c("left","center") else c("right","center") else
					 if(reverse)c("center","bottom") else c("center","top")
		textGrob(labels,x=x,y=y,just=just,name="labels",vp=legvp)
	} else NULL
	gTree(at=at,axis.min=axis.min,axis.max=axis.max,col.fun=col.fun,delta=delta,vertical=vertical,reverse=reverse,
		childrenvp=legvp,
		children=gList(rectangles,border,ticks,axis.labels),
		name=name,gp=gp,vp=vp,
		cl="gradientLegendGrob")
}
grid.gradientLegendGrob<-function(...){
	grad<-gradientLegendGrob(...)
	grid.draw(grad)
	invisible(grad)
}
widthDetails.gradientLegendGrob<-function(x){
	if(x$vertical) unit(1,"null") else{
		unit(0.1,"lines")+widthDetails(x$children[[2]])+widthDetails(x$children[[3]])+widthDetails(x$children[[4]])
	}
}
heightDetails.gradientLegendGrob<-function(x){
	if(!x$vertical) unit(1,"null") else{
		unit(0.1,"lines")+widthDetails(x$children[[2]])+widthDetails(x$children[[3]])+widthDetails(x$children[[4]])
	}
}


#grid.gradientLegendGrob()
#grid.gradientLegendGrob(vertical=T)
#g0<-grid.gradientLegendGrob(vertical=T,reverse=T)
#grid.gradientLegendGrob(1:5,col.fun=hsv,delta=1/1000)
#rb<-function(p)rgb(p,0,1-p)
#g1<-grid.gradientLegendGrob(1:10,col.fun=rb)
#widthDetails(g1)
#widthDetails(g0)
#mapGrob functions
#Andrew Redd
#Version 0.0.2

#TODO
#


#support function for helping grid graphics
convert.coordinates.for.grid<-function(cod,regions=".",...){
	x=cod$x
	y=cod$y
	id<-numeric(0)
	id.marker<-1
	for(i in 1:length(x)){
		if (is.na(x[i])){
			id[i]<-id.marker
			id.marker<-id.marker+1
		}else{
			id[i]<-id.marker
		}
	}
	region.id<-rep(NA,length(id))
	if(identical(regions,".")){
		region.id<-id
		region.names<-cod$names
	} else if(length(regions)==1){
		region.names<-regions
		region.id<-rep(1,length(id))
	} else {
		region.names<-regions
		regions<-tolower(regions)
		region.map<-1:length(regions)
		names(region.map)<-regions
		for(r in regions){
			name.matches<-grep(r,cod$names)
			region.id[id %in% name.matches]<-region.map[r]
		}
	}
	list(x=x,y=y,range=cod$range,names=cod$names,id=id,region.id=region.id,region.names=region.names)
}

makeMapViewports<-function(coord,asp=1){
	xrange<-coord$range[1:2]
	yrange<-coord$range[3:4]
	vpStack(
		viewport(name="maplayout",layout=grid.layout(1,1,
			widths=diff(xrange),
			heights=diff(yrange)*asp,
			respect=TRUE)),
		viewport(name="mapvp",layout.pos.row=1,layout.pos.col=1,
			xscale=xrange,
			yscale=yrange))
}
makeMapPolygons<-function(coord,fill.col=NULL,gp=NULL){
	n<-length(coord$region.names)
	if(!is.null(fill.col))fill.cols<-rep(fill.col,n)
	polygons<-vector("list",n)
	for(i in 1:n){
		polygons[[i]]<-if(any(coord$region.id==i))polygonGrob(
			name=paste("mappolygon",coord$region.names[i],sep=":"),
			unit(coord$x[coord$region.id==i],"native"),
			unit(coord$y[coord$region.id==i],"native"),
			gp=if(is.null(fill.col)) gp else gpar(fill=fill.col[i],gp),
			vp=vpPath("maplayout","mapvp")) else NULL
	}
	do.call("gList",polygons)
}
mapGrob<-function(
	database = "world", 
	regions=".",
	exact=F,
	xlim=NULL,
	ylim=NULL,
	name=NULL,
	fill.col=NA,#superceeds gp$fill if specified
	gp=NULL,
	vp=NULL,
	asp=1,
	...) 
{
	#validity checks
	if(!require(maps))stop("maps package is required")
	if(!require(grid))stop("grid graphics is required")

	#Get Coordinates for plotting regions
	c1<-map(database=database,regions=regions,exact=exact,fill=T,xlim=xlim,ylim=ylim,plot=F,...)
	coord<-convert.coordinates.for.grid(c1,regions)

	#Grob generation
	#mapvp<-viewport(height=unit(1,"npc"),width=unit(1,"npc"),xscale=coord$range[1:2],yscale=coord$range[3:4],name="map")
	#map<-gTree(,vp=mapvp)
	mapvp<-makeMapViewports(coord,asp=asp)
	mappolys<-makeMapPolygons(coord,fill.col=fill.col,gp=gp)
	gTree(coord=coord,name=name,gp=gp,vp=vp,
		childrenvp=mapvp,
		children=mappolys,
		cl="mapGrob")
}

grid.mapGrob<-function(...){
	map<-mapGrob(...)
	grid.draw(map)
	invisible(map)
}
validDetails.mapGrob<-function(x){
	x
}


USALevelPlot<-function(
	states,
	levels,
	col.fun=grey,
	alaska='alaska'%in%tolower(states),
	hawaii='hawaii'%in%tolower(states),
	normalize=TRUE,
	name=NULL,
	vp=NULL,
	gp=NULL,
	asp=1.4,
	...
){
	#validity checks
	if(!require(grid))stop("grid package is required!")
	if(!require(maps))stop("maps package is required!")
	if(!require(mapdata, quietly = TRUE))message("Higher resolution could be obtained if the mapdata package were installed.")

	#Contiguous USA
	if(!normalize && (min(levels)<0 || max(levels)>1))stop("Levels out of range, use normalize=TRUE")
	lnorm<-if(normalize) (levels-min(levels))/diff(range(levels)) else levels 
	col<-col.fun(lnorm)
	map<-mapGrob("state",regions=states,name="mapUSAContiguous",fill.col=col,gp=gp,vp=vp,asp=asp,...)
	
	#Alaska
	if(alaska ){
		if(length(grep("alaska",tolower(states)))==0)stop("alaska=TRUE option specified but Alaska data could not be found.")
		alaskavp<-viewport(x=unit(0,"npc"),y=unit(0,"npc"),width=unit(.3,"snpc"),height=unit(.3,"snpc"),
			name="alaskavp",just=c("left","bottom"))
		alaskafill<-col[grep("alaska",tolower(states))]
		alaskamap<-mapGrob(if(require(mapdata, quietly = TRUE)) "worldHires" else "world" ,"USA:Alaska",exact=F, 
			name="mapUSAAlaska",xlim=c(-178,-130.01306),ylim=c(50,72),
			fill.col=alaskafill,gp=gp,
			vp=vpStack(map$childrenvp,alaskavp),asp=1)
		map<-addGrob(map,alaskamap)
		}

	#Hawaii
	if(hawaii){
		if(length(grep("hawaii",tolower(states)))==0)stop("hawaii=TRUE option specified but Hawaii data could not be found.")
		hawaiivp<-viewport(x=unit(.3,"snpc"),y=unit(0,"snpc"),width=unit(.3,"snpc"),height=unit(.3,"snpc"),
			name="hawaiivp",just=c("left","bottom"))
		hawaiifill<-col[grep("hawaii",tolower(states))]
		hawaiimap<-mapGrob(if(require(mapdata, quietly = TRUE)) "worldHires" else "world" ,"Hawaii",exact=F, 
			name="mapUSAHawaii",xlim=c(-161.2,-154.7),ylim=c(18.9,23.2),
			fill.col=hawaiifill,gp=gp,
			vp=vpStack(map$childrenvp,hawaiivp),asp=1)
		map<-addGrob(map,hawaiimap)
		}

	#plot results
	map
}
grid.USALevelPlot<-function(...){
	map<-USALevelPlot(...)
	grid.draw(map)
	invisible(map)
}

#examples/test code
#data(state)
#p<-rbeta(50,5,2)
#map1<-grid.USALevelPlot(state.name,p,normalize=F)
#grid.newpage()
#map2<-grid.USALevelPlot(state.name,p,normalize=T,alaska=T,hawaii=T,col.fun=function(x)hsv(0,x))
#childNames(map2)
