User:DemocraticLuntz/CenPopExternal.js

Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
/**<nowiki>
 * Note that this script will only run on the 'Project:CenPop/Script' page.
 * This script is based on the AWB script by Joeytje50 which in turn is based on the downloadable AutoWikiBrowser.
 * 
 * @licence
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 * http://www.gnu.org/copyleft/gpl.html
 * @version 1.0
 * @author Jacob Alperin-Sheriff
 */
 
/*** Load population data coming from pagename (now from the Census Bureau 
 * website API) into array 
 HOW TO DO IT: think while getting gats gorgeous

@pagename is the name of the page to load from
@hasHeader is whether or not the first line is a header
***/

CenPop.state_fips={'01': 'Alabama', '02': 'Alaska', '04': 'Arizona',
        '05': 'Arkansas', '06': 'California', '08': 'Colorado', '09': 'Connecticut',
        '10': 'Delaware', '11': 'District of Columbia', '12': 'Florida',
        '13': 'Georgia', '15': 'Hawaii', '16': 'Idaho', '17': 'Illinois',
        '18': 'Indiana', '19': 'Iowa', '20': 'Kansas', '21': 'Kentucky',
        '22': 'Louisiana','23': 'Maine', '24': 'Maryland', '25': 'Massachusetts',
        '26': 'Michigan','27': 'Minnesota', '28': 'Mississippi', '29': 'Missouri',
        '30': 'Montana', '31': 'Nebraska', '32': 'Nevada', '33': 'New Hampshire',
        '34': 'New Jersey', '35': 'New Mexico', '36': 'New York',
        '37': 'North Carolina', '38': 'North Dakota', '39': 'Ohio', '40': 'Oklahoma',
        '41': 'Oregon', '42': 'Pennsylvania', '44': 'Rhode Island',
        '45': 'South Carolina', '46': 'South Dakota', '47': 'Tennessee',
        '48': 'Texas', '49': 'Utah', '50': 'Vermont', '51': 'Virginia',
        '53': 'Washington', '54': 'West Virginia', '55': 'Wisconsin',
        '56': 'Wyoming'};

/* KEY to be used for making API queries to Census */
CenPop.api_key='5ccd0821c15d9f4520e2dcc0f8d92b2ec9336108';

/* Beginning of Census URL for queries */
CenPop.begin_census_URL='https://api.census.gov/data/';

/* part of Census URL for queries following estimate year, before 
summary level to get stuff from ('place' or 'county') 

If every used this should change GEONAME -> NAME, 2019 onward
*/
CenPop.mid_census_URL='/pep/population?get=POP,GEONAME&for=';

CenPop.ref_str="(?<ref>(?:<ref\\s+name\\s*=\\s*\"?([^\">/]*)\"?\\s*>.*?\\</ref>)|(?:<ref>.*?\\</ref>)|(?:<ref\\s+name\\s*=\\s*\"?(?<refname>[^\">\/]*)\"?\\s*/\\s*>))?";

CenPop.pop_mention_regexes=[{"regex":
/(population was )([\d,]+)( (?:at\s*|as of\s*) the \[?\[?)(\d+)( United States Census\|?)(\d+)( census\]?\]?\.)((?:<ref\s+name\s*=\s*"?([^">\/]*)"?\s*>.*?<\/ref>)|(?:<ref\s+name\s*=\s*"?([^">\/]*)"?\s*\/\s*>))?/i,
"replacer":function(match,p1,p2,p3,p4,p5,p6,p7,p8, p9) {
	let curr_year=$('.estYearText').val();
	let curr_pop=new Intl.NumberFormat().format(parseInt(CenPop.pop_page.curr_place[CenPop.est_column]));
	if(p8 && /\<\/ref\>/.test(p8)) {
		console.log("p8=",p8," p9=",p9)
		CenPop.removed_refs[p9]=p8;
	}
	return p1+curr_pop+p3+curr_year+p5+curr_year+p7; }
},
{"regex":/(At the )((?:\[\[(?:\d+\s+)?United States Census)?\s*(?:\d+)?\|?\s*(?:\d+)\s+census\]?\]?\,? the population was )([\d,]+)\.(\s*)((?:<ref\s+name\s*=\s*"?([^">\/]*)"?\s*>.*?<\/ref>)|(?:<ref\s+name\s*=\s*"?([^">\/]*)"?\s*\/\s*>))?/i,
"replacer":function(match,p1,p2,p3,p4,p5,p6) {
	let curr_year=$('.estYearText').val();
	let curr_pop=new Intl.NumberFormat().format(parseInt(CenPop.pop_page.curr_place[CenPop.est_column]));
	if(p5 && /\<\/ref\>/.test(p5)) {
		console.log("p5=",p5," p6=",p6)
		CenPop.removed_refs[p6]=p5;
	}
	return p1+`[[${curr_year} United States census|${curr_year} census]], the population was ${curr_pop}.`+p4; }
	
},
{"regex":new RegExp("the\\s*(\\[?\\[?(?:\\d+\\s+)?United States Census)?\\s*(?:\\d+)?\\|?\\s*(?:\\d+)\\s+census\\]?\\]?\,?"+
"(?<verbiage1>(?:[A-Za-z\\-]+\\s){1,3})had a population of ([\d,]+)\.(?<finalspace>\s*)"+CenPop.ref_str),
	"replacer":function(match,groups) {
		console.log("groups=",groups)
		let curr_year=$('.estYearText').val();
	let curr_pop=new Intl.NumberFormat().format(parseInt(CenPop.pop_page.curr_place[CenPop.est_column]));
	if(groups['ref'] && groups['refname']) {
		CenPop.removed_refs[groups['refname']]=groups['ref'];
	}
	return `the [[${curr_year} United States census|${curr_year} census]],${groups["verbiage1"]}had a population of ${curr_pop}.${groups["finalspace"]}`; 


  }
},
{"regex":new RegExp("the\\s*\\[?\\[?(?:(?:\\d+\\s+)?United States Census)?\\s*(?:\\d+)?\\|?\\s*(?:\\d+)\\s+census\\]?\\]?\,?"+
"\\s*the population (?<verbiage1>(?:[A-Za-z\\-\']+\\s){0,4})(?<verbiage2>was|is) ([\\d,]+)\\.(?<finalspace>\s*)"+CenPop.ref_str,"i"),
	"replacer":function() {
		console.log("arguments=",arguments);
		groups=arguments[arguments.length-1]
	//	console.log("groups=",groups)
		let curr_year=$('.estYearText').val();
	let curr_pop=new Intl.NumberFormat().format(parseInt(CenPop.pop_page.curr_place[CenPop.est_column]));
	if(groups['ref'] && groups['refname']) {
		CenPop.removed_refs[groups['refname']]=groups['ref'];
	}
	return `the [[${curr_year} United States census|${curr_year} census]],the population ${groups["verbiage1"]}${groups["verbiage2"]} ${curr_pop}.${groups["finalspace"]}`; 


  }
},
{"regex":new RegExp("the\\s*\\[?\\[?(?:(?:\\d+\\s+)?United States Census)?\\s*(?:\\d+)?\\|?\\s*(?:\\d+)\\s+(?:U\\.S\\. |United States )?census\\]?\\]?\,?"+
"\\s*the (?<verbiage1>(?:[A-Za-z\\-\']+\\s+){0,4})population\\s*(?<verbiage2>(?:was|is|of))\\s*([\\d,]+)\\.(?<finalspace>\\s*)"+CenPop.ref_str,"i"),
	"replacer":function() {
		console.log("arguments=",arguments);
		groups=arguments[arguments.length-1]
		for(y in groups) console.log(y);
		let curr_year=$('.estYearText').val();
	let curr_pop=new Intl.NumberFormat().format(parseInt(CenPop.pop_page.curr_place[CenPop.est_column]));
	if(groups['ref'] && groups['refname']) {
		CenPop.removed_refs[groups['refname']]=groups['ref'];
	}
	return `the [[${curr_year} United States census|${curr_year} census]], the ${groups["verbiage1"]}population ${groups["verbiage2"]} ${curr_pop}.${groups["finalspace"]}`; 


  }
}

];
/* Use regular expressions to replace autogenerated references in the text of place articles, i.e. as of census the population was x
   Hopefully the ones that have been messed with will have people to do it manually but ones that haven't definitely won't 
   */
