public class

PostalSplitter

extends Object
/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License
 */
package com.android.providers.contacts;

import android.content.ContentValues;
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
import android.text.TextUtils;

import java.util.Locale;

/**
 * Split and join {@link StructuredPostal} fields.
 */
public class PostalSplitter {
    private static final String JAPANESE_LANGUAGE = Locale.JAPANESE.getLanguage().toLowerCase();

    private final Locale mLocale;

    public static class Postal {
        public String street;
        public String pobox;
        public String neighborhood;
        public String city;
        public String region;
        public String postcode;
        public String country;

        public void fromValues(ContentValues values) {
            street = values.getAsString(StructuredPostal.STREET);
            pobox = values.getAsString(StructuredPostal.POBOX);
            neighborhood = values.getAsString(StructuredPostal.NEIGHBORHOOD);
            city = values.getAsString(StructuredPostal.CITY);
            region = values.getAsString(StructuredPostal.REGION);
            postcode = values.getAsString(StructuredPostal.POSTCODE);
            country = values.getAsString(StructuredPostal.COUNTRY);
        }

        public void toValues(ContentValues values) {
            values.put(StructuredPostal.STREET, street);
            values.put(StructuredPostal.POBOX, pobox);
            values.put(StructuredPostal.NEIGHBORHOOD, neighborhood);
            values.put(StructuredPostal.CITY, city);
            values.put(StructuredPostal.REGION, region);
            values.put(StructuredPostal.POSTCODE, postcode);
            values.put(StructuredPostal.COUNTRY, country);
        }
    }

    public PostalSplitter(Locale locale) {
        mLocale = locale;
    }

    /**
     * Parses {@link StructuredPostal#FORMATTED_ADDRESS} and returns parsed
     * components in the {@link Postal} object.
     */
    public void split(Postal postal, String formattedAddress) {
        if (!TextUtils.isEmpty(formattedAddress)) {
            postal.street = formattedAddress;
        }
    }

    private static final String NEWLINE = "\n";
    private static final String COMMA = ",";
    private static final String SPACE = " ";

    /**
     * Flattens the given {@link Postal} into a single field, usually for
     * storage in {@link StructuredPostal#FORMATTED_ADDRESS}.
     */
    public String join(Postal postal) {
        final String[] values = new String[] {
                postal.street, postal.pobox, postal.neighborhood, postal.city,
                postal.region, postal.postcode, postal.country
        };
        // TODO: split off to handle various locales
        if (mLocale != null &&
                JAPANESE_LANGUAGE.equals(mLocale.getLanguage()) &&
                !arePrintableAsciiOnly(values)) {
            return joinJaJp(postal);
        } else {
            return joinEnUs(postal);
        }
    }

    private String joinJaJp(final Postal postal) {
        final boolean hasStreet = !TextUtils.isEmpty(postal.street);
        final boolean hasPobox = !TextUtils.isEmpty(postal.pobox);
        final boolean hasNeighborhood = !TextUtils.isEmpty(postal.neighborhood);
        final boolean hasCity = !TextUtils.isEmpty(postal.city);
        final boolean hasRegion = !TextUtils.isEmpty(postal.region);
        final boolean hasPostcode = !TextUtils.isEmpty(postal.postcode);
        final boolean hasCountry = !TextUtils.isEmpty(postal.country);

        // First block: [country][ ][postcode]
        // Second block: [region][ ][city][ ][neighborhood]
        // Third block: [street][ ][pobox]

        final StringBuilder builder = new StringBuilder();

        final boolean hasFirstBlock = hasCountry || hasPostcode;
        final boolean hasSecondBlock = hasRegion || hasCity || hasNeighborhood;
        final boolean hasThirdBlock = hasStreet || hasPobox;

        if (hasFirstBlock) {
            if (hasCountry) {
                builder.append(postal.country);
            }
            if (hasPostcode) {
                if (hasCountry) builder.append(SPACE);
                builder.append(postal.postcode);
            }
        }

        if (hasSecondBlock) {
            if (hasFirstBlock) {
                builder.append(NEWLINE);
            }
            if (hasRegion) {
                builder.append(postal.region);
            }
            if (hasCity) {
                if (hasRegion) builder.append(SPACE);
                builder.append(postal.city);
            }
            if (hasNeighborhood) {
                if (hasRegion || hasCity) builder.append(SPACE);
                builder.append(postal.neighborhood);
            }
        }

        if (hasThirdBlock) {
            if (hasFirstBlock || hasSecondBlock) {
                builder.append(NEWLINE);
            }
            if (hasStreet) {
                builder.append(postal.street);
            }
            if (hasPobox) {
                if (hasStreet) builder.append(SPACE);
                builder.append(postal.pobox);
            }
        }

        if (builder.length() > 0) {
            return builder.toString();
        } else {
            return null;
        }
    }

    private String joinEnUs(final Postal postal) {
        final boolean hasStreet = !TextUtils.isEmpty(postal.street);
        final boolean hasPobox = !TextUtils.isEmpty(postal.pobox);
        final boolean hasNeighborhood = !TextUtils.isEmpty(postal.neighborhood);
        final boolean hasCity = !TextUtils.isEmpty(postal.city);
        final boolean hasRegion = !TextUtils.isEmpty(postal.region);
        final boolean hasPostcode = !TextUtils.isEmpty(postal.postcode);
        final boolean hasCountry = !TextUtils.isEmpty(postal.country);

        // First block: [street][\n][pobox][\n][neighborhood]
        // Second block: [city][, ][region][ ][postcode]
        // Third block: [country]

        final StringBuilder builder = new StringBuilder();

        final boolean hasFirstBlock = hasStreet || hasPobox || hasNeighborhood;
        final boolean hasSecondBlock = hasCity || hasRegion || hasPostcode;
        final boolean hasThirdBlock = hasCountry;

        if (hasFirstBlock) {
            if (hasStreet) {
                builder.append(postal.street);
            }
            if (hasPobox) {
                if (hasStreet) builder.append(NEWLINE);
                builder.append(postal.pobox);
            }
            if (hasNeighborhood) {
                if (hasStreet || hasPobox) builder.append(NEWLINE);
                builder.append(postal.neighborhood);
            }
        }

        if (hasSecondBlock) {
            if (hasFirstBlock) {
                builder.append(NEWLINE);
            }
            if (hasCity) {
                builder.append(postal.city);
            }
            if (hasRegion) {
                if (hasCity) builder.append(COMMA + SPACE);
                builder.append(postal.region);
            }
            if (hasPostcode) {
                if (hasCity || hasRegion) builder.append(SPACE);
                builder.append(postal.postcode);
            }
        }

        if (hasThirdBlock) {
            if (hasFirstBlock || hasSecondBlock) {
                builder.append(NEWLINE);
            }
            if (hasCountry) {
                builder.append(postal.country);
            }
        }

        if (builder.length() > 0) {
            return builder.toString();
        } else {
            return null;
        }
    }

    private static boolean arePrintableAsciiOnly(final String[] values) {
        if (values == null) {
            return true;
        }
        for (final String value : values) {
            if (TextUtils.isEmpty(value)) {
                continue;
            }
            if (!TextUtils.isPrintableAsciiOnly(value)) {
                return false;
            }
        }
        return true;
    }
}