1 /*
2  * Copyright (C) 2012 The Libphonenumber Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.i18n.phonenumbers.prefixmapper;
18 
19 import com.google.i18n.phonenumbers.PhoneNumberUtil;
20 import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
21 
22 import java.io.Externalizable;
23 import java.io.IOException;
24 import java.io.ObjectInput;
25 import java.io.ObjectOutput;
26 import java.util.LinkedList;
27 import java.util.List;
28 import java.util.SortedMap;
29 import java.util.StringTokenizer;
30 
31 /**
32  * A utility that maps phone number prefixes to a list of strings describing the time zones to
33  * which each prefix belongs.
34  */
35 public class PrefixTimeZonesMap implements Externalizable {
36   private final PhonePrefixMap phonePrefixMap = new PhonePrefixMap();
37   private static final String RAW_STRING_TIMEZONES_SEPARATOR = "&";
38 
39   /**
40     * Creates a {@link PrefixTimeZoneMap} initialized with {@code sortedPrefixTimeZoneMap}.  Note
41     * that the underlying implementation of this method is expensive thus should not be called by
42     * time-critical applications.
43     *
44     * @param sortedPrefixTimeZoneMap  a map from phone number prefixes to their corresponding time
45     * zones, sorted in ascending order of the phone number prefixes as integers.
46     */
readPrefixTimeZonesMap(SortedMap<Integer, String> sortedPrefixTimeZoneMap)47   public void readPrefixTimeZonesMap(SortedMap<Integer, String> sortedPrefixTimeZoneMap) {
48     phonePrefixMap.readPhonePrefixMap(sortedPrefixTimeZoneMap);
49   }
50 
51   /**
52    * Supports Java Serialization.
53    */
writeExternal(ObjectOutput objectOutput)54   public void writeExternal(ObjectOutput objectOutput) throws IOException {
55     phonePrefixMap.writeExternal(objectOutput);
56   }
57 
readExternal(ObjectInput objectInput)58   public void readExternal(ObjectInput objectInput) throws IOException {
59     phonePrefixMap.readExternal(objectInput);
60   }
61 
62   /**
63    * Returns the list of time zones {@code key} corresponds to.
64    *
65    * <p>{@code key} could be the calling country code and the full significant number of a
66    * certain number, or it could be just a phone-number prefix.
67    * For example, the full number 16502530000 (from the phone-number +1 650 253 0000) is a valid
68    * input. Also, any of its prefixes, such as 16502, is also valid.
69    *
70    * @param key  the key to look up
71    * @return  the list of corresponding time zones
72    */
lookupTimeZonesForNumber(long key)73   private List<String> lookupTimeZonesForNumber(long key) {
74     // Lookup in the map data. The returned String may consist of several time zones, so it must be
75     // split.
76     String timezonesString = phonePrefixMap.lookup(key);
77     if (timezonesString == null) {
78       return new LinkedList<String>();
79     }
80     return tokenizeRawOutputString(timezonesString);
81   }
82 
83   /**
84    * As per {@link #lookupTimeZonesForNumber(long)}, but receives the number as a PhoneNumber
85    * instead of a long.
86    *
87    * @param number  the phone number to look up
88    * @return  the list of corresponding time zones
89    */
lookupTimeZonesForNumber(PhoneNumber number)90   public List<String> lookupTimeZonesForNumber(PhoneNumber number) {
91     long phonePrefix = Long.parseLong(number.getCountryCode() +
92         PhoneNumberUtil.getInstance().getNationalSignificantNumber(number));
93     return lookupTimeZonesForNumber(phonePrefix);
94   }
95 
96   /**
97    * Returns the list of time zones {@code number}'s calling country code corresponds to.
98    *
99    * @param number  the phone number to look up
100    * @return  the list of corresponding time zones
101    */
lookupCountryLevelTimeZonesForNumber(PhoneNumber number)102   public List<String> lookupCountryLevelTimeZonesForNumber(PhoneNumber number) {
103     return lookupTimeZonesForNumber(number.getCountryCode());
104   }
105 
106   /**
107    * Split {@code timezonesString} into all the time zones that are part of it.
108    */
tokenizeRawOutputString(String timezonesString)109   private List<String> tokenizeRawOutputString(String timezonesString) {
110     StringTokenizer tokenizer = new StringTokenizer(timezonesString,
111                                                     RAW_STRING_TIMEZONES_SEPARATOR);
112     LinkedList<String> timezonesList = new LinkedList<String>();
113     while (tokenizer.hasMoreTokens()) {
114       timezonesList.add(tokenizer.nextToken());
115     }
116     return timezonesList;
117   }
118 
119   /**
120    * Dumps the mappings contained in the phone prefix map.
121    */
122   @Override
toString()123   public String toString() {
124     return phonePrefixMap.toString();
125   }
126 }
127