CenPop.api.replaceDecennialReferences = function(content)  {
	var rx_obj;
			console.warn("REGEXP: ",content.match(new RegExp(CenPop.ref_str)));

/* TODO: bug where it deletes good <ref>.*</ref> references subsequent to the "as of", either this is insurmountable
 or we can replace the old references with one of our own, for now, commenting this out
 Regarding the [[https://en.wikipedia.org/w/index.php?title=Highwood,_Illinois&oldid=prev&diff=1077306514|Highwood, Illinois edit]], I 
must have missed your response initially. I am working on a somewhat-delayed project of getting all places (incorporated and unincorporated census-designated places, but not yet including minor civil divisions [townships in states that have them]) updated with 2020 Census data, using the 
[[User:DemocraticLuntz/CenPop|CenPop]] semi-automated script which I have developed off and on over the last 6-7 years.

As part of the 2020 Census update, I was hoping to automate to the maximum extent possible replacing the "as of the [[year]] census, the population was xxx" (and variants) with 2020 data for those many articles from places that rarely get updated. To avoid leaving up incorrect references (i.e. to previous decade populations), I had the script removing references subsequent to the "as of ..." sentence. 

I could ''probably'' add an exception to leave it alone if it already says as of [[2020]] (or whichever decade, 2030 will be on us soon enough lol). 

However, a safer and more comprehensive alternative would be to insert a reference of my own (linking back to the US Census API) after the script's newly inserted "as of [[most recent census]], [current population]." Would you be okay with this latter alternative or should I just try to do the exception above to not mess with references people have already put in for this decade? 

(For now, I've disabled the part of the script that does "as of [[year]] Census" replacements. Waiting on your reply). Thanks. 
 
 */
/*	for(rx_obj of CenPop.pop_mention_regexes) {
		console.log("rx_obj=",rx_obj)
		content=content.replace(rx_obj.regex,rx_obj.replacer);
	}*/
	return content;
};

/* Below for copying purposes */
CenPop.example_URL='https://api.census.gov/data/2016/pep/population?get=POP,GEONAME&for=county:*&in=state:01&key=5ccd0821c15d9f4520e2dcc0f8d92b2ec9336108';

/* Hopefully matches the conversion for Census Bureau itself */
CenPop.m2_to_sqmi = function(area_sq_meters)
{
	var conversion_factor=2589988.110336;
	return (area_sq_meters/conversion_factor).toFixed(3);
	
};

CenPop.API_PREFIX='https://api.census.gov/data/';
CenPop.POPEST_SUFFIX='/pep/population';
CenPop.DECENNIAL_SUFFIX='/dec/pl';
CenPop.USER_KEY='5ccd0821c15d9f4520e2dcc0f8d92b2ec9336108';


CenPop.POPEST_FIELD='POP';
CenPop.DECENNIAL_FIELD='P1_001N';

/* Get the query url depending on the type */
CenPop.api.get_api_url = function(year, state_fips, est_or_census, geo_type) {
	var GEONAME=year>=2019 ? "NAME" : "GEONAME";

	const api_suffix=est_or_census==='Estimate' ? CenPop.POPEST_SUFFIX : CenPop.DECENNIAL_SUFFIX;
	const query_field=est_or_census==='Estimate' ? CenPop.POPEST_FIELD : CenPop.DECENNIAL_FIELD;
	const url=CenPop.API_PREFIX+year+api_suffix+'?get='+query_field+','+GEONAME+'&for='+geo_type+':*&in=state:'+state_fips+'&key='+CenPop.USER_KEY;
	console.log("url=",url);
	CenPop.curr_api_url = url;
	return url;
};

/**
 * Get all the counties in a certain state
 *
 &
 * Array of arrays of 4 elements each. 1st line (response[0])
 * contains "POP","GEONAME" ("NAME" from 2019 onward),"state","county"
 * 
 * 
 * where POP is the population estimate for that year, GEONAME (NAME) is 
 * 	'[Name] [County | Parish], State'
 * 
 * "state" is the 2 number FIPS code of the state 
 * "county" is the 3 number FIPS code of the county (for the state)
 * 
 * est_or_census is "est" for mid-decade estimates, "census" for decennial census
 */
CenPop.api.get_counties = function(year, state_fips, est_or_census, callback)
{
	var GEONAME=year>=2019 ? "NAME" : "GEONAME";
	CenPop.debug("Getting counties","global");
		$.ajax({
		crossDomain: true,
		data: {},
		dataType: 'json',
		url: CenPop.api.get_api_url(year,state_fips,est_or_census,"county"),  
		//'https://api.census.gov/data/'+year+'/pep/population?get=POP,'+GEONAME+'&for=county:*&in=state:'+state_fips+'&key=5ccd0821c15d9f4520e2dcc0f8d92b2ec9336108',
		type: 'GET',
		success: function(response) {
			if (response.error) {
				alert('Parse call error: ' + response.error.info);
				CenPop.stop();
			} else {
				callback(response);
			}
		},
		error: function(xhr, error) {
			console.log('AJAX error: ' + JSON.stringify(xhr)+JSON.stringify(error));
			CenPop.stop();
			if (onerror) onerror();
		}
	}); 
};
/**
 * Get all the places in a certain state into a JSON object
 *
 * Array of arrays of 4 elements each. 1st line (response[0])
 * contains "POP","GEONAME" ("NAME" from 2019 onward),"state","place"
 * 
 * where POP is the population estimate for that year, 
 *
 * GEONAME ("NAME" from 2019 onward) is 
 * 		'[Name] [municipality], State'
 * 
 * where 'municipality' is in lower case and should be one of  
 *  city, town, village, borough if we are doing places. 
 * 
 * If we're allowing non-places (e.g. county subdivisions) then 
 * they could potentially be different, ignore for now?
 * 
 * "state" is the 2 number FIPS code of the state 
 * "place" is the 5 number FIPS code of the county
 *
 * 
 * TO DO subdivisions https://api.census.gov/data/2016/pep/population?get=POP,GEONAME&for=county+subdivision:*&in=state:09&in=county:*&key=5ccd0821c15d9f4520e2dcc0f8d92b2ec9336108
 */
CenPop.api.get_places = function(year, state_fips, est_or_census, callback) {
	var GEONAME=year>=2019 ? "NAME" : "GEONAME";
	var url=CenPop.api.get_api_url(year,state_fips,est_or_census,"place");
	console.log("pre_call");
	console.log(url);
		$.ajax({crossDomain: true,data: {},dataType: 'json',type: 'GET',
		url: url,   
		//'https://api.census.gov/data/'+year+'/pep/population?get=POP,'+GEONAME+'&for=place:*&in=state:'+state_fips+'&key=5ccd0821c15d9f4520e2dcc0f8d92b2ec9336108',
		success: function(response) {
			if (response.error) {
				alert('Parse call error: ' + response.error.info);
				CenPop.stop();
			} 
			else {
				callback(response);
			}
		},
		error: function(xhr, error) {
			console.log("xhr=",xhr);
			console.log("error=",error);
			alert('AJAX error: ',xhr,error,JSON.stringify(error));
			CenPop.stop();
			if (onerror) onerror();
		}
	}); 
};

/**
 * TO DO subdivisions https://api.census.gov/data/2016/pep/population?get=POP,GEONAME&for=county+subdivision:*&in=state:09&in=county:*&key=5ccd0821c15d9f4520e2dcc0f8d92b2ec9336108
 */
CenPop.api.get_county_subdivisions = function(year, state_fips, est_or_census, callback)
{
	var GEONAME=year>=2019 ? "NAME" : "GEONAME";
	var my_url= CenPop.api.get_api_url(year,state_fips,est_or_census,"county+subdivision")+'&DATE=1,';
//	my_url='https://api.census.gov/data/'+year+'/pep/population?get=POP,'+GEONAME+'&for=county+subdivision:*&in=state:'+state_fips+'&in=county:*'+'&key=5ccd0821c15d9f4520e2dcc0f8d92b2ec9336108&DATE=1,';
	my_url+=''+((year % 10)+3);
	console.log('url='+my_url);
		$.ajax({crossDomain:true,data: {},dataType: 'json',type: 'GET',
		url:  my_url,
		success: function(response) {
			if (response.error) {
				alert('Parse call error: ' + response.error.info);
				CenPop.stop();
			} else {
				//console.log('Response done');
				callback(response);
			}
		},
		error: function(xhr, error) {
			alert('AJAX error: ' + JSON.stringify(error));
			CenPop.stop();
			if (onerror) onerror();
		}
	}); 
};

