1// Copyright (C) 2012 The Libphonenumber Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15// Author: Patrick Mezard
16
17#include "phonenumbers/geocoding/area_code_map.h"
18
19#include <cstddef>
20
21#include "phonenumbers/geocoding/default_map_storage.h"
22#include "phonenumbers/phonenumber.pb.h"
23#include "phonenumbers/phonenumberutil.h"
24#include "phonenumbers/stringutil.h"
25
26namespace i18n {
27namespace phonenumbers {
28
29AreaCodeMap::AreaCodeMap()
30  : phone_util_(*PhoneNumberUtil::GetInstance()) {
31}
32
33AreaCodeMap::~AreaCodeMap() {
34}
35
36void AreaCodeMap::ReadAreaCodeMap(const PrefixDescriptions* descriptions) {
37  DefaultMapStorage* storage = new DefaultMapStorage();
38  storage->ReadFromMap(descriptions);
39  storage_.reset(storage);
40}
41
42const char* AreaCodeMap::Lookup(const PhoneNumber& number) const {
43  const int entries = storage_->GetNumOfEntries();
44  if (!entries) {
45    return NULL;
46  }
47
48  string national_number;
49  phone_util_.GetNationalSignificantNumber(number, &national_number);
50  int64 phone_prefix;
51  safe_strto64(SimpleItoa(number.country_code()) + national_number,
52               &phone_prefix);
53
54  const int* const lengths = storage_->GetPossibleLengths();
55  const int lengths_size = storage_->GetPossibleLengthsSize();
56  int current_index = entries - 1;
57  for (int lengths_index = lengths_size - 1; lengths_index >= 0;
58       --lengths_index) {
59    const int possible_length = lengths[lengths_index];
60    string phone_prefix_str = SimpleItoa(phone_prefix);
61    if (static_cast<int>(phone_prefix_str.length()) > possible_length) {
62      safe_strto64(phone_prefix_str.substr(0, possible_length), &phone_prefix);
63    }
64    current_index = BinarySearch(0, current_index, phone_prefix);
65    if (current_index < 0) {
66      return NULL;
67    }
68    const int32 current_prefix = storage_->GetPrefix(current_index);
69    if (phone_prefix == current_prefix) {
70      return storage_->GetDescription(current_index);
71    }
72  }
73  return NULL;
74}
75
76int AreaCodeMap::BinarySearch(int start, int end, int64 value) const {
77  int current = 0;
78  while (start <= end) {
79    current = (start + end) / 2;
80    int32 current_value = storage_->GetPrefix(current);
81    if (current_value == value) {
82      return current;
83    } else if (current_value > value) {
84      --current;
85      end = current;
86    } else {
87      start = current + 1;
88    }
89  }
90  return current;
91}
92
93}  // namespace phonenumbers
94}  // namespace i18n
95