1bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com// Copyright (C) 2014 Google Inc.
2bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com//
3bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com// Licensed under the Apache License, Version 2.0 (the "License");
4bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com// you may not use this file except in compliance with the License.
5bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com// You may obtain a copy of the License at
6bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com//
7bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com// http://www.apache.org/licenses/LICENSE-2.0
8bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com//
9bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com// Unless required by applicable law or agreed to in writing, software
10bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com// distributed under the License is distributed on an "AS IS" BASIS,
11bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com// See the License for the specific language governing permissions and
13bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com// limitations under the License.
14bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com
15bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com#include "validation_task.h"
16bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com
17bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com#include <libaddressinput/address_data.h>
18bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com#include <libaddressinput/address_field.h>
19b1b5b1fcaaaa95129f1f351641dd20d14bc667e3roubert@google.com#include <libaddressinput/address_metadata.h>
20bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com#include <libaddressinput/address_problem.h>
21bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com#include <libaddressinput/address_validator.h>
229f47fe3ed525accac995b095d408a825673a2ee1roubert@google.com#include <libaddressinput/callback.h>
239693f6426f3500db74dcfc766a130a747a571e5eroubert@google.com#include <libaddressinput/supplier.h>
24bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com#include <libaddressinput/util/basictypes.h>
25bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com
26bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com#include <algorithm>
27bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com#include <cassert>
28bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com#include <cstddef>
29bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com#include <string>
30bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com#include <utility>
31bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com#include <vector>
32bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com
339f47fe3ed525accac995b095d408a825673a2ee1roubert@google.com#include <re2/re2.h>
349f47fe3ed525accac995b095d408a825673a2ee1roubert@google.com
35bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com#include "lookup_key.h"
36bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com#include "post_box_matchers.h"
37bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com#include "rule.h"
38ea5e77397b59d94af3591644c3dc23dc6f9ba22eroubert@google.com#include "util/re2ptr.h"
39ea5e77397b59d94af3591644c3dc23dc6f9ba22eroubert@google.com
40bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.comnamespace i18n {
41bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.comnamespace addressinput {
42bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com
43bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.comValidationTask::ValidationTask(const AddressData& address,
44bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com                               bool allow_postal,
45bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com                               bool require_name,
46bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com                               const FieldProblemMap* filter,
47bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com                               FieldProblemMap* problems,
48bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com                               const AddressValidator::Callback& validated)
49bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com    : address_(address),
50bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com      allow_postal_(allow_postal),
51bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com      require_name_(require_name),
52bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com      filter_(filter),
53bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com      problems_(problems),
54bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com      validated_(validated),
559693f6426f3500db74dcfc766a130a747a571e5eroubert@google.com      supplied_(BuildCallback(this, &ValidationTask::Validate)),
56bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com      lookup_key_(new LookupKey) {
57bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  assert(problems_ != NULL);
589693f6426f3500db74dcfc766a130a747a571e5eroubert@google.com  assert(supplied_ != NULL);
59bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  assert(lookup_key_ != NULL);
60bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com}
61bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com
62bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.comValidationTask::~ValidationTask() {
63bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com}
64bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com
659693f6426f3500db74dcfc766a130a747a571e5eroubert@google.comvoid ValidationTask::Run(Supplier* supplier) const {
669693f6426f3500db74dcfc766a130a747a571e5eroubert@google.com  assert(supplier != NULL);
67bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  problems_->clear();
68bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  lookup_key_->FromAddress(address_);
699693f6426f3500db74dcfc766a130a747a571e5eroubert@google.com  supplier->Supply(*lookup_key_, *supplied_);
70bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com}
71bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com
72bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.comvoid ValidationTask::Validate(bool success,
73bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com                              const LookupKey& lookup_key,
749693f6426f3500db74dcfc766a130a747a571e5eroubert@google.com                              const Supplier::RuleHierarchy& hierarchy) {
75bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  assert(&lookup_key == lookup_key_.get());  // Sanity check.
76bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com
77bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  if (success) {
78bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com    if (address_.IsFieldEmpty(COUNTRY)) {
79bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com      ReportProblemMaybe(COUNTRY, MISSING_REQUIRED_FIELD);
8017471f7b69a94f92480650b06721e698204be3c0roubert@google.com    } else if (hierarchy.rule[0] == NULL) {
81bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com      ReportProblemMaybe(COUNTRY, UNKNOWN_VALUE);
82bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com    } else {
83b1b5b1fcaaaa95129f1f351641dd20d14bc667e3roubert@google.com      // Checks which use statically linked metadata.
84b1b5b1fcaaaa95129f1f351641dd20d14bc667e3roubert@google.com      const std::string& region_code = address_.region_code;
85b1b5b1fcaaaa95129f1f351641dd20d14bc667e3roubert@google.com      CheckUnexpectedField(region_code);
86b1b5b1fcaaaa95129f1f351641dd20d14bc667e3roubert@google.com      CheckMissingRequiredField(region_code);
87b1b5b1fcaaaa95129f1f351641dd20d14bc667e3roubert@google.com
88b1b5b1fcaaaa95129f1f351641dd20d14bc667e3roubert@google.com      // Checks which use data from the metadata server. Note that
89b1b5b1fcaaaa95129f1f351641dd20d14bc667e3roubert@google.com      // CheckPostalCodeFormatAndValue assumes CheckUnexpectedField has already
90b1b5b1fcaaaa95129f1f351641dd20d14bc667e3roubert@google.com      // been called.
91bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com      CheckUnknownValue(hierarchy);
92bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com      CheckPostalCodeFormatAndValue(hierarchy);
93bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com      CheckUsesPoBox(hierarchy);
94bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com    }
95bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  }
96bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com
97bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  validated_(success, address_, *problems_);
98bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  delete this;
99bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com}
100bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com
101b1b5b1fcaaaa95129f1f351641dd20d14bc667e3roubert@google.com// A field will return an UNEXPECTED_FIELD problem type if the current value of
102b1b5b1fcaaaa95129f1f351641dd20d14bc667e3roubert@google.com// that field is not empty and the field should not be used by that region.
103bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.comvoid ValidationTask::CheckUnexpectedField(
104b1b5b1fcaaaa95129f1f351641dd20d14bc667e3roubert@google.com    const std::string& region_code) const {
105bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  static const AddressField kFields[] = {
106bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com    // COUNTRY is never unexpected.
107bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com    ADMIN_AREA,
108bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com    LOCALITY,
109bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com    DEPENDENT_LOCALITY,
110bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com    SORTING_CODE,
111bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com    POSTAL_CODE,
112bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com    STREET_ADDRESS,
113b52a2aeb63a28914850f3ed81cd7fd26ecdd4cdcrouslan@chromium.org    ORGANIZATION,
114bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com    RECIPIENT
115bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  };
116bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com
117bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  for (size_t i = 0; i < arraysize(kFields); ++i) {
118bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com    AddressField field = kFields[i];
119b1b5b1fcaaaa95129f1f351641dd20d14bc667e3roubert@google.com    if (!address_.IsFieldEmpty(field) && !IsFieldUsed(field, region_code)) {
120bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com      ReportProblemMaybe(field, UNEXPECTED_FIELD);
121bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com    }
122bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  }
123bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com}
124bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com
125b1b5b1fcaaaa95129f1f351641dd20d14bc667e3roubert@google.com// A field will return an MISSING_REQUIRED_FIELD problem type if the current
126b1b5b1fcaaaa95129f1f351641dd20d14bc667e3roubert@google.com// value of that field is empty and the field is required by that region.
127bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.comvoid ValidationTask::CheckMissingRequiredField(
128b1b5b1fcaaaa95129f1f351641dd20d14bc667e3roubert@google.com    const std::string& region_code) const {
129b1b5b1fcaaaa95129f1f351641dd20d14bc667e3roubert@google.com  static const AddressField kFields[] = {
130b1b5b1fcaaaa95129f1f351641dd20d14bc667e3roubert@google.com    // COUNTRY is assumed to have already been checked.
131b1b5b1fcaaaa95129f1f351641dd20d14bc667e3roubert@google.com    ADMIN_AREA,
132b1b5b1fcaaaa95129f1f351641dd20d14bc667e3roubert@google.com    LOCALITY,
133b1b5b1fcaaaa95129f1f351641dd20d14bc667e3roubert@google.com    DEPENDENT_LOCALITY,
134b1b5b1fcaaaa95129f1f351641dd20d14bc667e3roubert@google.com    SORTING_CODE,
135b1b5b1fcaaaa95129f1f351641dd20d14bc667e3roubert@google.com    POSTAL_CODE,
136b52a2aeb63a28914850f3ed81cd7fd26ecdd4cdcrouslan@chromium.org    STREET_ADDRESS
137b52a2aeb63a28914850f3ed81cd7fd26ecdd4cdcrouslan@chromium.org    // ORGANIZATION is never required.
138b1b5b1fcaaaa95129f1f351641dd20d14bc667e3roubert@google.com    // RECIPIENT is handled separately.
139b1b5b1fcaaaa95129f1f351641dd20d14bc667e3roubert@google.com  };
140bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com
141b1b5b1fcaaaa95129f1f351641dd20d14bc667e3roubert@google.com  for (size_t i = 0; i < arraysize(kFields); ++i) {
142b1b5b1fcaaaa95129f1f351641dd20d14bc667e3roubert@google.com    AddressField field = kFields[i];
143b1b5b1fcaaaa95129f1f351641dd20d14bc667e3roubert@google.com    if (address_.IsFieldEmpty(field) && IsFieldRequired(field, region_code)) {
144b1b5b1fcaaaa95129f1f351641dd20d14bc667e3roubert@google.com      ReportProblemMaybe(field, MISSING_REQUIRED_FIELD);
145bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com    }
146bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  }
147bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com
148bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  if (require_name_ && address_.IsFieldEmpty(RECIPIENT)) {
149bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com    ReportProblemMaybe(RECIPIENT, MISSING_REQUIRED_FIELD);
150bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  }
151bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com}
152bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com
153bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com// A field is UNKNOWN_VALUE if the metadata contains a list of possible values
154bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com// for the field and the address data server could not match the current value
155bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com// of that field to one of those possible values, therefore returning NULL.
156bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.comvoid ValidationTask::CheckUnknownValue(
1579693f6426f3500db74dcfc766a130a747a571e5eroubert@google.com    const Supplier::RuleHierarchy& hierarchy) const {
158bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  for (size_t depth = 1; depth < arraysize(LookupKey::kHierarchy); ++depth) {
159bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com    AddressField field = LookupKey::kHierarchy[depth];
160bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com    if (!(address_.IsFieldEmpty(field) ||
16117471f7b69a94f92480650b06721e698204be3c0roubert@google.com          hierarchy.rule[depth - 1] == NULL ||
16217471f7b69a94f92480650b06721e698204be3c0roubert@google.com          hierarchy.rule[depth - 1]->GetSubKeys().empty() ||
16317471f7b69a94f92480650b06721e698204be3c0roubert@google.com          hierarchy.rule[depth] != NULL)) {
164bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com      ReportProblemMaybe(field, UNKNOWN_VALUE);
165bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com    }
166bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  }
167bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com}
168bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com
169b1b5b1fcaaaa95129f1f351641dd20d14bc667e3roubert@google.com// Note that it is assumed that CheckUnexpectedField has already been called.
170bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.comvoid ValidationTask::CheckPostalCodeFormatAndValue(
1719693f6426f3500db74dcfc766a130a747a571e5eroubert@google.com    const Supplier::RuleHierarchy& hierarchy) const {
17217471f7b69a94f92480650b06721e698204be3c0roubert@google.com  assert(hierarchy.rule[0] != NULL);
17317471f7b69a94f92480650b06721e698204be3c0roubert@google.com  const Rule& country_rule = *hierarchy.rule[0];
174bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com
175bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  if (!(ShouldReport(POSTAL_CODE, INVALID_FORMAT) ||
176bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com        ShouldReport(POSTAL_CODE, MISMATCHING_VALUE))) {
177bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com    return;
178bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  }
179bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com
180bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  if (address_.IsFieldEmpty(POSTAL_CODE)) {
181bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com    return;
182b1b5b1fcaaaa95129f1f351641dd20d14bc667e3roubert@google.com  } else if (std::find(problems_->begin(), problems_->end(),
183b1b5b1fcaaaa95129f1f351641dd20d14bc667e3roubert@google.com                       FieldProblemMap::value_type(POSTAL_CODE,
184b1b5b1fcaaaa95129f1f351641dd20d14bc667e3roubert@google.com                                                   UNEXPECTED_FIELD))
185b1b5b1fcaaaa95129f1f351641dd20d14bc667e3roubert@google.com             != problems_->end()) {
186b1b5b1fcaaaa95129f1f351641dd20d14bc667e3roubert@google.com    return;  // Problem already reported.
187bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  }
188bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com
189bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  // Validate general postal code format. A country-level rule specifies the
190bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  // regular expression for the whole postal code.
191bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  const RE2ptr* format_ptr = country_rule.GetPostalCodeMatcher();
192bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  if (format_ptr != NULL &&
193bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com      !RE2::FullMatch(address_.postal_code, *format_ptr->ptr) &&
194bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com      ShouldReport(POSTAL_CODE, INVALID_FORMAT)) {
195bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com    ReportProblem(POSTAL_CODE, INVALID_FORMAT);
196bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com    return;
197bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  }
198bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com
199bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  if (!ShouldReport(POSTAL_CODE, MISMATCHING_VALUE)) {
200bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com    return;
201bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  }
202bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com
203bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  for (size_t depth = arraysize(LookupKey::kHierarchy) - 1;
204bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com       depth > 0; --depth) {
20517471f7b69a94f92480650b06721e698204be3c0roubert@google.com    if (hierarchy.rule[depth] != NULL) {
206bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com      // Validate sub-region specific postal code format. A sub-region specifies
207bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com      // the regular expression for a prefix of the postal code.
20817471f7b69a94f92480650b06721e698204be3c0roubert@google.com      const RE2ptr* prefix_ptr = hierarchy.rule[depth]->GetPostalCodeMatcher();
209bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com      if (prefix_ptr != NULL) {
210bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com        if (!RE2::PartialMatch(address_.postal_code, *prefix_ptr->ptr)) {
211bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com          ReportProblem(POSTAL_CODE, MISMATCHING_VALUE);
212bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com        }
213bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com        return;
214bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com      }
215bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com    }
216bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  }
217bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com}
218bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com
219bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.comvoid ValidationTask::CheckUsesPoBox(
2209693f6426f3500db74dcfc766a130a747a571e5eroubert@google.com    const Supplier::RuleHierarchy& hierarchy) const {
22117471f7b69a94f92480650b06721e698204be3c0roubert@google.com  assert(hierarchy.rule[0] != NULL);
22217471f7b69a94f92480650b06721e698204be3c0roubert@google.com  const Rule& country_rule = *hierarchy.rule[0];
223bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com
224bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  if (allow_postal_ ||
225bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com      !ShouldReport(STREET_ADDRESS, USES_P_O_BOX) ||
226bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com      address_.IsFieldEmpty(STREET_ADDRESS)) {
227bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com    return;
228bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  }
229bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com
230bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  std::vector<const RE2ptr*> matchers =
231bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com      PostBoxMatchers::GetMatchers(country_rule);
232bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  for (std::vector<std::string>::const_iterator
233bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com       line = address_.address_line.begin();
234bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com       line != address_.address_line.end(); ++line) {
235bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com    for (std::vector<const RE2ptr*>::const_iterator
236bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com         matcher = matchers.begin();
237bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com         matcher != matchers.end(); ++matcher) {
238bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com      if (RE2::PartialMatch(*line, *(*matcher)->ptr)) {
239bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com        ReportProblem(STREET_ADDRESS, USES_P_O_BOX);
240bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com        return;
241bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com      }
242bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com    }
243bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  }
244bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com}
245bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com
246bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.comvoid ValidationTask::ReportProblem(AddressField field,
247bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com                                   AddressProblem problem) const {
248bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  problems_->insert(std::make_pair(field, problem));
249bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com}
250bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com
251bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.comvoid ValidationTask::ReportProblemMaybe(AddressField field,
252bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com                                        AddressProblem problem) const {
253bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  if (ShouldReport(field, problem)) {
254bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com    ReportProblem(field, problem);
255bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  }
256bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com}
257bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com
258bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.combool ValidationTask::ShouldReport(AddressField field,
259bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com                                  AddressProblem problem) const {
260bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com  return filter_ == NULL || filter_->empty() ||
261000aa6dbb70273ccefa77a5d4cd1a400939a2666roubert@google.com         std::find(filter_->begin(),
262000aa6dbb70273ccefa77a5d4cd1a400939a2666roubert@google.com                   filter_->end(),
263bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com                   FieldProblemMap::value_type(field, problem)) !=
264000aa6dbb70273ccefa77a5d4cd1a400939a2666roubert@google.com             filter_->end();
265bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com}
266bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com
267bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com}  // namespace addressinput
268bb96489d0f6066c96a5388a2a91d30ca6bc87ba8roubert@google.com}  // namespace i18n
269