* Authors:
* Chuntao Li, Ph.D. , China Stata Club(爬虫俱乐部)(chtl@zuel.edu.cn)
* Yuan Xue, China Stata Club(爬虫俱乐部)(xueyuan19920310@163.com)
* October 16st, 2019
* Program written by Dr. Chuntao Li and Yuan Xue
* Used to extracts the longitude and latitude of Chinese address from Baidu Map API v3.0
* and can only be used in Stata version 14.0 or above
* Original Data Source: http://api.map.baidu.com
* Please do not use this code for commerical purpose

cap prog drop cngcode

program cngcode
	version 14.0
	syntax, baidukey(string) [PROvince(string) CITy(string) ADDress(string) DIStrict(string) FULLADDress(string) LATitude(string) LONGitude(string) ffirst COORDtype(string)]

	if "`province'" == "" & "`city'" == "" & "`address'" == "" & "`district'" == "" & "`fulladdress'" == "" {
		di as error "error: must specify at least one option of 'province', 'city', 'district', 'address' and 'fulladdress'"
		exit 198
	}

	if "`ffirst'" != "" & "`fulladdress'" == "" {
		di as error "error: must specify specify option 'fulladdress' in order to use ffirst"
		exit 198
	}

	if "`coordtype'" == "" local coordtype = "bd09ll"
	else if !inlist("`coordtype'", "bd09ll", "bd09mc", "gcj02ll", "wgs84ll") {
		di as error "You can only specify the option coordtype() among bd09ll, bd09mc, gcj02ll or wgs84ll"
	}

	qui {
		tempvar blank work1 work2 baidumap
		gen `blank' = ""
		if "`province'" == "" local province `blank'
		if "`city'" == "" local city `blank'
		if "`district'" == "" local district `blank'
		if "`address'" == "" local address  `blank'
		if "`longitude'" == "" local longitude longitude
		if "`latitude'" == "" local latitude latitude
		if "`ffirst'" != "" {
			gen `work1' = `fulladdress'
			gen `work2' = `province' + `city' + `district' + `address'
		}
		else if "`province'" == "`blank'" & "`city'" == "`blank'" & "`district'" == "`blank'" & "`address'" == "`blank'" {
			gen `work1' = `fulladdress'
			gen `work2' = `province' + `city' + `district' + `address'
		}
		else {
			gen `work1' = `province' + `city' + `district' + `address'
			if "`fulladdress'" == "" gen `work2' = ""
			else gen `work2' = `fulladdress'
		}

		drop `blank'
		if c(stata_version) >= 15 {
			replace `work1' = geturi(`work1')
			replace `work2' = geturi(`work2')
		}
		else {
			replace `work1' = upper(subinstr(tobytes(`work1', 1), "\x", "%", .))
			replace `work2' = upper(subinstr(tobytes(`work2', 1), "\x", "%", .))
		}

		gen `baidumap' = ""
		forvalues i = 1/`=_N' {
			replace `baidumap' = fileread(`"http://api.map.baidu.com/geocoding/v3/?address=`=`work1'[`i']'&output=json&ak=`baidukey'&callback=showLocation&ret_coordtype=`coordtype'"') in `i'
			local times = 0
			while filereaderror(`baidumap'[`i']) != 0 {
				sleep 1000
				local times = `times' + 1
				replace `baidumap' = fileread(`"http://api.map.baidu.com/geocoding/v3/?address=`=`work1'[`i']'&output=json&ak=`baidukey'&callback=showLocation&ret_coordtype=`coordtype'"') in `i'
				if `times' > 10 {
					noi disp as error "Internet speeds is too low to get the data"
					exit `=filereaderror(`baidumap'[`i'])'
				}
			}
			if index(`baidumap'[`i'], "AK有误请检查再重试") {
				noisily di as error "error: please check your baidukey"
				exit 198
			}
			else if index(`baidumap'[`i'], "lack address or location") | index(`baidumap'[`i'], "无相关结果") {
				replace `baidumap' = fileread(`"http://api.map.baidu.com/geocoding/v3/?address=`=`work2'[`i']'&output=json&ak=`baidukey'&callback=showLocation&ret_coordtype=`coordtype'"') in `i'
				local times = 0
				while filereaderror(`baidumap'[`i']) != 0 {
					sleep 1000
					local times = `times' + 1
					replace `baidumap' = fileread(`"http://api.map.baidu.com/geocoding/v3/?address=`=`work2'[`i']'&output=json&ak=`baidukey'&callback=showLocation&ret_coordtype=`coordtype'"') in `i'
					if `times' > 10 {
						noi disp as error "Internet speeds is too low to get the data"
						exit `=filereaderror(`baidumap'[`i'])'
					}
				}
				if index(`baidumap'[`i'], "lack address or location") | index(`baidumap'[`i'], "无相关结果") {
					noisily di as text "Address in Obs `i' is missing or incorrect, no location extracted"
				}
			}
		}
		gen `longitude' = ustrregexs(1) if ustrregexm(`baidumap', `""lng":(.*?),"')
		gen `latitude'  = ustrregexs(1) if ustrregexm(`baidumap', `""lat":(.*?)\}"')
		destring `longitude' `latitude', replace
	}
end