From c36e80933718e6c2826ef6f7bd9efa59c0bee1e7 Mon Sep 17 00:00:00 2001
From: "Mirar (Pontus Hagland)" <pike@sort.mirar.org>
Date: Thu, 18 May 2000 10:27:50 +0200
Subject: [PATCH] first checkin; some geographical support

Rev: lib/modules/Geography.pmod/Countries.pmod:1.1
Rev: lib/modules/Geography.pmod/Position.pike:1.1
---
 lib/modules/Geography.pmod/Countries.pmod | 408 ++++++++++++++++++++++
 lib/modules/Geography.pmod/Position.pike  | 170 +++++++++
 2 files changed, 578 insertions(+)
 create mode 100644 lib/modules/Geography.pmod/Countries.pmod
 create mode 100644 lib/modules/Geography.pmod/Position.pike

diff --git a/lib/modules/Geography.pmod/Countries.pmod b/lib/modules/Geography.pmod/Countries.pmod
new file mode 100644
index 0000000000..950496f517
--- /dev/null
+++ b/lib/modules/Geography.pmod/Countries.pmod
@@ -0,0 +1,408 @@
+array(Country) countries=
+({
+   Country("AD","Andorra"),
+   Country("AE","United Arab Emirates"),
+   Country("AF","Afghanistan"),
+   Country("AG","Antigua and Barbuda"),
+   Country("AI","Anguilla"),
+   Country("AL","Albania"),
+   Country("AM","Armenia"),
+   Country("AN","Netherlands Antilles"),
+   Country("AO","Angola"),
+   Country("AQ","Antarctica"),
+   Country("AR","Argentina"),
+   Country("AS","American Samoa"),
+   Country("AT","Austria"),
+   Country("AU","Australia"),
+   Country("AW","Aruba"),
+   Country("AZ","Azerbaijan"),
+   Country("BA","Bosnia and Herzegovina"),
+   Country("BB","Barbados"),
+   Country("BD","Bangladesh"),
+   Country("BE","Belgium"),
+   Country("BF","Burkina Faso"),
+   Country("BG","Bulgaria"),
+   Country("BH","Bahrain"),
+   Country("BI","Burundi"),
+   Country("BJ","Benin"),
+   Country("BM","Bermuda"),
+   Country("BN","Brunei Darussalam"),
+   Country("BO","Bolivia"),
+   Country("BR","Brazil"),
+   Country("BS","Bahamas"),
+   Country("BT","Bhutan"),
+   Country("BV","Bouvet Island"),
+   Country("BW","Botswana"),
+   Country("BY","Belarus"),
+   Country("BZ","Belize"),
+   Country("CA","Canada"),
+   Country("CC","Cocos Islands",(["aka":({"Keeling Islands"})])),
+   Country("CF","Central African Republic"),
+   Country("CG","Congo"),
+   Country("CH","Switzerland"),
+   Country("CI","Cote D'Ivoire",(["aka":({"Ivory Coast"})])),
+   Country("CK","Cook Islands"),
+   Country("CL","Chile"),
+   Country("CM","Cameroon"),
+   Country("CN","China"),
+   Country("CO","Colombia"),
+   Country("CR","Costa Rica"),
+   Country("CS","Czechoslovakia",(["former":1])),
+   Country("CU","Cuba"),
+   Country("CV","Cape Verde"),
+   Country("CX","Christmas Island"),
+   Country("CY","Cyprus"),
+   Country("CZ","Czech Republic"),
+   Country("DE","Germany"),
+   Country("DJ","Djibouti"),
+   Country("DK","Denmark"),
+   Country("DM","Dominica"),
+   Country("DO","Dominican Republic"),
+   Country("DZ","Algeria"),
+   Country("EC","Ecuador"),
+   Country("EE","Estonia"),
+   Country("EG","Egypt"),
+   Country("EH","Western Sahara"),
+   Country("ER","Eritrea"),
+   Country("ES","Spain"),
+   Country("ET","Ethiopia"),
+   Country("FI","Finland"),
+   Country("FJ","Fiji"),
+   Country("FK","Falkland Islands",(["aka":({"Malvinas"})])),
+   Country("FM","Micronesia"),
+   Country("FO","Faroe Islands"),
+   Country("FR","France"),
+   Country("FX","France, Metropolitan"),
+   Country("GA","Gabon"),
+   Country("GB","United Kingdom",(["aka":({"Great Britain"})])),
+   Country("GD","Grenada"),
+   Country("GE","Georgia"),
+   Country("GF","French Guiana"),
+   Country("GH","Ghana"),
+   Country("GI","Gibraltar"),
+   Country("GL","Greenland"),
+   Country("GM","Gambia"),
+   Country("GN","Guinea"),
+   Country("GP","Guadeloupe"),
+   Country("GQ","Equatorial Guinea"),
+   Country("GR","Greece"),
+   Country("GS","S. Georgia and S. Sandwich Isls."),
+   Country("GT","Guatemala"),
+   Country("GU","Guam"),
+   Country("GW","Guinea-Bissau"),
+   Country("GY","Guyana"),
+   Country("HK","Hong Kong"),
+   Country("HM","Heard and McDonald Islands"),
+   Country("HN","Honduras"),
+   Country("HR","Croatia",(["aka":({"Hrvatska"})])),
+   Country("HT","Haiti"),
+   Country("HU","Hungary"),
+   Country("ID","Indonesia"),
+   Country("IE","Ireland"),
+   Country("IL","Israel"),
+   Country("IN","India"),
+   Country("IO","British Indian Ocean Territory"),
+   Country("IQ","Iraq"),
+   Country("IR","Iran"),
+   Country("IS","Iceland"),
+   Country("IT","Italy"),
+   Country("JM","Jamaica"),
+   Country("JO","Jordan"),
+   Country("JP","Japan"),
+   Country("KE","Kenya"),
+   Country("KG","Kyrgyzstan"),
+   Country("KH","Cambodia"),
+   Country("KI","Kiribati"),
+   Country("KM","Comoros"),
+   Country("KN","Saint Kitts and Nevis"),
+   Country("KP","North Korea"),
+   Country("KR","South Korea"),
+   Country("KW","Kuwait"),
+   Country("KY","Cayman Islands"),
+   Country("KZ","Kazakhstan"),
+   Country("LA","Laos"),
+   Country("LB","Lebanon"),
+   Country("LC","Saint Lucia"),
+   Country("LI","Liechtenstein"),
+   Country("LK","Sri Lanka"),
+   Country("LR","Liberia"),
+   Country("LS","Lesotho"),
+   Country("LT","Lithuania"),
+   Country("LU","Luxembourg"),
+   Country("LV","Latvia"),
+   Country("LY","Libya"),
+   Country("MA","Morocco"),
+   Country("MC","Monaco"),
+   Country("MD","Moldova"),
+   Country("MG","Madagascar"),
+   Country("MH","Marshall Islands"),
+   Country("MK","Macedonia"),
+   Country("ML","Mali"),
+   Country("MM","Myanmar"),
+   Country("MN","Mongolia"),
+   Country("MO","Macau"),
+   Country("MP","Northern Mariana Islands"),
+   Country("MQ","Martinique"),
+   Country("MR","Mauritania"),
+   Country("MS","Montserrat"),
+   Country("MT","Malta"),
+   Country("MU","Mauritius"),
+   Country("MV","Maldives"),
+   Country("MW","Malawi"),
+   Country("MX","Mexico"),
+   Country("MY","Malaysia"),
+   Country("MZ","Mozambique"),
+   Country("NA","Namibia"),
+   Country("NC","New Caledonia"),
+   Country("NE","Niger"),
+   Country("NF","Norfolk Island"),
+   Country("NG","Nigeria"),
+   Country("NI","Nicaragua"),
+   Country("NL","Netherlands"),
+   Country("NO","Norway"),
+   Country("NP","Nepal"),
+   Country("NR","Nauru"),
+   Country("NT","Neutral Zone"),
+   Country("NU","Niue"),
+   Country("NZ","New Zealand (Aotearoa)"),
+   Country("OM","Oman"),
+   Country("PA","Panama"),
+   Country("PE","Peru"),
+   Country("PF","French Polynesia"),
+   Country("PG","Papua New Guinea"),
+   Country("PH","Philippines"),
+   Country("PK","Pakistan"),
+   Country("PL","Poland"),
+   Country("PM","St. Pierre and Miquelon"),
+   Country("PN","Pitcairn"),
+   Country("PR","Puerto Rico"),
+   Country("PT","Portugal"),
+   Country("PW","Palau"),
+   Country("PY","Paraguay"),
+   Country("QA","Qatar"),
+   Country("RE","Reunion"),
+   Country("RO","Romania"),
+   Country("RU","Russian Federation"),
+   Country("RW","Rwanda"),
+   Country("SA","Saudi Arabia"),
+   Country("Sb","Solomon Islands"),
+   Country("SC","Seychelles"),
+   Country("SD","Sudan"),
+   Country("SE","Sweden"),
+   Country("SG","Singapore"),
+   Country("SH","St. Helena"),
+   Country("SI","Slovenia"),
+   Country("SJ","Svalbard and Jan Mayen Islands"),
+   Country("SK","Slovak Republic"),
+   Country("SL","Sierra Leone"),
+   Country("SM","San Marino"),
+   Country("SN","Senegal"),
+   Country("SO","Somalia"),
+   Country("SR","Suriname"),
+   Country("ST","Sao Tome and Principe"),
+   Country("SU","USSR",(["former":1])),
+   Country("SV","El Salvador"),
+   Country("SY","Syria"),
+   Country("SZ","Swaziland"),
+   Country("TC","Turks and Caicos Islands"),
+   Country("TD","Chad"),
+   Country("TF","French Southern Territories"),
+   Country("TG","Togo"),
+   Country("TH","Thailand"),
+   Country("TJ","Tajikistan"),
+   Country("TK","Tokelau"),
+   Country("TM","Turkmenistan"),
+   Country("TN","Tunisia"),
+   Country("TO","Tonga"),
+   Country("TP","East Timor"),
+   Country("TR","Turkey"),
+   Country("TT","Trinidad and Tobago"),
+   Country("TV","Tuvalu"),
+   Country("TW","Taiwan"),
+   Country("TZ","Tanzania"),
+   Country("UA","Ukraine"),
+   Country("UG","Uganda"),
+   Country("UM","US Minor Outlying Islands"),
+   Country("US","United States"),
+   Country("UY","Uruguay"),
+   Country("UZ","Uzbekistan"),
+   Country("VA","Vatican City State (Holy See)"),
+   Country("VC","Saint Vincent and the Grenadines"),
+   Country("VE","Venezuela"),
+   Country("VG","Virgin Islands (British)"),
+   Country("VI","Virgin Islands (U.S.)"),
+   Country("VN","Viet Nam"),
+   Country("VU","Vanuatu"),
+   Country("WF","Wallis and Futuna Islands"),
+   Country("WS","Samoa"),
+   Country("YE","Yemen"),
+   Country("YT","Mayotte"),
+   Country("YU","Yugoslavia"),
+   Country("ZA","South Africa"),
+   Country("ZM","Zambia"),
+   Country("ZR","Zaire"),
+   Country("ZW","Zimbabwe"),
+});
+
+//! module Geographical
+//! submodule Countries
+//! subclass Country
+
+class Country
+{
+//! variable string iso2
+//!    ISO 2-character code aka domain name
+
+   string iso2; // iso-2-character-code aka domain name
+
+//! variable string name
+//! variable array(string) aka
+//!    Country name and as-known-as, if any
+
+   string name;
+   array(string) aka=({});
+
+//! variable int former
+//!    Flag that is set if this isn't a country anymore
+//!    (Like USSR.)
+
+   int former=0;
+
+   void create(string _iso2,string _name,mapping opts)
+   {
+      iso2=_iso2;
+      name=_name;
+      if (opts)
+      {
+	 foreach ( (array)opts, [string what,string val])
+	    ::`[]=(what,val);
+      }
+   }
+
+//! method string cast("string")
+//!	It is possible to cast a country to a string,
+//!	which will be the same as performing 
+//!	<tt>country->name;</tt>.
+
+   string cast(string to)
+   {
+      if (to[..5]=="string") return name;
+      error("can't cast to %O\n",to);
+   }
+
+   string _sprintf(int t)
+   {
+      if (t=='O')
+	 return "Country("+name+")";
+      return 0;
+   }
+
+}
+
+//! module Geographical
+//! submodule Countries
+
+//! constant array(Country) countries
+//!	All known countries.
+
+//! method Country from_domain(string domain)
+//!	Look up a country from a domain name.
+//!	Returns zero if the domain doesn't map
+//!	to a country. Note that there are some
+//!	valid domains that doesn't:
+//!	<dl compact>
+//!	<dt>INT   <dd>International
+//!	<dt>MIL   <dd>US Military
+//!	<dt>NET   <dd>Network
+//!	<dt>ORG   <dd>Non-Profit Organization
+//!	<dt>ARPA  <dd>Old style Arpanet
+//!	<dt>NATO  <dd>Nato field
+//!	</dl>
+//!
+//!	And that USA has three domains, Great Britain two:
+//!	<dl compact>
+//!	<dt>COM   <dd>US Commercial
+//!	<dt>EDU   <dd>US Educational
+//!	<dt>GOV   <dd>US Government
+//!	<dt>GB    <dd>Great Britain (UK)
+//!	<dt>UK    <dd>United Kingdom
+//!	</dl>
+
+
+static private mapping _from_domain=0;
+
+Country from_domain(string domain)
+{
+   if (!_from_domain)
+   {
+      _from_domain=mkmapping(countries->iso2,countries);
+      _from_domain|=
+      (["COM":_from_domain->US,
+	"EDU":_from_domain->US,
+	"MIL":_from_domain->US,
+	"UK":_from_domain->GB,
+      ]);
+   }
+   return _from_domain[upper_case(domain)];
+}
+
+//! method Country from_domain(string name)
+//!	Look up a country from its name or aka.
+//!	The search is case-insensitive but
+//!	regards whitespace and interpunctation.
+
+static private mapping _from_name=0;
+
+Country from_name(string name)
+{
+   if (!_from_name)
+   {
+      _from_name=
+	 `+(@map( countries,
+		  lambda(Country c)
+		  {
+		     if (c->aka && sizeof(c->aka))
+			return 
+		     ([lower_case(c->name):c])+
+			   (mapping)map(
+			      c->aka,
+			      lambda(string n)
+			      {
+				 return ({lower_case(n),c});
+			      });
+		     else
+			return ([lower_case(c->name):c]);
+		  }));
+   }
+   return _from_name[lower_case(name)];
+}
+
+//! method mixed `[](string what)
+//! method mixed `->(string what)
+//!	Convenience function for getting a country
+//!	the name-space way; it looks up whatever it
+//!	is in the name- and domain-space and
+//!	returns that country if possible:
+//!
+//!     <pre>
+//! &gt; Geographical.Countries.se;    
+//! Result: Country(Sweden)
+//! &gt; Geographical.Countries.djibouti;
+//! Result: Country(Djibouti)
+//! &gt; Geographical.Countries.com;     
+//! Result: Country(United States)
+//! &gt; Geographical.Countries.wallis_and_futuna_islands->iso2;
+//! Result: "WF"
+//! 	</pre>
+
+Country|function(string:Country)|array(Country)|program
+   `->(string what)
+{
+   return
+      ::`[](what) ||
+      from_domain(what)||
+      from_name(what)||
+      from_name(replace(what,"_"," "));
+}
+
+function `[] =`->;
diff --git a/lib/modules/Geography.pmod/Position.pike b/lib/modules/Geography.pmod/Position.pike
new file mode 100644
index 0000000000..ec360f278b
--- /dev/null
+++ b/lib/modules/Geography.pmod/Position.pike
@@ -0,0 +1,170 @@
+//!
+//! module Geographical
+//! class Position
+//!	This class contains a geographical position,
+//!	ie a point on the earths surface.
+//!
+
+//! variable float lat
+//! variable float long
+//!	Longitude (W--E) and latitude (N--S) of the position,
+//!	float value in degrees.
+//!	Positive number is north and east, respectively. 
+//!	Negative number is south and west, respectively.
+
+
+float lat;  // latitude in degrees  (N--S)
+float long; // longitude in degrees (W--E)
+
+//! method void create(float lat,float long)
+//! method void create(string lat,string long)
+//! method void create(string both)
+//!	Constructor for this class.
+//!	If feeded with strings, it will perform
+//!	a dwim scan on the strings. If they
+//!	fails to be understood, there will be an exception.
+
+void create(int|float|string _lat,void|int|float|string _long)
+{
+   if (stringp(_lat))
+   {
+      if (zero_type(_long))
+      {
+	 string tmp;
+	 if (sscanf(_lat,"%sN %s",tmp,_long)==2) _long=tmp+"N";
+	 else if (sscanf(_lat,"%sS %s",tmp,_long)==2) _long=tmp+"N";
+	 else if (sscanf(_lat,"%s %s",tmp,_long)==2) _long=tmp;
+      }
+      _lat=dwim(_lat,"NS");
+      if (stringp(_lat))
+	 error("Failed to understand latitude %O\n",lat);
+   }
+   if (stringp(_long))
+   {
+      _long=dwim(_long,"EW");
+      if (stringp(_long))
+	 error("Failed to understand longitude %O\n",long);
+   }
+   lat=(float)_lat;
+   long=(float)_long;
+}
+
+float|string dwim(string what,string direction)
+{
+   float d,m,s;
+   string dir=0;
+   int neg=0;
+#define DIV "%*[ \t\r\n'`�\"]"
+
+   if (sscanf(what,"-%s",what)) neg=1;
+
+   what=upper_case(what);
+
+   sscanf(what,"%f"DIV"%f"DIV"%f"DIV"%["+direction+"]",d,m,s,dir)==7 ||
+      sscanf(what,"%f"DIV"%f"DIV       "%["+direction+"]",d,m,  dir)==5 ||
+      sscanf(what,"%f"DIV              "%["+direction+"]",d,    dir);
+
+   if (dir==direction[1..1]) neg=!neg;
+
+   d+=m/60+s/3600;
+   return neg?-d:d;
+}
+
+//! method string latitude(void|int n)
+//! method string longitude(void|int n)
+//!	Returns the nicely formatted latitude
+//!	or longitude. 
+//!	<pre>
+//!	n    format
+//!	-    17�42.19'N       42�22.2'W
+//!	1    17.703�N         42.37�W
+//!	2    17�42.18'N       42�22.2'W
+//!	3    17�42'10.4"N     42�22'12"W
+//!	-1   17.703           -42.37
+//!	</pre>
+
+string prettyprint(float what,int n,string directions)
+{
+   if (what<0) what=-what,directions=directions[1..];
+   else directions=directions[..0];
+
+   switch (n)
+   {
+      case -1: return sprintf("%.5g",what);
+      case 1:
+	 return sprintf("%.5g�%s",what,directions);
+      case 3:
+	 return sprintf("%d�%d'%.3g\"%s",
+			(int)floor(what),(int)floor(60*(what-floor(what))),
+			3600*(what-floor(60*what)/60),
+			directions);
+      default:
+	 return sprintf("%d�%.5g'%s",
+			(int)floor(what),60*(what-floor(what)),
+			directions);
+   }
+}
+
+string latitude(void|int n)
+{
+   return prettyprint(lat,n,"NS");
+}
+
+string longitude(void|int n)
+{
+   return prettyprint(long,n,"EW");
+}
+
+
+//! method array cast("array")
+//!	It is possible to cast the position to an array,
+//!	<tt>({float lat,float long})</tt>.
+
+string|array cast(string to)
+{
+   if (to[..4]=="array")
+      return ({lat,long});
+
+   if (to[..5]=="string")
+      return latitude()+" "+longitude();
+
+   error("can't cast to %O\n",to);
+}
+
+//! method int __hash()
+//! method int `==(Position pos)
+//! method int `<(Position pos)
+//! method int `>(Position pos)
+//!	These exist solely for purpose of detecting
+//!	equal positions, for instance when used as keys in mappings.
+
+int __hash()
+{
+   return (int)(lat*3600000+long*3600000);
+}
+
+int `==(object pos)
+{
+   return (pos->lat==lat && pos->long==long);
+}
+
+int `<(object pos)
+{
+   if (pos->lat>lat) return 1;
+   else if (pos->lat==lat && pos->long>long) return 1;
+   return 0;
+}
+
+int `>(object pos)
+{
+   if (pos->lat<lat) return 1;
+   else if (pos->lat==lat && pos->long<long) return 1;
+   return 0;
+}
+
+string _sprintf(int t)
+{
+   if (t=='O')
+      return "Position("+longitude()+", "+latitude()+")";
+   return 0;
+}
-- 
GitLab