/**
 * Load place data from the Census gazetteer files for the purpose of updating areas of places 
 * year is the year of the gazetteer files
 * state_fips is the fips code for the state to get place data from
 * callback is the callback to execute after GET is complete
 * 
 * for county subdivisions, county_fips is queried directly from UI
 */
CenPop.api.get_gazetteer = function(year, state_fips, geo_adding, callback)
{
	/* Ignore year since this should be most current */
	var query_begin='https://tigerweb.geo.census.gov/arcgis/rest/services/TIGERweb/Places_CouSub_ConCity_SubMCD/MapServer/';
	var query_where='/query?where=STATE=\''+state_fips+'\'';
	var query_outFields;
	var query_orderByFields;
	var query_otherFields='returnGeometry=false&returnTrueCurves=false&f=json';
	CenPop.debug('geo_adding='+geo_adding,'gazetteer');
	if(geo_adding === 'cousub') 
	{
		geo_number='1'; 
		county_fips=$('#county_fips').val();
		query_where=query_where+' AND COUNTY=\''+county_fips+'\'';
		query_outFields='outFields=NAME,STATE,COUNTY,COUSUB,AREALAND,AREAWATER,LSADC,CENTLAT,CENTLON';
		query_orderByFields='orderByFields=COUNTY,COUSUB';
	}
	else if(geo_adding === 'place'||geo_adding === 'incplace') {
		geo_number='4'; 
		query_outFields='outFields=NAME,STATE,PLACE,AREALAND,AREAWATER,LSADC,CENTLAT,CENTLON';
		query_orderByFields='orderByFields=PLACE';
	}
	else {
		CenPop.debug("Error, bad value for geo_adding in get_gazetteer","global");
		CenPop.stop();
	}
	var get_url=query_begin+geo_number+query_where+'&'+query_outFields+'&'+query_orderByFields+'&'+query_otherFields;
	CenPop.curr_gazetteer_url=get_url;
	CenPop.debug('get_url='+get_url,'gazetteer');
	$.ajax({crossDomain: true,dataType: 'text',url:  get_url,type: 'GET',
		success: function(response) {
			if (response.error) {
				CenPop.debug('Parse call error: ' + response.error.info,'global');
				CenPop.stop();
			} else {
				the_response = JSON.parse(response);
				CenPop.debug(`Got a response, geo_adding=${geo_adding}`,'global');
				if(geo_adding === 'place') setTimeout(function() { CenPop.api.get_CDP_gazetteer(year, state_fips, the_response.features, callback); },100);
				else callback(the_response.features);
			}
		},
		error: function(xhr, error) {
			CenPop.debug('AJAX error: xhr=' + JSON.stringify(xhr)+',\n error='+JSON.stringify(error),'global');
			CenPop.stop();
			if (onerror) onerror();
		}
	}); 
};

CenPop.api.get_CDP_gazetteer = function(year, state_fips, place_list, callback)
{
	/* Ignore year since this should be most current */
	var query_begin='https://tigerweb.geo.census.gov/arcgis/rest/services/TIGERweb/Places_CouSub_ConCity_SubMCD/MapServer/5/query?';
	var query_where='where=STATE=\''+state_fips+'\'';
	var query_outFields='outFields=NAME,STATE,PLACE,AREALAND,AREAWATER,LSADC,CENTLAT,CENTLON';
	var query_orderByFields='orderByFields=PLACE';
	var query_otherFields='returnGeometry=false&returnTrueCurves=false&f=json';
	var get_url=query_begin+query_where+'&'+query_outFields+'&'+query_orderByFields+'&'+query_otherFields;
	CenPop.curr_gazetteer_url=get_url;
	CenPop.debug('get_url='+get_url,'gazetteer');
	$.ajax({
//		crossDomain: true,
		dataType: 'text',
		url:  get_url,	
		type: 'GET',
		success: function(response) {
			if (response.error) {
				CenPop.debug('Parse call error: ' + response.error.info,'global');
				CenPop.stop();
			} else {
				the_response=JSON.parse(response);
				callback(place_list.concat(the_response.features));
			}
		},
		error: function(xhr, error) {
			CenPop.debug('AJAX error: xhr=' + JSON.stringify(xhr)+',\n error='+JSON.stringify(error),'global');
			CenPop.stop();
			if (onerror) onerror();
		}
	}); 
};


/** 
 * Example query to get the places in each county for 2016, specifically giving back 
 *  "POP" (the population estimate for 2016)
 * "GEONAME" ("NAME" from 2019 onward) (the place, the county, the state, with (pt.) at the end if it's split between counties) 
 *            (probably leave the split places blank)
 * "state" the two digit FIPS code for the state
 * "county" the three digit FIPS code for the county (within the state)
 * "place" the five digit FIPS code for the place (within the state)
 * 
 * https://api.census.gov/data/2016/pep/population?get=POP,GEONAME&for=place:*&in=state:01+county:055&key=5ccd0821c15d9f4520e2dcc0f8d92b2ec9336108
 * 
 * 1. Query for every county to get an association between FIPS code and county names
 * 
 * 2. Query for every place in the state
 * 
 * 3. For each county in the state:
 * 	  a) Query for all the places in the county 
 * 	  [maybe to avoid overdoing Census queries, do each Wiki page update in county first
 * 
 *     or that might be more annoying, so maybe sleep some between queries]
 * 	  b) If place is listed without (pt.), assign it to be in that county
 */ 
 
 /**
  * Load the population data from US Census Bureau website for est_year 
  * in curr_state and geo_adding
  */
 CenPop.api.loadPopExternal = function(est_year,curr_state, est_or_census, geo_adding, callback) {
	CenPop.pageCount();
	console.log('Beginning loadPopExternal');
	CenPop.status('load-page');
	/* Call depending on whether we are adding counties or places */
	if(geo_adding === 'county')
	{
		CenPop.api.get_counties(est_year,curr_state, est_or_census, function(response)
		{
				CenPop.pop_page=response;
				CenPop.pop_page.list=response;
			//	alert("got counties: CenPop.pop_page.list="+CenPop.pop_page.list);
				CenPop.pop_page.curr_pos=0;
				callback(); /* Update buttons and stuff */
		});
	}
	else if(geo_adding==='place'||geo_adding==='incplace')
	{
		CenPop.api.get_places(est_year,curr_state, est_or_census, function(response)
		{

				CenPop.pop_page={};//response;
				if(response.length>1) {
					console.log("Sorting list");
					to_sort=response.slice(1);
					to_sort.sort(function(a,b) { return a[3]-b[3]; });
				
					CenPop.pop_page.list=[response[0]].concat(to_sort);
				}
				else CenPop.pop_page.list=response;
				
				console.log("* got places: CenPop.pop_page.list="+JSON.stringify(CenPop.pop_page.list));
				CenPop.pop_page.curr_pos=0;
				callback(); /* Update buttons and stuff */
		});
	}
	else if(geo_adding==='cousub') {
		/* get minor civil division population */
		CenPop.api.get_county_subdivisions(est_year,curr_state, est_or_census,function(response) {
				CenPop.pop_page={list:[],curr_pos:0};//response;
				/* Combine the DATE=1 line and the DATE=est_year+3 line, 
				starts at 2 because first line is header */
				for(i=2; i<response.length; i+=2) {
					/* [i]0 is POP for est_year+3 -> 0, [i]1 is GEONAME ("NAME" 2019 onward) -> 1, [i]3 is STATE -> 2, [i]4 is COUNTY -> 3, 5 is COUSUB-> 4, and the [i-1][0] is pop for Census -> 5 */
					CenPop.pop_page.list.push([response[i][0],response[i][1],response[i][3],response[i][4],response[i][5],response[i-1][0]]);
				}
				callback(); /* Update buttons and stuff */
		});
	}
	else console.log("ERROR: geo_adding="+geo_adding);
}; 

