*! geoboundary v1.1 (08 Dec 2024)
*! Asjad Naqvi (asjadnaqvi@gmail.com)

* v1.1 (08 Dec 2024): Added geoboundaries meta data. Added GDAM as an additional source. Added source(). Lower cases are now allowed. Added meta data.
* v1.0 (23 Nov 2024): First release


/*
Data source:
GeoBoundaries: https://www.geoboundaries.org/, https://github.com/wmgeolab/geoBoundaries/
GADM:
*/

/*

The Geographic Information System (GIS) data provided herein is for informational/educational purposes only and is not intended for use
as a legal or engineering resource. While every effort has been made to ensure the accuracy and reliability of the data, it is provided
"as is" without warranty of any kind.

The data provided through this GIS package assumes no liability for any inaccuracies, errors, or omissions in the data,
nor for any decision made or action taken based on the information contained herein.
Users of this data are responsible for verifying its accuracy and suitability for their intended purposes.

Please be advised that GIS data may be subject to change without notice due to updates, corrections, or other modifications.
Users are encouraged to consult the original data sources or contact the provider for the most current information.

By accessing or using the GIS data provided through this package, you acknowledge and agree to these terms and conditions.


All files are in the standard EPSG: 4326 (WGS84) projection.

*/


cap prog drop geoboundary

program define geoboundary, rclass
version 15

syntax anything,  [level(string) convert replace remove name(string) source(string) country(string) iso(string) NOSEParator region(string) length(string) any(string) strict ]


	if "`anything'" == "WLD" | "`anything'"=="wld" {
		local baseurl https://github.com/wmgeolab/geoBoundaries/raw/refs/heads/main/releaseData/CGAZ
		local skip 1
	}
	else if "`anything'" == "meta" {
		gettoken subcmd 0: 0, parse(", ")
		if "`subcmd'" == "meta" _geometa `0'
		*noi return list
		return local gadm `r(iso3_gadm)'
		return local geob `r(iso3_geob)'
	}
	else {
		local baseurl https://github.com/wmgeolab/geoBoundaries/raw/refs/heads/main/releaseData/gbOpen/
		local skip 0
	}



	if "`replace'"!= "" local rep replace

	local length1 : word count `level'
	local length2 : word count `anything'

	if "`anything'" != "meta" {
		if "`source'" != ""  {
			if !inlist("`source'", "geoboundaries", "gadm") {
				di as error "Correct {bf:source()} options are {ul:geoboundaries} or {ul:gadm}."
			}
		}
		else {
			local source geoboundaries
			di in green "Option {bf:source()} not specified. Assuming {bf:geoboundaries} as the default."
		}
	}



	///////////////
	//  checks   //
	///////////////


	if "`source'" == "gadm" local level ALL

	if "`anything'" != "meta" {
		forval i = 1/`length2' {
			local lvl : word `i' of `anything'

			if length("`lvl'") != 3 {
				display as error "`lvl' is an invalid ISO3 code."
				exit
			}
		}
	}


	local errcount = 0

	forval i = 1/`length1' {
		local lvl : word `i' of `level'
		local lvl = upper("`lvl'")

		if !inlist("`lvl'", "ADM0", "ADM1", "ADM2", "ADM3", "ADM4", "ADM5", "ALL") {
			display as error "Option {ul:`lvl'} is not valid. Valid options are {ul:ADM0}, {ul:ADM1}, {ul:ADM2}, {ul:ADM3}, {ul:ADM4}, {ul:ADM5}, {ul:ALL}."
			local ++errcount
		}

		if `errcount' > 0 exit
	}

	if "`level'" == "ALL" | "`level'"=="all" {
		local level ADM0 ADM1 ADM2 ADM3 ADM4 ADM5
		local length1 : word count `level'
	}


	//////////////////////////
	//  geoBoundaries loop  //
	//////////////////////////

	quietly {

		if "`source'" == "" | "`source'" == "geoboundaries" & "`anything'"!="meta" {

			foreach x of local anything {

				local x1 = upper("`x'")

				forval i = 1/`length1' {
					local lvl : word `i' of `level'
					local lvl = upper("`lvl'")

					// fetch
					noisily display in yellow _newline "`x1'-`lvl': Fetching" _continue

					local _check = 0

					if `skip'==0 {
						foreach j in shp prj shx dbf {
							capture copy "`baseurl'/`x1'/`lvl'/geoBoundaries-`x1'-`lvl'.`j'" "`x1'_`lvl'.`j'", `rep'

							if _rc!= 0 {
								local ++_check
							}
						}
					}
					else {
						copy "`baseurl'/geoBoundariesCGAZ_`lvl'.zip" "WLD_`lvl'.zip", `replace'
						unzipfile WLD_`lvl', `rep'

						// delete the zip
						capture erase 	"WLD_`lvl'.zip"  // windows
						capture rm 		"WLD_`lvl'.zip"	 // MAC

						local check = 0
					}


					if `_check' != 0 {
						noisily display in red _continue " > Does not exist."
					}
					else {

						// convert (if specified)
						if "`convert'" != "" {

							noisily display in yellow _continue " > Converting to Stata format"

							if `skip'==0 {
								if "`name'"!="" {
									spshape2dta `x1'_`lvl', replace saving(`name'_`lvl')
								}
								else {
									spshape2dta `x1'_`lvl', replace
								}
							}
							else {
								if "`name'"!="" {
									spshape2dta geoBoundariesCGAZ_`lvl', replace saving(`name'`lvl')
								}
								else {
									spshape2dta geoBoundariesCGAZ_`lvl', replace saving(WLD_`lvl')
								}
							}
						}

						// delete raw files (if specified)
						if "`remove'" != "" {
							noisily display in yellow _continue  " > Deleting raw shapefiles"

							if `skip'==0 {
								foreach j in shp prj shx dbf {
									capture erase 	"`x1'_`lvl'.`j'" // windows
									capture rm 		"`x1'_`lvl'.`j'"	// MAC
								}
							}
							else {
								foreach j in shp prj shx dbf {
									capture erase 	"geoBoundariesCGAZ_`lvl'.`j'"  // windows
									capture rm 		"geoBoundariesCGAZ_`lvl'.`j'"  // MAC


								}
							}
						}
					}
				}
			}
		}


		if "`source'" == "gadm" & "`anything'"!="meta" {

			foreach x of local anything {
			local x1 = upper("`x'")

				noisily display in yellow _newline "`x1'-`lvl': Fetching" _continue

				copy "https://geodata.ucdavis.edu/gadm/gadm4.1/shp/gadm41_`x1'_shp.zip" "`x1'.zip", `rep'

				unzipfile `x1', replace // ifilter(`"(.*\.(dbf)$)"')

				local x2  = lower("`x1'")
				local files : dir "." files "gadm41_`x1'_*.dbf"


				foreach y of local files {

					local layer = ustrregexra("`y'", ".dbf", "")


					local xtemp = ustrregexra("`layer'", "gadm41_`x2'_", "")
					local xtemp = "ADM" + "`xtemp'"

					if "`convert'"!= "" {

						noisily display in yellow _newline "`x1'-`xtemp' > Converting to Stata format" _continue


						if "`name'"!="" {
							spshape2dta `layer', replace saving(`name'_`xtemp')
						}
						else {
							spshape2dta `layer', replace saving(`x1'_`xtemp')
						}
					}

					// delete raw files (if specified)
					if "`remove'" != "" {
						noisily display in yellow _continue  " > Deleting raw shapefiles"

						capture erase 	"`x1'.zip"  // windows
						capture rm 		"`x1'.zip"  // MAC

						foreach j in shp prj shx dbf cpg {
							capture erase 	"`layer'.`j'"  // windows
							capture rm 		"`layer'.`j'"  // MAC
						}
					}
				}
			}
		}
	}

