1 /*
  2  * phoneloc.js - Represent a phone locale object.
  3  *
  4  * Copyright © 2014-2015, 2018, JEDLSoft
  5  *
  6  * Licensed under the Apache License, Version 2.0 (the "License");
  7  * you may not use this file except in compliance with the License.
  8  * You may obtain a copy of the License at
  9  *
 10  *     http://www.apache.org/licenses/LICENSE-2.0
 11  *
 12  * Unless required by applicable law or agreed to in writing, software
 13  * distributed under the License is distributed on an "AS IS" BASIS,
 14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 15  *
 16  * See the License for the specific language governing permissions and
 17  * limitations under the License.
 18  */
 19 
 20 // !data phoneloc
 21 
 22 var ilib = require("../index.js");
 23 var Utils = require("./Utils.js");
 24 var Locale = require("./Locale.js");
 25 
 26 /**
 27  * @class
 28  * Extension of the locale class that has extra methods to map various numbers
 29  * related to phone number parsing.
 30  *
 31  * @param {Object} options Options that govern how this phone locale works
 32  *
 33  * @private
 34  * @constructor
 35  * @extends Locale
 36  */
 37 var PhoneLocale = function(options) {
 38     var region,
 39         mcc,
 40         cc,
 41         sync = true,
 42         loadParams = {},
 43         locale;
 44 
 45     locale = (options && options.locale) || ilib.getLocale();
 46 
 47     this.parent.call(this, locale);
 48 
 49     region = this.region;
 50 
 51     if (options) {
 52         if (typeof(options.mcc) !== 'undefined') {
 53             mcc = options.mcc;
 54         }
 55 
 56         if (typeof(options.countryCode) !== 'undefined') {
 57             cc = options.countryCode;
 58         }
 59 
 60         if (typeof(options.sync) !== 'undefined') {
 61             sync = !!options.sync;
 62         }
 63 
 64         if (options.loadParams) {
 65             loadParams = options.loadParams;
 66         }
 67     }
 68 
 69     Utils.loadData({
 70         name: "phoneloc.json",
 71         object: "PhoneLocale",
 72         nonlocale: true,
 73         sync: sync,
 74         loadParams: loadParams,
 75         callback: ilib.bind(this, function (data) {
 76             /** @type {{mcc2reg:Object.<string,string>,cc2reg:Object.<string,string>,reg2cc:Object.<string,string>,area2reg:Object.<string,string>}} */
 77             this.mappings = data;
 78 
 79             if (typeof(mcc) !== 'undefined') {
 80                 region = this.mappings.mcc2reg[mcc];
 81             }
 82 
 83             if (typeof(cc) !== 'undefined') {
 84                 region = this.mappings.cc2reg[cc];
 85             }
 86 
 87             if (!region) {
 88                 region = "XX";
 89             }
 90 
 91             this.region = this._normPhoneReg(region);
 92             this._genSpec();
 93 
 94             if (options && typeof(options.onLoad) === 'function') {
 95                 options.onLoad(this);
 96             }
 97         })
 98     });
 99 };
