1// Copyright (C) 2014 Google Inc.
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#include <libaddressinput/address_data.h>
16
17#include <libaddressinput/address_field.h>
18#include <libaddressinput/util/basictypes.h>
19
20#include <algorithm>
21#include <cassert>
22#include <cstddef>
23#include <functional>
24#include <ostream>
25#include <string>
26#include <vector>
27
28#include <re2/re2.h>
29
30namespace i18n {
31namespace addressinput {
32
33namespace {
34
35// Mapping from AddressField value to pointer to AddressData member.
36std::string AddressData::*kStringField[] = {
37  &AddressData::region_code,
38  &AddressData::administrative_area,
39  &AddressData::locality,
40  &AddressData::dependent_locality,
41  &AddressData::sorting_code,
42  &AddressData::postal_code,
43  NULL,
44  &AddressData::organization,
45  &AddressData::recipient
46};
47
48// Mapping from AddressField value to pointer to AddressData member.
49const std::vector<std::string> AddressData::*kVectorStringField[] = {
50  NULL,
51  NULL,
52  NULL,
53  NULL,
54  NULL,
55  NULL,
56  &AddressData::address_line,
57  NULL,
58  NULL
59};
60
61COMPILE_ASSERT(arraysize(kStringField) == arraysize(kVectorStringField),
62               field_mapping_array_size_mismatch);
63
64// A string is considered to be "empty" not only if it actually is empty, but
65// also if it contains nothing but whitespace.
66bool IsStringEmpty(const std::string& str) {
67  static const RE2 kMatcher("\\S");
68  return str.empty() || !RE2::PartialMatch(str, kMatcher);
69}
70
71}  // namespace
72
73bool AddressData::IsFieldEmpty(AddressField field) const {
74  assert(field >= 0);
75  assert(static_cast<size_t>(field) < arraysize(kStringField));
76  if (kStringField[field] != NULL) {
77    const std::string& value = GetFieldValue(field);
78    return IsStringEmpty(value);
79  } else {
80    const std::vector<std::string>& value = GetRepeatedFieldValue(field);
81    return std::find_if(value.begin(),
82                        value.end(),
83                        std::not1(std::ptr_fun(&IsStringEmpty))) == value.end();
84  }
85}
86
87const std::string& AddressData::GetFieldValue(
88    AddressField field) const {
89  assert(field >= 0);
90  assert(static_cast<size_t>(field) < arraysize(kStringField));
91  assert(kStringField[field] != NULL);
92  return this->*kStringField[field];
93}
94
95void AddressData::SetFieldValue(AddressField field, const std::string& value) {
96  assert(field >= 0);
97  assert(static_cast<size_t>(field) < arraysize(kStringField));
98  assert(kStringField[field] != NULL);
99  (this->*kStringField[field]).assign(value);
100}
101
102const std::vector<std::string>& AddressData::GetRepeatedFieldValue(
103    AddressField field) const {
104  assert(IsRepeatedFieldValue(field));
105  return this->*kVectorStringField[field];
106}
107
108bool AddressData::operator==(const AddressData& other) const {
109  return region_code == other.region_code &&
110         address_line == other.address_line &&
111         administrative_area == other.administrative_area &&
112         locality == other.locality &&
113         dependent_locality == other.dependent_locality &&
114         postal_code == other.postal_code &&
115         sorting_code == other.sorting_code &&
116         language_code == other.language_code &&
117         organization == other.organization &&
118         recipient == other.recipient;
119}
120
121// static
122bool AddressData::IsRepeatedFieldValue(AddressField field) {
123  assert(field >= 0);
124  assert(static_cast<size_t>(field) < arraysize(kVectorStringField));
125  return kVectorStringField[field] != NULL;
126}
127
128}  // namespace addressinput
129}  // namespace i18n
130
131std::ostream& operator<<(std::ostream& o,
132                         const i18n::addressinput::AddressData& address) {
133  o << "region_code: \"" << address.region_code << "\"\n"
134    "administrative_area: \"" << address.administrative_area << "\"\n"
135    "locality: \"" << address.locality << "\"\n"
136    "dependent_locality: \"" << address.dependent_locality << "\"\n"
137    "postal_code: \"" << address.postal_code << "\"\n"
138    "sorting_code: \"" << address.sorting_code << "\"\n";
139
140  // TODO: Update the field order in the .h file to match the order they are
141  // printed out here, for consistency.
142  for (std::vector<std::string>::const_iterator it =
143           address.address_line.begin();
144       it != address.address_line.end(); ++it) {
145    o << "address_line: \"" << *it << "\"\n";
146  }
147
148  o << "language_code: \"" << address.language_code << "\"\n"
149    "organization: \"" << address.organization << "\"\n"
150    "recipient: \"" << address.recipient << "\"\n";
151
152  return o;
153}
154