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
17package com.google.i18n.phonenumbers.prefixmapper;
18
19import com.google.i18n.phonenumbers.PhoneNumberUtil;
20import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
21
22import java.io.Externalizable;
23import java.io.IOException;
24import java.io.ObjectInput;
25import java.io.ObjectOutput;
26import java.util.LinkedList;
27import java.util.List;
28import java.util.SortedMap;
29import 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 */
35public 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    */
47  public void readPrefixTimeZonesMap(SortedMap<Integer, String> sortedPrefixTimeZoneMap) {
48    phonePrefixMap.readPhonePrefixMap(sortedPrefixTimeZoneMap);
49  }
50
51  /**
52   * Supports Java Serialization.
53   */
54  public void writeExternal(ObjectOutput objectOutput) throws IOException {
55    phonePrefixMap.writeExternal(objectOutput);
56  }
57
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   */
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   */
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   */
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   */
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
123  public String toString() {
124    return phonePrefixMap.toString();
125  }
126}
127