100 
101 PhoneLocale.prototype = new Locale();
102 PhoneLocale.prototype.parent = Locale;
103 PhoneLocale.prototype.constructor = PhoneLocale;
104 
105 /**
106  * Map a mobile carrier code to a region code.
107  *
108  * @static
109  * @package
110  * @param {string|undefined} mcc the MCC to map
111  * @return {string|undefined} the region code
112  */
113 
114 PhoneLocale.prototype._mapMCCtoRegion = function(mcc) {
115     if (!mcc) {
116         return undefined;
117     }
118     return this.mappings.mcc2reg && this.mappings.mcc2reg[mcc] || "XX";
119 };
120 
121 /**
122  * Map a country code to a region code.
123  *
124  * @static
125  * @package
126  * @param {string|undefined} cc the country code to map
127  * @return {string|undefined} the region code
128  */
129 PhoneLocale.prototype._mapCCtoRegion = function(cc) {
130     if (!cc) {
131         return undefined;
132     }
133     return this.mappings.cc2reg && this.mappings.cc2reg[cc] || "XX";
134 };
135 
136 /**
137  * Map a region code to a country code.
138  *
139  * @static
140  * @package
141  * @param {string|undefined} region the region code to map
142  * @return {string|undefined} the country code
143  */
144 PhoneLocale.prototype._mapRegiontoCC = function(region) {
145     if (!region) {
146         return undefined;
147     }
148     return this.mappings.reg2cc && this.mappings.reg2cc[region] || "0";
149 };
150 
151 /**
152  * Map a country code to a region code.
153  *
154  * @static
155  * @package
156  * @param {string|undefined} cc the country code to map
157  * @param {string|undefined} area the area code within the country code's numbering plan
158  * @return {string|undefined} the region code
159  */
160 PhoneLocale.prototype._mapAreatoRegion = function(cc, area) {
161     if (!cc) {
162         return undefined;
163     }
164     if (cc in this.mappings.area2reg) {
165         return this.mappings.area2reg[cc][area] || this.mappings.area2reg[cc]["default"];
166     } else {
167         return this.mappings.cc2reg[cc];
168     }
169 };
170 
171 /**
172  * Return the region that controls the dialing plan in the given
173  * region. (ie. the "normalized phone region".)
174  *
175  * @static
176  * @package
177  * @param {string} region the region code to normalize
178  * @return {string} the normalized region code
179  */
180 PhoneLocale.prototype._normPhoneReg = function(region) {
181     var norm;
182 
183     /*
184     * Country list has been updated from metadata.json fro, libphonenumber-js library  v1.7.20
185     * and Modified some countries based on Wikipedia
186     */
187 
188     // Map all NANP regions to the right region, so that they get parsed using the
189     // correct state table
190     switch (region) {
191         case "US": // usa
192         case "AG": // antigua and barbuda
193         case "AI": // anguilla
194         case "AS": // American Samoa
195         case "BB": // barbados
196         case "BM": // bermuda
197         case "BS": // bahamas
198         case "CA": // canada
199         case "DM": // dominica
200         case "DO": // dominican republic
201         case "GD": // grenada
202         case "GU": // Guam
203         case "JM": // jamaica
204         case "KN": // st. kitts and nevis
205         case "KY": // cayman islands
206         case "LC": // st. lucia
207         case "MP": // Northern Mariana Islands
208         case "MS": // montserrat
209         case "PR": // Puerto Rico
210         case "SX": // Sint Maarten
211         case "TC": // turks and caicos
212         case "TT": // trinidad and tobago
213         case "VC": // st. vincent and the grenadines
214         case "VG": // british virgin islands
215         case "VI": // Virgin Islands, U.S.
216             norm = "US";
217             break;
218 
219         /* all the French dependencies are on the French dialling plan
220         *  Update manually following Wikipedia information
221         * https://en.wikipedia.org/wiki/Telephone_numbers_in_France#Others
222         */
223         case "FR": // france
224         case "GF": // french guiana
225         case "MQ": // martinique
226         case "GP": // guadeloupe,
227         case "BL": // saint barthélemy
228         case "MF": // saint martin
229         case "RE": // réunion
230         case "YT": // mayotte
231             norm = "FR";
232             break;
233 
234         // these all use the Italian dialling plan
235         case "IT": // italy
236         case "SM": // san marino
237         case "VA": // vatican city  // Update manually following Wikipedia information
238             norm = "IT";
239             break;
240 
241         // all the UK dependencies are on the UK dialling plan
242         case "GB": // United Kingdom
243         case "GG": // Guernsey
244         case "IM": // Isle of Man
245         case "JE": // Jersey
246             norm = "GB";
247             break;
248         case "RU": // Russia
249         case "KZ": // Kazakhstan
250             norm = "RU";
251             break;
252         case "NO": // Norway
253         case "SJ": // Svalbard and Jan Mayen
254             norm = "NO";
255             break;
256         case "AU": // Australia
257         case "CC": // Cocos (Keeling) Islands
258         case "CX": // Christmas Island
259             norm = "AU";
260             break;
261         case "MA": // Morocco
262         case "EH": // Western Sahara
263             norm = "MA";
264             break;
265         case "SH": // Saint Helena
266         case "TA": // ?
267             norm = "SH";
268             break;
269         case "FI": // Finland
270         case "AX": // Aland Islands
271             norm = "FI";
272             break;
273         case "GP": // Guadeloupe
274         case "BL": // Saint-Barthélemy
275         case "MF": // Saint Martin (French part)
276             norm = "GP";
277             break;
278         case "CW": // Curaçao
279         case "BQ": // Caribbean Netherlands
280             norm = "CW";
281             break;
282         default:
283             norm = region;
284             break;
285     }
286     return norm;
287 };
288 
289 module.exports = PhoneLocale;