001// --------------------------------------------------------------------------------
002// Copyright 2002-2025 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.PostalAddressLineTransfer;
023import com.echothree.model.control.geo.common.GeoCodeAliasTypes;
024import com.echothree.model.control.geo.common.GeoOptions;
025import java.util.ArrayList;
026import java.util.List;
027import java.util.Set;
028
029public class ContactPostalAddressUtils {
030    
031    private ContactPostalAddressUtils() {
032        super();
033    }
034    
035    private static class ContactPostalAddressUtilsHolder {
036        static ContactPostalAddressUtils instance = new ContactPostalAddressUtils();
037    }
038    
039    public static ContactPostalAddressUtils getInstance() {
040        return ContactPostalAddressUtilsHolder.instance;
041    }
042    
043    public Set<String> addOptions(Set<String> options) {
044        options.add(ContactOptions.PostalAddressFormatIncludeLines);
045        options.add(ContactOptions.PostalAddressLineIncludeElements);
046        options.add(GeoOptions.CountryIncludeAliases);
047        options.add(GeoOptions.StateIncludeAliases);
048        
049        return options;
050    }
051    
052    private String getCountryAlias(final String geoCodeAliasTypeName, final ContactPostalAddressTransfer contactPostalAddress) {
053        String addition;
054        var country = contactPostalAddress.getCountryGeoCode();
055        
056        if(country == null) {
057            throw new IllegalArgumentException("CountryGeoCode is not available to get " + geoCodeAliasTypeName + " Alias on ContactPostalAddress TO");
058        } else {
059            var geoCodeAliases = country.getGeoCodeAliases();
060
061            if(geoCodeAliases == null) {
062                throw new IllegalArgumentException("CountryIncludeAliases is a required Option to format ContactPostalAddress TO");
063            } else {
064                var geoCodeAlias = geoCodeAliases.getMap().get(geoCodeAliasTypeName);
065
066                if(geoCodeAlias == null) {
067                    throw new IllegalArgumentException(geoCodeAliasTypeName + " Alias is not available on ContactPostalAddress TO");
068                } else {
069                    addition = geoCodeAlias.getAlias();
070                }
071            }
072        }
073        
074        return addition;
075    }
076    
077    private String getLineElementAddition(final ContactPostalAddressTransfer contactPostalAddress, final String postalAddressElementTypeName) {
078        String addition = null;
079        
080        if(postalAddressElementTypeName.equals(PostalAddressElementTypes.PERSONAL_TITLE.name())) {
081            var personalTitle = contactPostalAddress.getPersonalTitle();
082            
083            if(personalTitle != null) {
084                addition = personalTitle.getDescription();
085            }
086        } else if(postalAddressElementTypeName.equals(PostalAddressElementTypes.FIRST_NAME.name())) {
087            addition = contactPostalAddress.getFirstName();
088        } else if(postalAddressElementTypeName.equals(PostalAddressElementTypes.MIDDLE_NAME.name())) {
089            addition = contactPostalAddress.getMiddleName();
090        } else if(postalAddressElementTypeName.equals(PostalAddressElementTypes.LAST_NAME.name())) {
091            addition = contactPostalAddress.getLastName();
092        } else if(postalAddressElementTypeName.equals(PostalAddressElementTypes.NAME_SUFFIX.name())) {
093            var nameSuffix = contactPostalAddress.getNameSuffix();
094            
095            if(nameSuffix != null) {
096                addition = nameSuffix.getDescription();
097            }
098        } else if(postalAddressElementTypeName.equals(PostalAddressElementTypes.COMPANY_NAME.name())) {
099            addition = contactPostalAddress.getCompanyName();
100        } else if(postalAddressElementTypeName.equals(PostalAddressElementTypes.ATTENTION.name())) {
101            addition = contactPostalAddress.getAttention();
102        } else if(postalAddressElementTypeName.equals(PostalAddressElementTypes.ADDRESS_1.name())) {
103            addition = contactPostalAddress.getAddress1();
104        } else if(postalAddressElementTypeName.equals(PostalAddressElementTypes.ADDRESS_2.name())) {
105            addition = contactPostalAddress.getAddress2();
106        } else if(postalAddressElementTypeName.equals(PostalAddressElementTypes.ADDRESS_3.name())) {
107            addition = contactPostalAddress.getAddress3();
108        } else if(postalAddressElementTypeName.equals(PostalAddressElementTypes.CITY.name())) {
109            var city = contactPostalAddress.getCityGeoCode();
110            
111            addition = city == null? contactPostalAddress.getCity(): city.getDescription();
112        } else if(postalAddressElementTypeName.equals(PostalAddressElementTypes.COUNTY.name())) {
113            var county = contactPostalAddress.getCountyGeoCode();
114            
115            if(county != null) {
116                addition = county.getDescription();
117            }
118        } else if(postalAddressElementTypeName.equals(PostalAddressElementTypes.STATE.name())) {
119            var state = contactPostalAddress.getStateGeoCode();
120            
121            addition = state == null? contactPostalAddress.getState(): state.getDescription();
122        } else if(postalAddressElementTypeName.equals(PostalAddressElementTypes.STATE_POSTAL_2_LETTER.name())) {
123            var state = contactPostalAddress.getStateGeoCode();
124            
125            if(state == null) {
126                throw new IllegalArgumentException("StateGeoCode is not available to get STATE_POSTAL_2_LETTER Alias on ContactPostalAddress TO");
127            } else {
128                var geoCodeAliases = state.getGeoCodeAliases();
129                
130                if(geoCodeAliases == null) {
131                    throw new IllegalArgumentException("StateIncludeAliases is a required Option to format ContactPostalAddress TO");
132                } else {
133                    var geoCodeAlias = geoCodeAliases.getMap().get(GeoCodeAliasTypes.POSTAL_2_LETTER.name());
134                    
135                    if(geoCodeAlias == null) {
136                        throw new IllegalArgumentException("STATE_POSTAL_2_LETTER Alias is not available on ContactPostalAddress TO");
137                    } else {
138                        addition = geoCodeAlias.getAlias();
139                    }
140                }
141            }
142        } else if(postalAddressElementTypeName.equals(PostalAddressElementTypes.POSTAL_CODE.name())) {
143            var postalCode = contactPostalAddress.getPostalCodeGeoCode();
144            
145            addition = postalCode == null? contactPostalAddress.getPostalCode(): postalCode.getDescription();
146        } else if(postalAddressElementTypeName.equals(PostalAddressElementTypes.COUNTRY.name())) {
147            addition = contactPostalAddress.getCountryGeoCode().getDescription();
148        } else if(postalAddressElementTypeName.equals(PostalAddressElementTypes.COUNTRY_ISO_3_NUMBER.name())) {
149            addition = getCountryAlias(GeoCodeAliasTypes.ISO_3_NUMBER.name(), contactPostalAddress);
150        } else if(postalAddressElementTypeName.equals(PostalAddressElementTypes.COUNTRY_ISO_3_LETTER.name())) {
151            addition = getCountryAlias(GeoCodeAliasTypes.ISO_3_LETTER.name(), contactPostalAddress);
152        } else if(postalAddressElementTypeName.equals(PostalAddressElementTypes.COUNTRY_ISO_2_LETTER.name())) {
153            addition = getCountryAlias(GeoCodeAliasTypes.ISO_2_LETTER.name(), contactPostalAddress);
154        }
155        
156        return addition == null? "": addition;
157    }
158    
159    private StringBuilder formatContactPostalAddressLine(final ContactPostalAddressTransfer contactPostalAddress, final PostalAddressLineTransfer postalAddressLine) {
160        var postalAddressLineElements = postalAddressLine.getPostalAddressLineElements();
161        var lineAddition = new StringBuilder();
162        
163        postalAddressLineElements.getList().forEach((postalAddressLineElement) -> {
164            var lineElement = getLineElementAddition(contactPostalAddress, postalAddressLineElement.getPostalAddressElementType().getPostalAddressElementTypeName());
165            var lineElementHasLength = lineElement.length() != 0;
166            boolean alwaysIncludePrefix = postalAddressLineElement.getAlwaysIncludePrefix();
167            boolean alwaysIncludeSuffix = postalAddressLineElement.getAlwaysIncludeSuffix();
168            var addedToLine = false;
169            if (lineElementHasLength || alwaysIncludePrefix || alwaysIncludeSuffix) {
170                var prefix = postalAddressLineElement.getPrefix();
171                var suffix = postalAddressLineElement.getSuffix();
172                if(prefix != null && (lineElementHasLength || alwaysIncludePrefix)) {
173                    lineAddition.append(prefix);
174                    addedToLine = true;
175                }
176                if(lineElement.length() > 0) {
177                    lineAddition.append(lineElement);
178                    addedToLine = true;
179                }
180                if(suffix != null && (lineElementHasLength || alwaysIncludeSuffix)) {
181                    lineAddition.append(suffix);
182                    addedToLine = true;
183                }
184                if (addedToLine) {
185                    lineAddition.append(' ');
186                }
187            }
188        });
189        
190        return lineAddition;
191    }
192    
193    public List<String> formatContactPostalAddress(final ContactPostalAddressTransfer contactPostalAddress) {
194        var postalAddressFormat = contactPostalAddress.getCountryGeoCode().getPostalAddressFormat();
195        var postalAddressLines = postalAddressFormat.getPostalAddressLines();
196        List<String> result;
197        
198        if(postalAddressLines == null) {
199            throw new IllegalArgumentException("PostalAddressFormatIncludeLines is a required Option to format ContactPostalAddress TO");
200        } else {
201            result = new ArrayList<>(postalAddressLines.getSize());
202            
203            for(var postalAddressLine: postalAddressLines.getList()) {
204                var resultLine = new StringBuilder();
205                var postalAddressLineElements = postalAddressLine.getPostalAddressLineElements();
206                
207                if(postalAddressLineElements == null) {
208                    throw new IllegalArgumentException("PostalAddressLineIncludeElements is a required Option to format ContactPostalAddress TO");
209                } else {
210                    resultLine.append(formatContactPostalAddressLine(contactPostalAddress, postalAddressLine));
211
212                    var resultLineHasLength = resultLine.length() != 0;
213                    if(resultLineHasLength || !postalAddressLine.getCollapseIfEmpty()) {
214                        boolean alwaysIncludePrefix = postalAddressLine.getAlwaysIncludePrefix();
215                        boolean alwaysIncludeSuffix = postalAddressLine.getAlwaysIncludeSuffix();
216
217                        if(resultLineHasLength || alwaysIncludePrefix || alwaysIncludeSuffix) {
218                            var prefix = postalAddressLine.getPrefix();
219                            var suffix = postalAddressLine.getSuffix();
220
221                            if(prefix != null && (resultLineHasLength || alwaysIncludePrefix)) {
222                                resultLine = new StringBuilder(prefix).append(' ').append(resultLine);
223                            }
224
225                            if(suffix != null && (resultLineHasLength || alwaysIncludeSuffix)) {
226                                resultLine.append(suffix);
227                            }
228                        }
229
230                        result.add(resultLine.toString().trim());
231                    }
232                }
233            }
234        }
235        
236        return result;
237    }
238    
239}