001// --------------------------------------------------------------------------------
002// Copyright 2002-2024 Echo Three, LLC
003//
004// Licensed under the Apache License, Version 2.0 (the "License");
005// you may not use this file except in compliance with the License.
006// You may obtain a copy of the License at
007//
008//     http://www.apache.org/licenses/LICENSE-2.0
009//
010// Unless required by applicable law or agreed to in writing, software
011// distributed under the License is distributed on an "AS IS" BASIS,
012// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013// See the License for the specific language governing permissions and
014// limitations under the License.
015// --------------------------------------------------------------------------------
016
017package com.echothree.util.common.string;
018
019import com.echothree.model.control.contact.common.ContactOptions;
020import com.echothree.model.control.contact.common.PostalAddressElementTypes;
021import com.echothree.model.control.contact.common.transfer.ContactPostalAddressTransfer;
022import com.echothree.model.control.contact.common.transfer.PostalAddressFormatTransfer;
023import com.echothree.model.control.contact.common.transfer.PostalAddressLineElementTransfer;
024import com.echothree.model.control.contact.common.transfer.PostalAddressLineTransfer;
025import com.echothree.model.control.geo.common.GeoConstants;
026import com.echothree.model.control.geo.common.GeoOptions;
027import com.echothree.model.control.geo.common.transfer.CityTransfer;
028import com.echothree.model.control.geo.common.transfer.CountryTransfer;
029import com.echothree.model.control.geo.common.transfer.CountyTransfer;
030import com.echothree.model.control.geo.common.transfer.GeoCodeAliasTransfer;
031import com.echothree.model.control.geo.common.transfer.PostalCodeTransfer;
032import com.echothree.model.control.geo.common.transfer.StateTransfer;
033import com.echothree.model.control.party.common.transfer.NameSuffixTransfer;
034import com.echothree.model.control.party.common.transfer.PersonalTitleTransfer;
035import com.echothree.util.common.transfer.ListWrapper;
036import com.echothree.util.common.transfer.MapWrapper;
037import java.util.ArrayList;
038import java.util.List;
039import java.util.Set;
040
041public class ContactPostalAddressUtils {
042    
043    private ContactPostalAddressUtils() {
044        super();
045    }
046    
047    private static class ContactPostalAddressUtilsHolder {
048        static ContactPostalAddressUtils instance = new ContactPostalAddressUtils();
049    }
050    
051    public static ContactPostalAddressUtils getInstance() {
052        return ContactPostalAddressUtilsHolder.instance;
053    }
054    
055    public Set<String> addOptions(Set<String> options) {
056        options.add(ContactOptions.PostalAddressFormatIncludeLines);
057        options.add(ContactOptions.PostalAddressLineIncludeElements);
058        options.add(GeoOptions.CountryIncludeAliases);
059        options.add(GeoOptions.StateIncludeAliases);
060        
061        return options;
062    }
063    
064    private String getCountryAlias(final String geoCodeAliasTypeName, final ContactPostalAddressTransfer contactPostalAddress) {
065        String addition;
066        CountryTransfer country = contactPostalAddress.getCountryGeoCode();
067        
068        if(country == null) {
069            throw new IllegalArgumentException("CountryGeoCode is not available to get " + geoCodeAliasTypeName + " Alias on ContactPostalAddress TO");
070        } else {
071            MapWrapper<GeoCodeAliasTransfer> geoCodeAliases = country.getGeoCodeAliases();
072
073            if(geoCodeAliases == null) {
074                throw new IllegalArgumentException("CountryIncludeAliases is a required Option to format ContactPostalAddress TO");
075            } else {
076                GeoCodeAliasTransfer geoCodeAlias = geoCodeAliases.getMap().get(geoCodeAliasTypeName);
077
078                if(geoCodeAlias == null) {
079                    throw new IllegalArgumentException(geoCodeAliasTypeName + " Alias is not available on ContactPostalAddress TO");
080                } else {
081                    addition = geoCodeAlias.getAlias();
082                }
083            }
084        }
085        
086        return addition;
087    }
088    
089    private String getLineElementAddition(final ContactPostalAddressTransfer contactPostalAddress, final String postalAddressElementTypeName) {
090        String addition = null;
091        
092        if(postalAddressElementTypeName.equals(PostalAddressElementTypes.PERSONAL_TITLE.name())) {
093            PersonalTitleTransfer personalTitle = contactPostalAddress.getPersonalTitle();
094            
095            if(personalTitle != null) {
096                addition = personalTitle.getDescription();
097            }
098        } else if(postalAddressElementTypeName.equals(PostalAddressElementTypes.FIRST_NAME.name())) {
099            addition = contactPostalAddress.getFirstName();
100        } else if(postalAddressElementTypeName.equals(PostalAddressElementTypes.MIDDLE_NAME.name())) {
101            addition = contactPostalAddress.getMiddleName();
102        } else if(postalAddressElementTypeName.equals(PostalAddressElementTypes.LAST_NAME.name())) {
103            addition = contactPostalAddress.getLastName();
104        } else if(postalAddressElementTypeName.equals(PostalAddressElementTypes.NAME_SUFFIX.name())) {
105            NameSuffixTransfer nameSuffix = contactPostalAddress.getNameSuffix();
106            
107            if(nameSuffix != null) {
108                addition = nameSuffix.getDescription();
109            }
110        } else if(postalAddressElementTypeName.equals(PostalAddressElementTypes.COMPANY_NAME.name())) {
111            addition = contactPostalAddress.getCompanyName();
112        } else if(postalAddressElementTypeName.equals(PostalAddressElementTypes.ATTENTION.name())) {
113            addition = contactPostalAddress.getAttention();
114        } else if(postalAddressElementTypeName.equals(PostalAddressElementTypes.ADDRESS_1.name())) {
115            addition = contactPostalAddress.getAddress1();
116        } else if(postalAddressElementTypeName.equals(PostalAddressElementTypes.ADDRESS_2.name())) {
117            addition = contactPostalAddress.getAddress2();
118        } else if(postalAddressElementTypeName.equals(PostalAddressElementTypes.ADDRESS_3.name())) {
119            addition = contactPostalAddress.getAddress3();
120        } else if(postalAddressElementTypeName.equals(PostalAddressElementTypes.CITY.name())) {
121            CityTransfer city = contactPostalAddress.getCityGeoCode();
122            
123            addition = city == null? contactPostalAddress.getCity(): city.getDescription();
124        } else if(postalAddressElementTypeName.equals(PostalAddressElementTypes.COUNTY.name())) {
125            CountyTransfer county = contactPostalAddress.getCountyGeoCode();
126            
127            if(county != null) {
128                addition = county.getDescription();
129            }
130        } else if(postalAddressElementTypeName.equals(PostalAddressElementTypes.STATE.name())) {
131            StateTransfer state = contactPostalAddress.getStateGeoCode();
132            
133            addition = state == null? contactPostalAddress.getState(): state.getDescription();
134        } else if(postalAddressElementTypeName.equals(PostalAddressElementTypes.STATE_POSTAL_2_LETTER.name())) {
135            StateTransfer state = contactPostalAddress.getStateGeoCode();
136            
137            if(state == null) {
138                throw new IllegalArgumentException("StateGeoCode is not available to get STATE_POSTAL_2_LETTER Alias on ContactPostalAddress TO");
139            } else {
140                MapWrapper<GeoCodeAliasTransfer> geoCodeAliases = state.getGeoCodeAliases();
141                
142                if(geoCodeAliases == null) {
143                    throw new IllegalArgumentException("StateIncludeAliases is a required Option to format ContactPostalAddress TO");
144                } else {
145                    GeoCodeAliasTransfer geoCodeAlias = geoCodeAliases.getMap().get(GeoConstants.GeoCodeAliasType_POSTAL_2_LETTER);
146                    
147                    if(geoCodeAlias == null) {
148                        throw new IllegalArgumentException("STATE_POSTAL_2_LETTER Alias is not available on ContactPostalAddress TO");
149                    } else {
150                        addition = geoCodeAlias.getAlias();
151                    }
152                }
153            }
154        } else if(postalAddressElementTypeName.equals(PostalAddressElementTypes.POSTAL_CODE.name())) {
155            PostalCodeTransfer postalCode = contactPostalAddress.getPostalCodeGeoCode();
156            
157            addition = postalCode == null? contactPostalAddress.getPostalCode(): postalCode.getDescription();
158        } else if(postalAddressElementTypeName.equals(PostalAddressElementTypes.COUNTRY.name())) {
159            addition = contactPostalAddress.getCountryGeoCode().getDescription();
160        } else if(postalAddressElementTypeName.equals(PostalAddressElementTypes.COUNTRY_ISO_3_NUMBER.name())) {
161            addition = getCountryAlias(GeoConstants.GeoCodeAliasType_ISO_3_NUMBER, contactPostalAddress);
162        } else if(postalAddressElementTypeName.equals(PostalAddressElementTypes.COUNTRY_ISO_3_LETTER.name())) {
163            addition = getCountryAlias(GeoConstants.GeoCodeAliasType_ISO_3_LETTER, contactPostalAddress);
164        } else if(postalAddressElementTypeName.equals(PostalAddressElementTypes.COUNTRY_ISO_2_LETTER.name())) {
165            addition = getCountryAlias(GeoConstants.GeoCodeAliasType_ISO_2_LETTER, contactPostalAddress);
166        }
167        
168        return addition == null? "": addition;
169    }
170    
171    private StringBuilder formatContactPostalAddressLine(final ContactPostalAddressTransfer contactPostalAddress, final PostalAddressLineTransfer postalAddressLine) {
172        ListWrapper<PostalAddressLineElementTransfer> postalAddressLineElements = postalAddressLine.getPostalAddressLineElements();
173        StringBuilder lineAddition = new StringBuilder();
174        
175        postalAddressLineElements.getList().stream().forEach((postalAddressLineElement) -> {
176            String lineElement = getLineElementAddition(contactPostalAddress, postalAddressLineElement.getPostalAddressElementType().getPostalAddressElementTypeName());
177            boolean lineElementHasLength = lineElement.length() != 0;
178            boolean alwaysIncludePrefix = postalAddressLineElement.getAlwaysIncludePrefix();
179            boolean alwaysIncludeSuffix = postalAddressLineElement.getAlwaysIncludeSuffix();
180            boolean addedToLine = false;
181            if (lineElementHasLength || alwaysIncludePrefix || alwaysIncludeSuffix) {
182                String prefix = postalAddressLineElement.getPrefix();
183                String suffix = postalAddressLineElement.getSuffix();
184                if(prefix != null && (lineElementHasLength || alwaysIncludePrefix)) {
185                    lineAddition.append(prefix);
186                    addedToLine = true;
187                }
188                if(lineElement.length() > 0) {
189                    lineAddition.append(lineElement);
190                    addedToLine = true;
191                }
192                if(suffix != null && (lineElementHasLength || alwaysIncludeSuffix)) {
193                    lineAddition.append(suffix);
194                    addedToLine = true;
195                }
196                if (addedToLine) {
197                    lineAddition.append(' ');
198                }
199            }
200        });
201        
202        return lineAddition;
203    }
204    
205    public List<String> formatContactPostalAddress(final ContactPostalAddressTransfer contactPostalAddress) {
206        PostalAddressFormatTransfer postalAddressFormat = contactPostalAddress.getCountryGeoCode().getPostalAddressFormat();
207        ListWrapper<PostalAddressLineTransfer> postalAddressLines = postalAddressFormat.getPostalAddressLines();
208        List<String> result = null;
209        
210        if(postalAddressLines == null) {
211            throw new IllegalArgumentException("PostalAddressFormatIncludeLines is a required Option to format ContactPostalAddress TO");
212        } else {
213            result = new ArrayList<>(postalAddressLines.getSize());
214            
215            for(PostalAddressLineTransfer postalAddressLine: postalAddressLines.getList()) {
216                StringBuilder resultLine = new StringBuilder();
217                ListWrapper<PostalAddressLineElementTransfer> postalAddressLineElements = postalAddressLine.getPostalAddressLineElements();
218                
219                if(postalAddressLineElements == null) {
220                    throw new IllegalArgumentException("PostalAddressLineIncludeElements is a required Option to format ContactPostalAddress TO");
221                } else {
222                    resultLine.append(formatContactPostalAddressLine(contactPostalAddress, postalAddressLine));
223                    
224                    boolean resultLineHasLength = resultLine.length() != 0;
225                    if(resultLineHasLength || !postalAddressLine.getCollapseIfEmpty()) {
226                        boolean alwaysIncludePrefix = postalAddressLine.getAlwaysIncludePrefix();
227                        boolean alwaysIncludeSuffix = postalAddressLine.getAlwaysIncludeSuffix();
228
229                        if(resultLineHasLength || alwaysIncludePrefix || alwaysIncludeSuffix) {
230                            String prefix = postalAddressLine.getPrefix();
231                            String suffix = postalAddressLine.getSuffix();
232
233                            if(prefix != null && (resultLineHasLength || alwaysIncludePrefix)) {
234                                resultLine = new StringBuilder(prefix).append(' ').append(resultLine);
235                            }
236
237                            if(suffix != null && (resultLineHasLength || alwaysIncludeSuffix)) {
238                                resultLine.append(suffix);
239                            }
240                        }
241
242                        result.add(resultLine.toString().trim());
243                    }
244                }
245            }
246        }
247        
248        return result;
249    }
250    
251}