CenPop.setupGazetteerPage = function(place_list, geo_adding) {
	CenPop.gazetteer_page={};
	var temp_fips='';
	var attr;
	var convert_map={'NAME': 'NAME', 'STATE': 'STATE', 'COUNTY': 'COUNTY', 'COUSUB': 'COUSUB', 'PLACE': 'PLACE', 
	'AREALAND':'ALAND','AREAWATER':'AWATER','LSADC': 'LSAD','CENTLAT':'CENTLAT','CENTLON':'CENTLON'};
	for(var pos=0; pos < place_list.length; pos++) {
		attr=place_list[pos].attributes;
		if(geo_adding==='place'||geo_adding==='incplace') temp_fips=attr['STATE']+'-'+attr['PLACE'];
		else temp_fips=attr['STATE']+'-'+attr['COUNTY']+'-'+attr['COUSUB'];
		CenPop.gazetteer_page[temp_fips]={};		
		for(field in attr) CenPop.gazetteer_page[temp_fips][convert_map[field]]=attr[field];
		CenPop.debug(JSON.stringify(CenPop.gazetteer_page[temp_fips]),'gazetteer');
		CenPop.gazetteer_page[temp_fips]['ALAND_SQMI']=CenPop.m2_to_sqmi(attr['AREALAND']);
		CenPop.gazetteer_page[temp_fips]['AWATER_SQMI']=CenPop.m2_to_sqmi(attr['AREAWATER']);
	}
};


 /**
  * Load the population data from internal page  for est_year 
  * in curr_state and geo_adding 
  */
 CenPop.api.loadGazetteer = function(est_year,curr_state, geo_adding,  callback) {
	var temp_list, header_list, temp_fips, temp_splitline, temp_content, temp_page;
	var i,j, pagename;
	CenPop.debug('Beginning loadGazetteer','gazetteer');
	CenPop.status('load-page');
	/* County lines rarely change, so leave blank for now */
	if(/place|cousub/.test(geo_adding))
	{
		/* Query it */
		CenPop.api.get_gazetteer(est_year,curr_state, geo_adding,
		function(place_list)
		{
			CenPop.setupGazetteerPage(place_list, geo_adding);
			callback();
		});
	}
	else if(geo_adding === 'county')
	{
		CenPop.debug("Getting county gazetteer, nullop for now","gazetteer");
		callback();
	}
	else if(geo_adding === 'BOOMBOOMNONSENSE')
	{
		/* Can just use single file, it'll detect when it doesn't match current page */
		pagename='User:'+CenPop.username+'/Gazetteer';//+curr_state.toString()+'-'+est_year.toString();
		CenPop.debug('pagename='+pagename,'global');
		var data = {
			'action': 'query',
			'prop': 'info|revisions',
			'titles': pagename,
			'rvprop': 'content|timestamp|ids',
			'rvlimit': '1',
			'indexpageids': true,
			'meta': 'userinfo',
			'uiprop': 'hasmsg'
		};
		data.redirects=true;
	
		CenPop.status('load-page');
		
		/* Make the API call to get the data */

	
		CenPop.api.call(data, function(response) {
		//	CenPop.debug('response='+JSON.stringify(response),'gazetteer');
			/* Initialize the gazetteer page */
			CenPop.gazetteer_page={};
			temp_page=response.query.pages[response.query.pageids[0]];
			temp_content=temp_page.revisions ? temp_page.revisions[0]['*'] : '';
			temp_list=temp_content.split('\n');
			if(temp_list.length===0)
			{
				CenPop.debug('Error with response, correct gazetteer page may not exist','global');
				CenPop.stop();
				return;
			}
			header_list=temp_list[0].split('\t'); /* Get name of each column if we want to make it more robust in the future? */
			for(i=1; i < temp_list.length; i++)
			{
				temp_splitline=temp_list[i].split(/\t/);
				var k=0,l=0, temp_splicer;
				/* Splice to deal with bad space tab stuff in files */
				while(k < temp_splitline.length)
				{
					temp_splitline[k]=temp_splitline[k].toString().trim();
					if(temp_splitline[k].charAt(0).search(/[0123456789\.\-]/)!==-1)
					{
						temp_splicer=temp_splitline[k].split(/[^0123456789\.\-]/);
						if(temp_splicer.length>1)
							CenPop.debug('temp_splicer='+temp_splicer,'gazetteer');
						temp_splitline=temp_splitline.slice(0,k).concat(temp_splicer).concat(temp_splitline.slice(k+1));
						k+=temp_splicer.length;
					}
					else k++;
				}
				if(geo_adding === 'place'||geo_adding==='incplace')
					temp_fips=curr_state.toString()+'-'+temp_splitline[1].toString().substring(2);
				else if(geo_adding === 'cousub')
					temp_fips=curr_state.toString()+'-'+temp_splitline[1].toString().slice(2,5)+'-'+temp_splitline[1].toString().substring(5);
				CenPop.gazetteer_page[temp_fips]={};
				for(j=0; j < header_list.length; j++)
				{
					if(j < temp_splitline.length)
					{
						/* Add each field to object under header name */
						CenPop.gazetteer_page[temp_fips][header_list[j]]=temp_splitline[j].trim();
					}
					else CenPop.debug('Line too long,'+JSON.stringify(temp_splitline),'gazetteer');
				}
				CenPop.debug('CenPop.gazetteer_page['+temp_fips+']='+JSON.stringify(CenPop.gazetteer_page[temp_fips]),'gazetteer');
				/* Create object stuff for every gazetteer place */

			}
			callback(); /* Update buttons and stuff */
		});
	}
	
}; 

CenPop.api.loadPop = function(pagename,hasHeader,est_year,callback) {
	CenPop.pageCount();
	if (pagename === '#PRE-PARSE-STOP') {
		var curval = $('#articleList').val();
		$('#articleList').val(curval.substr(curval.indexOf('\n') + 1));
		$('#preparse').prop('checked', false);
		CenPop.stop();
		callback();
		return;
	}
	/* If we're adding counties, query for counties, if places, query for places */
	var data = {'action': 'query','prop': 'info|revisions','inprop': 'watched','intoken': 'edit|delete|protect|move|watch',
	'titles': pagename,'rvprop': 'content|timestamp|ids','rvlimit': '1','indexpageids': true,'meta': 'userinfo',
		'uiprop': 'hasmsg',redirects:true};
	CenPop.status('load-page');
	console.log("pre-call,data="+JSON.stringify(data));
	/* Make the API call to get the data */
	CenPop.api.call(data, function(response) {
		console.log("In callback of call in loadPop");
		if (response.query.userinfo.hasOwnProperty('messages')) {
			var view = mw.config.get('wgScriptPath') + '?title=Special:MyTalk';
			var viewNew = view + '&diff=cur';
			CenPop.status(
				'<span style="color:red;font-weight:bold;">'+
					CenPop.msg('status-newmsg', 
						'<a href="'+view+'" target="_blank">'+CenPop.msg('status-talklink')+'</a>',
						'<a href="'+viewNew+'" target="_blank">'+CenPop.msg('status-difflink')+'</a>')+
				'</span>', true);
			alert(CenPop.msg('new-message'));
			CenPop.stop();
			callback();
			return;
		}
		var varOffset = CenPop.list[0].indexOf('|') !== -1 ? CenPop.list[0].indexOf('|') + 1 : 0;
		CenPop.pop_page = response.query.pages[response.query.pageids[0]];
		console.log("content="+CenPop.pop_page.content+"type="+(typeof CenPop.pop_page.content)+"\nhasHeader="+hasHeader);
		console.log("list="+CenPop.pop_page.list);
		Object.assign(CenPop.pop_page,{curr_pos:0,name:pagename,pagevar:CenPop.list[0].substr(varOffset),
			content:CenPop.pop_page.revisions ? CenPop.pop_page.revisions[0]['*'] : ''});
		Object.assign(CenPop.pop_page,{list:CenPop.pop_page.content.split(/\n/),
			hasHeader:hasHeader,headerList:hasHeader?(CenPop.pop_page.list.shift()).split(/,/):"",
			exists:!response.query.pages["-1"],deletedrevs:response.query.deletedrevs,
			watched:CenPop.pop_page.hasOwnProperty('watched')});
		callback();
		return;
	}); 
}; 
/* Get the name of the query we're using */
CenPop.api.getQueryName = function(fips_code, geoname, query_attempt) {
	var	str_array_end=geoname.toString().split(','); /* Split off the state name */
	var str_array_begin=str_array_end[0].split(' '); /* Split so we can remove lower case */
	var pagename='';
	if($('#geoAdding').val()==='cousub')
	{
		var temp_pagename;
		if(query_attempt===0)
		{
			/* Form: [Name] ["T"ypeof], [County], [State] */

			temp_pagename=geoname.toString().replace(/ [a-z]/, function(match) {
				return match.toUpperCase();
			});
			pagename=temp_pagename;
		}
		else if(query_attempt===1)
		{
			/* Form: [Name] ([typeof]), [County], [State]) */
			temp_pagename=geoname.toString();
			pagename=''
			str_array_end=temp_pagename.toString().split(','); /* Split off the state name */
			str_array_begin=str_array_end[0].split(' '); /* Split so we can remove lower case */
			for(i=0; i < str_array_begin.length-1; i++)
			{
				if(i>0) pagename=pagename+' ';
				pagename = pagename + str_array_begin[i];
			}
			pagename = pagename + ' ('+ str_array_begin[i][0].toLowerCase()+str_array_begin[i].substr(1)+')';
			pagename=pagename+','+str_array_end[1];
			pagename=pagename+','+str_array_end[2];
		}
		else 
		{
			/* Form: [Name], [State] */
			temp_pagename=geoname.toString().replace(/ [a-z]/, function(match) {
				return match.toUpperCase();
			});
			pagename=''
			str_array_end=temp_pagename.toString().split(','); /* Split off the state name */
			//console.log('str_array_end='+str_array_end);
			str_array_begin=str_array_end[0].split(' '); /* Split so we can remove lower case */
			for(i=0; i < str_array_begin.length-1; i++)
			{
				if(i>0) pagename=pagename+' ';
				pagename = pagename + str_array_begin[i];
			}
			pagename=pagename+','+str_array_end[2];
		}
	}
	else
	{
		if(query_attempt < 2) {
			/* Remove the trailing lowercase terms before the comma if any exist */
			var j=str_array_begin.length-1;
			while(str_array_begin[j][0] !== str_array_begin[j][0].toUpperCase()) { j--; }
			for(i=0; i <= j; i++) {
				pagename = pagename + (i>0?' ':'')+ str_array_begin[i];
			}
			pagename=pagename+','+str_array_end[1];
			pagename=pagename.replace(/ CDP,/," (CDP),");
		}
		else
		{
			/* Remove the trailing lowercase terms before the comma if any exist, as well as any 
				words contained in parentheses
			*/
			var j=str_array_begin.length-1;
			while(str_array_begin[j][0] !== str_array_begin[j][0].toUpperCase()) { j--; }
			for(i=0; i <= j; i++)
			{
				if(!(str_array_begin[i][0]=='(' && str_array_begin[i][str_array_begin[i].length-1]==')'))
				{
					if(i>0) pagename=pagename+' ';
					pagename = pagename + str_array_begin[i];
				}
			}
			
			
			
			pagename=pagename+','+str_array_end[1];
			
			/* remove CDP */
			pagename = pagename.replace(/ CDP,/,",");
		}
	}
	return pagename.replace(new RegExp('/','g'),' ');
};