end

program define _geometa, rclass
 version 11

 	syntax [, country(string) iso(string) length(real 30) level(string) any(string) strict NOSEParator region(string) ]

	preserve
	quietly {

		use "https://github.com/asjadnaqvi/stata-geoboundary/raw/refs/heads/main/GIS/geoboundary_meta.dta", clear
		*use geoboundary_meta, clear  // add GitHub link

		foreach x of varlist _all {
			char `x'[varname] `"`: var label `x''"'
		}

		gen _markme = .

		foreach x of local iso {
			if "`strict'" != "" {
				replace _markme = 1 if ustrregexm(iso3, "\b(`x')\b", 1)==1
			}
			else {
				replace _markme = 1 if ustrregexm(iso3, "`x'", 1)==1
			}
		}

		foreach x of local country {
			if "`strict'" != "" {
				replace _markme = 1 if ustrregexm(name, "\b(`x')\b", 1)==1
			}
			else {
				replace _markme = 1 if ustrregexm(name, "`x'", 1)==1
			}
		}

		foreach x of local region {
			if "`strict'" != "" {
				replace _markme = 1 if ustrregexm(wb_regioncode, "\b(`x')\b", 1)==1
			}
			else {
				replace _markme = 1 if ustrregexm(wb_regioncode, "`x'", 1)==1
			}
		}

		foreach x of local level {
			if "`strict'" != "" {
				replace _markme = 1 if ustrregexm(adm_geoboundary, "\b(`x')\b", 1)==1
				replace _markme = 1 if ustrregexm(adm_gadm       , "\b(`x')\b", 1)==1
			}
			else {
				replace _markme = 1 if ustrregexm(adm_geoboundary, "`x'", 1)==1
				replace _markme = 1 if ustrregexm(adm_gadm       , "`x'", 1)==1
			}

		}

		foreach x of local any {
			foreach y of varlist _all {
				if "`strict'" != "" {
					capture replace _markme = 1 if ustrregexm(`y', "\b(`x')\b", 1)==1
				}
				else {
					capture replace _markme = 1 if ustrregexm(`y', "`x'", 1)==1
				}
			}
		}



		if "`noseparator'" == "" {
			local mysep sepby(iso3)
		}
		else {
			local mysep separator(0)
		}


		sort name iso3 adm
		noisily list name iso3 adm* geob_year continent un_region wb_region wb_regioncode if _markme==1, string(`length') header table noobs subvarname `mysep'

		quietly levelsof iso3 if _markme==1 & !missing(adm_gadm), clean local(iso3_gadm)
		quietly levelsof iso3 if _markme==1 & !missing(adm_geob), clean local(iso3_geob)

		return local iso3_gadm = "`iso3_gadm'"
		return local iso3_geob = "`iso3_geob'"



	}
	restore



end

************************
***** END OF FILE ******
************************