/** Retrieve page contents/info DIRECTLY from Census Bureau, process them, and update population data.
 * 
 * Then we want to process the data.
 * Specifically, we want to 
 * 1) Check to see if the page already contains either of the two templates used for historical population data
 *   If so, we need to potentially update the template with the given data.
 * 
 * 
 * 2) If not:
 *     a) If we find the ==Demographics== or == Demographics == section tags
 * 	        i) Replace in page content 
 * 			ii) Submit update
 * 	   b) Add to manual list of pages 
 *
 * @param fips_code the FIPS (Federal Information Processing Service) code for place
 * @param geoname the geographic name for the place as specified above
 * @param query_attempt the current number query being attempted
 * @param name_only Get the current pagename to the left of the first comma only
 */
CenPop.api.getExternal = function(fips_code, geoname, query_attempt, name_only, dfd = null, estorcensus) {
	if(dfd === null) {
		dfd = jQuery.Deferred(); }
	CenPop.debug('query_attempt='+query_attempt+",fips_code="+fips_code+"geoname="+geoname,'global');
	CenPop.pageCount();
	CenPop.converted_geobox=false;
	CenPop.needs_fips=false; /* Initially assume FIPS is there already */
	if (CenPop.isStopped && !name_only) {
		CenPop.stop();
		dfd.reject("Stopped");
		return dfd.promise();
	}
	var has_geobox=false;
	var	str_array_end=geoname.toString().split(','); /* Split off the state name */
	var str_array_begin=str_array_end[0].split(' '); /* Split so we can remove lower case */
	var data,alt_fips_code=fips_code.replace('-','');
	/* Get the page title to query based on flag */
	pagename = CenPop.api.getQueryName(fips_code, geoname, query_attempt);
	place_name=str_array_begin[0];
	var gsrsearch_str='("Code'+fips_code+'GNIS" OR "FIPS Code '+fips_code+'")';//+ ' OR "'+'INCITS place code '+alt_fips_code+'"';
	if(query_attempt===0 && ($('#geoAdding').val()==='place'||$('#geoAdding').val()==='incplace')) 
	{
		CenPop.debug("Using FIPS, gsrsearch_str="+gsrsearch_str,'global');
		data = {'action': 'query','generator': 'search', 'gsrsearch':  gsrsearch_str, 'gsrnamespace': '0', 'gsrlimit': '1',
			'prop': 'info|revisions|templates',	'intoken': 'edit|protect|move',
			'tltemplates': 'Template:US Census population|Template:Historical populations|Template:Disambiguation|'+
			'Template:Geodis|Template:Geobox|Template:Disambiguation page short description|Template:Dmbox',
			'rvprop': 'content|timestamp|ids','rvlimit': '1',
			'indexpageids': true, 'meta': 'userinfo', 'uiprop': 'hasmsg'
		};
	}
	else {
		/* Use title and pagename */
		console.log('geoname='+geoname+', using pagename="'+pagename+'"');
		data = {
			'action': 'query', 'prop': 'info|revisions|templates','intoken': 'edit|protect|move',
			'tltemplates': 'Template:US Census population|Template:Historical populations|Template:Disambiguation|'+
			'Template:Geodis|Template:Geobox|Template:Disambiguation page short description|Template:Dmbox',
			'titles': pagename,	'rvprop': 'content|timestamp|ids', 'rvlimit': '1',
			'indexpageids': true, 'meta': 'userinfo', 'uiprop': 'hasmsg'
		};
//		console.log('after data in geoname');
	}
	data.redirects = true;
	if(!name_only)
		CenPop.status('load-page');
//	console.log("precall, data="+JSON.stringify(data));
	CenPop.api.call(data, function(response) {
		//console.log("Response="+JSON.stringify(response));
		var has_uscensuspop=false;
		console.log('preusing response');
		if (response.query.userinfo.hasOwnProperty('messages')) {
			/* STOP if we got a message */
			var view = mw.config.get('wgScriptPath') + '?title=Special:MyTalk';
			var viewNew = view + '&diff=cur';
			CenPop.status('<span style="color:red;font-weight:bold;">'+
					CenPop.msg('status-newmsg', 
						'<a href="'+view+'" target="_blank">'+CenPop.msg('status-talklink')+'</a>',
						'<a href="'+viewNew+'" target="_blank">'+CenPop.msg('status-difflink')+'</a>')+
				'</span>', true);
			alert(CenPop.msg('new-message'));
			CenPop.stop();
			dfd.reject("Message!");
			return;
		}
		/* Added to get the page's name since we're searching using FIPS codes */
		
		pagename='';
		var text_page="";
		if(response.query && response.query.pages) {
			text_page=response.query.pages[response.query.pageids[0]].revisions ? response.query.pages[response.query.pageids[0]].revisions[0]['*'] : '';
		}
		if(!response.query.pages || response.query.pageids[0]==='-1')
		{
			if(query_attempt===0)
			{ 
				/* Check if we're doing fips only, should change at some point since NY screws up without it */
				if(!($('#tryfipsonly').prop('checked')))
				{
					if($('#geoAdding').val()==='cousub')					CenPop.debug("No page found with full name, Making new non-full call",'global');
					else CenPop.debug("No page found with FIPS, Making new non-FIPS call",'global');
					setTimeout(function() { CenPop.api.getExternal(fips_code,geoname,query_attempt+1, name_only, dfd, estorcensus); }, 200);
				}
				else
				{
					console.log("No page found with FIPS, moving to next");
					CenPop.api.failed_to_get(fips_code,geoname,name_only,dfd);

				}
				return;
			}
			else if(query_attempt === 1)
			{
				CenPop.debug("Can't find a page here either. Trying last time",'global');
				console.log('dfd='+JSON.stringify(dfd));
				setTimeout(function() { CenPop.api.getExternal(fips_code,geoname,query_attempt+1, name_only, dfd, estorcensus); }, 200);
				return;
			}
			else
			{
				console.log("\tNo page found, Can't find with FIPS or geoname or anything else");
				CenPop.api.failed_to_get(fips_code,geoname, name_only, dfd);
				return;
			}
		}
		else if(query_attempt===0 && response.query.pages[response.query.pageids[0]].title.search(place_name) === -1)
		{
			/* Clearly a bad title */
			console.log("Badly titled page found, Making new non-FIPS call");
			setTimeout(function() { CenPop.api.getExternal(fips_code,geoname,query_attempt+1, name_only, dfd, estorcensus); }, 200);
			return;
		}
		else if(query_attempt>=2 && / CDP,/.test(geoname) && !CenPop.api.is_CDP(geoname, text_page, fips_code)) {
			console.warn(`${geoname} is a CDP and the page retrieved by ${response.query} does not appear to be a CDP, skipping`);
			CenPop.api.failed_to_get(fips_code,geoname, name_only, dfd);
				return;
		}
		else
		{
			/* This is a good page, set things up */
			console.warn("Good page, response=",response,", calling CenPop.create_page");
			CenPop.create_page(response.query,fips_code,estorcensus); /* Create details for the page */
			pagename=response.query.pages[response.query.pageids[0]].title;
			CenPop.page.name=pagename; /* Hope this works */
			if (response.query.redirects) CenPop.page.name = pagename = response.query.redirects[0].to;
		}
		dfd.resolve("Found page");
		/* Now just process the templates in a new function */
		if(!name_only) CenPop.api.process_templates(fips_code, geoname, query_attempt, estorcensus);
		else CenPop.debug("Found it, returning!",'global');
		return;
	});
	return dfd.promise();
};

CenPop.api.get_dist_meters = function(lat1,lon1,lat2,lon2) {
	// https://www.movable-type.co.uk/scripts/latlong.html
		const R = 6371e3; // metres
	const φ1 = lat1 * Math.PI/180; // φ, λ in radians
	const φ2 = lat2 * Math.PI/180;
	const Δφ = (lat2-lat1) * Math.PI/180;
	const Δλ = (lon2-lon1) * Math.PI/180;
	
	const a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
	          Math.cos(φ1) * Math.cos(φ2) *
	          Math.sin(Δλ/2) * Math.sin(Δλ/2);
	const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
	
	const d = R * c; // in metres
	return d;
};

/* Check by closeness to gazetteer coordinates and tell-tale signs like Census-designated place for whether it's a CDP */
CenPop.api.is_CDP = function(geoname, text_page, fips_code) {
	if(/\|\s*settlement\_type\s*\=\s*\[?\[?([A-Za-z\s\-]*\|\s*)?\s*Census-designated place\s*[\|\]]?/i.test(text_page)) {
			return true;
		}
		
	var settle_match=text_page.match(/\|\s*settlement\_type\s*\=\s*\[?\[?([A-Za-z\s\-#]*\|\s*)?\s*unincorporated/i);
	if(!settle_match) return false;
	var current_gazetteer=CenPop.gazetteer_page[fips_code];
	console.log("current_gazetteer=",current_gazetteer);
	var coord_re=/\|coordinates\s*\=\s*\{\{coord\|(\d+)\|(\d+)\|(\d+)\|([A-Z])\|(\d+)\|(\d+)\|(\d+)\|([A-Z])/;
	var coord_match=text_page.match(coord_re);
	CenPop.debug("CenPop.api.is_CDP, coord_match="+coord_match,"global");
	var coord_lat=0.0,coord_lon=0.0;
	if(!coord_match) {
		return false;
	}
	coord_lat=parseFloat(coord_match[1])+parseFloat(coord_match[2])/60.+parseFloat(coord_match[3])/3600.;
	if(coord_match[4]=='S') coord_lat*=-1;
	coord_lon=parseFloat(coord_match[5])+parseFloat(coord_match[6])/60.+parseFloat(coord_match[7])/3600.;
	if(coord_match[8]=='W') coord_lon*=-1;
	console.log(`coord_lat=${coord_lat}, coord_lon=${coord_lon}`);
	var gaz_lat=parseFloat(current_gazetteer['CENTLAT']), gaz_lon=parseFloat(current_gazetteer['CENTLON']);

	dist_meters=CenPop.api.get_dist_meters(coord_lat, coord_lon, gaz_lat, gaz_lon);
	console.log(`coord_lat=${coord_lat}, coord_lon=${coord_lon}, gaz_lat=${gaz_lat}, gaz_lon=${gaz_lon}, dist_meters=${dist_meters}`);
	if(dist_meters <= 5000) {
		return true;
	}
	return false;
};
CenPop.api.process_templates = function(fips_code, geoname, query_attempt, estorcensus)
{
	console.log("*** est_or_census="+estorcensus)
	//CenPop.debug("CenPop.api.process_templates, CenPop.page="+JSON.stringify(CenPop.page),"global");
	var has_uscensuspop=false;
	
	var pagename = CenPop.api.getQueryName(fips_code, geoname, query_attempt);
	var split_pgname = pagename.split(/,|\(/);
	var begin_pagename=split_pgname.length>0 ? split_pgname[0] : pagename;
	var gsrsearch_str='"'+fips_code+'" AND '+begin_pagename;//+ ' OR "'+'INCITS place code '+alt_fips_code+'"';
	//CenPop.debug('image gsrsearch_str='+gsrsearch_str,'global');
	var temp_ret='', newContent='';
	if(CenPop.page.templates)
	{
		for(var i=0;i<CenPop.page.templates.length; i++)
		{
			var curr_title=CenPop.page.templates[i].title;
			console.log("curr_title="+curr_title);
			if(curr_title === 'Template:US Census population' && !has_uscensuspop)
			{	
				console.log("Found us_censuspop");
				has_uscensuspop=true; 
				CenPop.page.has_template=true;
			}
			else if(curr_title === 'Template:Historical populations') { CenPop.page.has_template=true; }
			else if(curr_title === 'Template:Disambiguation' || curr_title === 'Template:Geodis' 
			||/Template:Dmbox/.test(curr_title)) {
				/* TODO: In this case we ought to search the disambiguation page for the 
					correct place name */
					console.log("CenPop.page.disambig");
				CenPop.page.disambig=true;	
			}
			if(curr_title === 'Template:Geobox')
			{
				console.log("received with Template:Geobox");
				CenPop.page.has_geobox=true;
			}
		}
	}
	else
	{
		console.log("No templates assigned ...");
		//CenPop.api.failed_to_get(fips_code,geoname,name_only);
		//return;
	}
	if(CenPop.page.disambig) {
		/* If it's a county or we already tried enough times, give up */
		if(query_attempt>=2 ||  $('#geoAdding').val() === 'county') {
			CenPop.in_get=false;
			console.log("Failed, hit disambig page");
			CenPop.api.failed_to_get(fips_code,geoname,false,null);
			/* prevent infinite loops */
			return;
		}
		/* This is a disambiguation page. Try once more with the in_get flag set */
		CenPop.in_get = true;
		console.log("Failed, hit disambig page");
		CenPop.api.failed_to_get(fips_code,geoname,false,null);
		return;
	}


	CenPop.page.newContent="";

	if(!CenPop.page.has_template)
	{
		/* Add a new population section, get new page */
		newContent = CenPop.add_pop(CenPop.page.content, estorcensus);
	//	console.log("new template content="+newContent);
		CenPop.page.newContent=newContent;
		CenPop.added_pop=newContent !== '';
		if(newContent==='') CenPop.page.newContent=CenPop.page.content;
		if(CenPop.added_pop) CenPop.updateEditBox(); 
		else console.log("Failure at adding new historical census box");
	}
	else {
		if(has_uscensuspop) temp_ret=CenPop.add_to_template(CenPop.page.content, estorcensus);
		else temp_ret=CenPop.add_to_histpop_template(CenPop.page.content, estorcensus);
		if(temp_ret!=='') {
			CenPop.debug("temp_ret is not blank","global");
			CenPop.check_modified_pop(temp_ret);
			CenPop.added_popest_ref=has_uscensuspop; /* It should have successfully added the population reference */
		}
		else
		{
			var extra_str=has_uscensuspop ? "USCensusPop" : "histpoptemplate";
			console.log("Failure at adding to "+extra_str);
		}
	}
	if(estorcensus==="Decennial") {
			CenPop.debug("Attempting to replace decennial census reference ");
			if((CenPop.page.newContent=CenPop.api.replaceDecennialReferences(CenPop.page.newContent))) CenPop.updateEditBox();
		}
	if(CenPop.page.has_geobox) {
		CenPop.converted_geobox=CenPop.api.geobox_to_infobox(CenPop.page.newContent, 
		function(gotMyContent) {
			if((CenPop.page.newContent=gotMyContent)) CenPop.updateEditBox();
		});
	}
		
	if($('#addimages').prop('checked')) {
		imagesrch_data={'action': 'query','generator': 'search','gsrnamespace': '6',
			'gsrsearch': gsrsearch_str,'gsrlimit': '5','prop': 'info|revisions',
			'rvprop': 'content','indexpageids': true};
		CenPop.api.call(imagesrch_data, function(response) {
			CenPop.debug('image response='+JSON.stringify(response),'global');
			img_stuff={};
			var img_title='',img_text_match;
			if(response.query && response.query.pages) {
				var	curr_page_id=response.query.pageids[0];
				var curr_img_page=response.query.pages[curr_page_id];
				img_stuff['image_map']=curr_img_page.title;
				img_text_match=curr_img_page.revisions[0]['*'].match(/(Location of.*\.)\n\nFIPS/);
				if(img_text_match && img_text_match.length>1 && 
				img_text_match[1]) img_stuff['map_caption']=img_text_match[1];
				console.log('img_stuff='+JSON.stringify(img_stuff));
			}
			else console.log('ERROR: found no response');
			/* Call infobox */
			CenPop.api.doInfobox(CenPop.page.newContent, fips_code, query_attempt, img_stuff, 
			function(gotMyContent) {
				CenPop.gotNewestContent=gotMyContent;
				if(gotMyContent) CenPop.modified_info=true;
				if ($('#autosave').prop('checked')) {
					//timeout will take #throttle's value * 1000, if it's a number above 0. Currently defaults to 0.
					setTimeout(CenPop.api.submit, Math.max(+$('#throttle').val() || 0, 0) * 1000);
				}
				CenPop.added_popest_ref=false;
			}, estorcensus);
		});
	}
	else
	{

		CenPop.debug("Going directly to infobox","global");
		/* Go directly to infobox */
		CenPop.api.doInfobox(CenPop.page.newContent, fips_code, query_attempt, {}, function(gotMyContent) 
		{
			CenPop.gotNewestContent=gotMyContent;
			if(gotMyContent)
			{
				CenPop.modified_info=true;
			}
			if ($('#autosave').prop('checked')) {
				//timeout will take #throttle's value * 1000, if it's a number above 0. Currently defaults to 0.
				setTimeout(CenPop.api.submit, Math.max(+$('#throttle').val() || 0, 0) * 1000);
			}
			CenPop.added_popest_ref=false;
		}, estorcensus);
	}


};

/**
 * Moving out to separate function to move on to the next one on failure 
 */
CenPop.api.failed_to_get = function(fips_code,geoname, name_only, dfd) {
	if(!name_only) {
		if(dfd !== null) dfd.reject("Moving on");
		curr_art_val=$('#articleList').val();
		$('#articleList').val(curr_art_val+'\n'+geoname +', '+fips_code);
		CenPop.status('pausing');
		setTimeout(CenPop.next, Math.max($('#throttle').val() || 0, 3) * 1000);
	}
	else {
		dfd.reject("Failed name");
		/* We just wanted the name, set CenPop.page.name to '', return */
		CenPop.page.name='';
		return;
	}
};

CenPop.api.doInfobox = function(input, fips_code, query_attempt, img_stuff, callback, estorcensus) {
	console.log("Estorcensus=",estorcensus)
	var temp_regexp=/{{Infobox[ ]+settlement/i;
	var ref_regexp=/^<ref name="([^"]*)"\s*>/;
	var curr_estref=$('.estRefText').val().match(ref_regexp);
	var curr_state=$('#stateAdding').val(), curr_year=$('.estYearText').val();
	var estref_text='';
	var today=new Date();
	var tot_km2=0, tot_sqmi=0,curr_gaz_line;
	var date_options={year:'numeric',day:'numeric',month:'long'};
	var curr_date_str=today.toLocaleString('en-us',date_options);
	var area_footnotes='<ref name="TigerWebMapServer">{{cite web|title='+
    'ArcGIS REST Services Directory|'+
	'url='+CenPop.curr_gazetteer_url+
	'|publisher=United States Census Bureau|accessdate='+
	curr_date_str+'}}</ref>';
	// Check to see if we've added the full estRef 
	var loc_full_estref=input.search($('.estRefText').val());
	var fields_to_update={}, fields_no_overwrite=[];
	if(curr_estref != null && input.loc_full_estref != -1 && CenPop.added_popest_ref) {
		estref_text=curr_estref[0].slice(0,curr_estref[0].length-1)+'/>'; }
	else estref_text=$('.estRefText').val()
	if(CenPop.page.official_url&&CenPop.page.official_url.length>0) fields_to_update['website']="{{URL|"+CenPop.page.official_url+"}}";
	if(img_stuff.image_map) {
		Object.assign(fields_to_update,{'image_map':img_stuff.image_map,'map_caption':img_stuff.map_caption,
			'pushpin_map':' '});
		/* Add the image map and caption */
	}
	if(query_attempt>0) {
		fields_no_overwrite=['blank_name','blank_info'];
		fields_to_update['blank_name']='[[Federal Information Processing Standards|FIPS code]]';
		fields_to_update['blank_info']=fips_code;
	}
	fields_no_overwrite.push('website');
	if(CenPop.gazetteer_page!==undefined && CenPop.gazetteer_page[fips_code]!==undefined && 
	('LSAD' in CenPop.gazetteer_page[fips_code]) &&
		(estorcensus==='Decennial'||CenPop.gazetteer_page[fips_code]['LSAD']!='57'))
	{
		console.warn("In first part Census added")
		if(fips_code in CenPop.gazetteer_page|| CenPop.gazetteer_page[fips_code]!==undefined)
		{ 
					console.warn("In second part Census added")

			if(fips_code in CenPop.gazetteer_page || CenPop.gazetteer_page[fips_code]!==undefined) {
				curr_gaz_line=CenPop.gazetteer_page[fips_code];
				tot_km2=((parseFloat(curr_gaz_line['ALAND'])+parseFloat(curr_gaz_line['AWATER']))/1000000.);
				tot_sqmi=1.*parseFloat(curr_gaz_line['ALAND_SQMI'])+parseFloat(curr_gaz_line['AWATER_SQMI']);
				
			}
			else {
			}
			
			fields_to_update['pop_est_as_of']=estorcensus==='Estimate' ? $('.estYearText').val():" ";
			fields_to_update['pop_est_footnotes']= estorcensus==='Estimate' ? estref_text : " ";
			fields_to_update['population_est']=estorcensus==='Estimate' ? CenPop.pop_page.curr_place[CenPop.est_column] : " ";
			
			if(estorcensus==='Decennial') {
				fields_to_update['population_as_of']="[["+$('.estYearText').val()+" United States Census|"+$('.estYearText').val()+"]]";
				console.warn("Hit population_footnotes");
				fields_to_update['population_footnotes']=estref_text; 
				fields_to_update['population_total']=CenPop.pop_page.curr_place[CenPop.est_column];
			}
			if(fips_code in CenPop.gazetteer_page|| CenPop.gazetteer_page[fips_code]!==undefined) {
				fields_to_update['unit_pref']='Imperial';
				let pop=estorcensus==='Estimate' ? fields_to_update['population_est'] : fields_to_update['population_total'];
	
				fields_to_update['area_footnotes']=area_footnotes;
				fields_to_update['area_total_km2']=tot_km2.toFixed(2);
				fields_to_update['area_total_sq_mi']=parseFloat(tot_sqmi).toFixed(2);
				fields_to_update['area_land_km2']=(parseFloat(curr_gaz_line['ALAND'])/1000000.).toFixed(2);
				fields_to_update['area_water_km2']=(parseFloat(curr_gaz_line['AWATER'])/1000000.).toFixed(2);
				fields_to_update['area_land_sq_mi']=parseFloat(curr_gaz_line['ALAND_SQMI']).toFixed(2);
				fields_to_update['area_water_sq_mi']=parseFloat(curr_gaz_line['AWATER_SQMI']).toFixed(2);
				fields_to_update['population_density_sq_mi']= (pop/parseFloat(curr_gaz_line['ALAND_SQMI'])).toFixed(2);
				fields_to_update['population_density_km2']= (pop/(parseFloat(curr_gaz_line['ALAND'])/1000000.)).toFixed(2);
			}
			
		}
		else {
			console.warn("CenPop.gazetteer_page=",CenPop.gazetteer_page, "fips_code=",fips_code)
		}
		
		/* Add population_as_of fields if most_recent_census is not 0 */ 
		if(estorcensus==='Estimate' && CenPop.most_recent_census !== 0 && CenPop.most_recent_census % 10 === 0)
		{
			console.log("updated population as of");
			fields_to_update['population_as_of']='[['+CenPop.most_recent_census+' United States Census|'+CenPop.most_recent_census+']]';
			fields_to_update['population_total']=CenPop.most_recent_census_pop;
		}
/*		if($('#overwrite').prop('checked'))
		{
			fields_to_update['population_total']=' ';
		}*/
	}
	var fields_to_remove={};
	if(fields_to_update['population_total']!==undefined) fields_to_remove['population']=true;
	var old_infobox=CenPop.get_template(input,temp_regexp);
	console.log("pre old_infobox map");
	if(old_infobox!== null && old_infobox.length>0)
	{
		CenPop.page.newestContent=input.replace(old_infobox, function(match,p1,p2,p3)
		{
			var my_ret=CenPop.update_template(match,fields_to_update, fields_no_overwrite, fields_to_remove);
			CenPop.api.updateWebsite(my_ret['fields']);
			return my_ret['text'];
		});
		console.log("Calling fix_removed_refs");
		CenPop.page.newestContent=CenPop.fix_removed_refs(CenPop.page.newestContent); /* Fix the references we removed */
		$('#editBoxArea').val(CenPop.page.newestContent);
		$('#diffLen').html(CenPop.page.newestContent.length-CenPop.page.content.length);
		if($('#autosave').prop('checked') !== true)
			$('.editbutton').prop('disabled', false);
	//	console.log("MOO");
		/* TODO: add replacement function for prose geography, call the callback there */
		callback(true);
	}
	else callback(false);
};
/* Update the website count with populations */
CenPop.api.updateWebsite=function(fields)
{
	//console.log("fields="+JSON.stringify(fields));
	if(fields['population_total']!==undefined) {
		/* Add to the no website list */
		console.log("Adding no website"+CenPop.page.name);
		var curr_val = $('#noWebsiteList').val();
		var website=((fields['website']==undefined || fields['website'].trim().length<2)?'':fields['website']);
		website=website.replace(/\{\{url\|([^\}]*)\}\}/i,"$1").trim();
		var addition=CenPop.page.name+";"+fields['population_total']+';'+website;
		$('#noWebsiteList').val($('#noWebsiteList').val()+"\n"+addition.trim());
	}
};


/* Empty out removed_refs and replace */
CenPop.fix_removed_refs=function(to_replace)
{	
	var ref_regexp,ref_regexpstr,field_name;
	console.log("CenPop.removed_refs="+JSON.stringify(CenPop.removed_refs));
	for(field_name in CenPop.removed_refs)
	{
		ref_regexpstr='<ref\\s+name\\s*=\\s*"?'+field_name+'"?\\s*/>';
		ref_regexp=new RegExp(ref_regexpstr); // maybe needs to NOT be global, rest should stay the same
		console.log('ref_regexp='+ref_regexp);
		to_replace=to_replace.replace(ref_regexp,function(match,p1,p2,p3)
		{
			console.log('Replacing "'+match+'" with '+CenPop.removed_refs[field_name]);
			return CenPop.removed_refs[field_name];
		});
	}
	CenPop.removed_refs={};
	return to_replace;
};

/* Do replacing in geobox to infobox */
CenPop.api.replace_infobox=function(match,p1,p2,p3) {
	console.log("In replace");	
	var my_ret='{{Infobox settlement\n';
	var i, curr_field_now, equiv_geobox_field,good_map_flag=false,checked_for_item=false;
	var curr_state=$('#stateAdding option:selected').text();
	for(i=0; i<CenPop.infobox_fields.length; i++) {
		curr_field_now=CenPop.infobox_fields[i];
		my_ret+='| '+curr_field_now + ' = ';
		if(curr_field_now in CenPop.infobox_geobox_fields && 
			CenPop.found_field(CenPop.infobox_geobox_fields[curr_field_now],CenPop.ret_obj))
		{
			equiv_geobox_field=CenPop.found_field(CenPop.infobox_geobox_fields[curr_field_now],ret_obj);
			my_ret += CenPop.ret_obj[equiv_geobox_field]
			delete CenPop.ret_obj[equiv_geobox_field];
		}
		else if(curr_field_now in CenPop.infobox_defaults) my_ret += CenPop.infobox_defaults[curr_field_now];
		
		else if(curr_field_now in CenPop.infobox_optionals) my_ret += CenPop.infobox_optionals[curr_field_now];
		else if(curr_field_now === 'image_map' && (good_map_flag=true)) {
			my_ret += CenPop.ret_obj['map'];
			delete CenPop.ret_obj['map'];
		}
		else if(good_map_flag && curr_field_now in CenPop.infobox_geobox_good_maps) {
			equiv_geobox_field=CenPop.infobox_geobox_good_maps[curr_field_now];
			if(equiv_geobox_field in CenPop.ret_obj) {
				my_ret += CenPop.ret_obj[equiv_geobox_field]
				delete CenPop.ret_obj[equiv_geobox_field];
			}
		}
		else if(curr_field_now === 'image_map1' && !/^(Hawaii|Alaska)$/.test(curr_state)) {
			my_ret+=curr_state+' in United States (US48).svg';
		}
		else if(curr_field_now === 'map_caption1' && !/^(Hawaii|Alaska)$/.test(curr_state)) {
			my_ret+='Location of '+curr_state+' in the United States';
		}
		my_ret=my_ret+'\n';
	}
	CenPop.debug("Fields not added",'update');
	for(val in CenPop.ret_obj) {
		if(val.search(/round$/)===-1 && 
			CenPop.ret_obj[val].toString().trim().length > 0) CenPop.debug('CenPop.ret_obj['+val+']='+ret_obj[val]);
	}
	my_ret+='}}\n';
	return my_ret;
};

CenPop.api.geobox_to_infobox = function(input,callback) {
	var temp_regexp=/{{[gG]eobox\s*\|\s*[sS]ettlement/;
	var old_geobox=CenPop.get_template(input,temp_regexp); // Find the geobox
	var real_ret='';
	CenPop.ret_obj = CenPop.convert.parse_template(old_geobox);
	if(CenPop.ret_obj) {
		real_ret=input.replace(old_geobox,CenPop.api.replace_infobox);
		$('#editBoxArea').val(CenPop.page.newContent);
		$('#diffLen').html(CenPop.page.newContent.length-CenPop.page.content.length);
		if(!$('#autosave').prop('checked')) $('.editbutton').prop('disabled', false);
	}
	callback(real_ret)
	return real_ret.length>0;
};

/* Whether or not one of the possible lists of objects are there */
CenPop.found_field = function(obj_list,list_of_fields) {
	if(Array.isArray(obj_list)) {
		for(i=0; i < obj_list.length; i++) {
			if(obj_list[i] in list_of_fields && 
				list_of_fields[obj_list[i]].toString().trim().length>0) return obj_list[i];
		}
		return null;
	}
	else if(obj_list in list_of_fields) return obj_list;
	return null;
};

CenPop.replace_geography = function() {
	var my_str='';
	my_str+='According to the [[U.S. Census Bureau]], the (city|town|village|township|CDP) has a total area of ';
	my_str+='{{convert|33.8|mi2|km2}} of which {{convert|32.9|mi2|km2}}  is land and {{convert|0.9|mi2|km2}}';
	my_str+='(3.09%) is water.<ref name ="Gazetteer files">{{cite web|title=';
	my_str+='US Gazetteer files 2013|url=http://www.census.gov/geo/www/gazetteer/files/Gaz_places_national.txt';
	my_str+='|publisher=[[United States Census Bureau]]|accessdate=2014-02-05}}</ref>';	
};