001/* ***** BEGIN LICENSE BLOCK ***** 002 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 003 * 004 * The contents of this file are subject to the Mozilla Public License Version 005 * 1.1 (the "License"); you may not use this file except in compliance with 006 * the License. You may obtain a copy of the License at 007 * http://www.mozilla.org/MPL/ 008 * 009 * Software distributed under the License is distributed on an "AS IS" basis, 010 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 011 * for the specific language governing rights and limitations under the 012 * License. 013 * 014 * The Original Code is part of dcm4che, an implementation of DICOM(TM) in 015 * Java(TM), hosted at https://github.com/gunterze/dcm4che. 016 * 017 * The Initial Developer of the Original Code is 018 * Agfa Healthcare. 019 * Portions created by the Initial Developer are Copyright (C) 2011 020 * the Initial Developer. All Rights Reserved. 021 * 022 * Contributor(s): 023 * See @authors listed below 024 * 025 * Alternatively, the contents of this file may be used under the terms of 026 * either the GNU General Public License Version 2 or later (the "GPL"), or 027 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 028 * in which case the provisions of the GPL or the LGPL are applicable instead 029 * of those above. If you wish to allow use of your version of this file only 030 * under the terms of either the GPL or the LGPL, and not to allow others to 031 * use your version of this file under the terms of the MPL, indicate your 032 * decision by deleting the provisions above and replace them with the notice 033 * and other provisions required by the GPL or the LGPL. If you do not delete 034 * the provisions above, a recipient may use your version of this file under 035 * the terms of any one of the MPL, the GPL or the LGPL. 036 * 037 * ***** END LICENSE BLOCK ***** */ 038 039package org.dcm4che3.data; 040 041import java.util.Arrays; 042import java.util.StringTokenizer; 043 044import org.slf4j.Logger; 045import org.slf4j.LoggerFactory; 046 047/** 048 * @author Gunter Zeilinger <gunterze@gmail.com> 049 * @author Michael Backhaus <michael.backhaus@agfa.com> 050 */ 051public class PersonName { 052 053 private static final Logger LOG = LoggerFactory.getLogger(PersonName.class); 054 055 public static enum Component { 056 FamilyName, GivenName, MiddleName, NamePrefix, NameSuffix 057 }; 058 059 public static enum Group { 060 Alphabetic, Ideographic, Phonetic 061 }; 062 063 private final String[] fields = new String[15]; 064 065 public PersonName() {} 066 067 public PersonName(String s) { 068 this(s, false); 069 } 070 071 public PersonName(String s, boolean lenient) { 072 if (s != null) 073 parse(s, lenient); 074 } 075 076 private void parse(String s, boolean lenient) { 077 int gindex = 0; 078 int cindex = 0; 079 StringTokenizer stk = new StringTokenizer(s, "^=", true); 080 while (stk.hasMoreTokens()) { 081 String tk = stk.nextToken(); 082 switch (tk.charAt(0)) { 083 case '=': 084 if (++gindex > 2) 085 if (lenient) { 086 LOG.info( 087 "illegal PN: {} - truncate illegal component group(s)", s); 088 return; 089 } else 090 throw new IllegalArgumentException(s); 091 cindex = 0; 092 break; 093 case '^': 094 if (++cindex > 4) 095 if (lenient) { 096 LOG.info( 097 "illegal PN: {} - ignore illegal component(s)", s); 098 break; 099 } else 100 throw new IllegalArgumentException(s); 101 break; 102 default: 103 if (cindex <= 4) 104 set(gindex, cindex, tk); 105 } 106 } 107 } 108 109 public String toString() { 110 int totLen = 0; 111 Group lastGroup = Group.Alphabetic; 112 for (Group g : Group.values()) { 113 Component lastCompOfGroup = Component.FamilyName; 114 for (Component c : Component.values()) { 115 String s = get(g, c); 116 if (s != null) { 117 totLen += s.length(); 118 lastGroup = g; 119 lastCompOfGroup = c; 120 } 121 } 122 totLen += lastCompOfGroup.ordinal(); 123 } 124 totLen += lastGroup.ordinal(); 125 char[] ch = new char[totLen]; 126 int wpos = 0; 127 for (Group g : Group.values()) { 128 Component lastCompOfGroup = Component.FamilyName; 129 for (Component c : Component.values()) { 130 String s = get(g, c); 131 if (s != null) { 132 int d = c.ordinal() - lastCompOfGroup.ordinal(); 133 while (d-- > 0) 134 ch[wpos++] = '^'; 135 d = s.length(); 136 s.getChars(0, d, ch, wpos); 137 wpos += d; 138 lastCompOfGroup = c; 139 } 140 } 141 if (g == lastGroup) 142 break; 143 ch[wpos++] = '='; 144 } 145 return new String(ch); 146 } 147 148 public String toString(Group g, boolean trim) { 149 int totLen = 0; 150 Component lastCompOfGroup = Component.FamilyName; 151 for (Component c : Component.values()) { 152 String s = get(g, c); 153 if (s != null) { 154 totLen += s.length(); 155 lastCompOfGroup = c; 156 } 157 } 158 totLen += trim ? lastCompOfGroup.ordinal() : 4; 159 char[] ch = new char[totLen]; 160 int wpos = 0; 161 for (Component c : Component.values()) { 162 String s = get(g, c); 163 if (s != null) { 164 int d = s.length(); 165 s.getChars(0, d, ch, wpos); 166 wpos += d; 167 } 168 if (trim && c == lastCompOfGroup) 169 break; 170 if (wpos < ch.length) 171 ch[wpos++] = '^'; 172 } 173 return new String(ch); 174 } 175 176 public String get(Component c) { 177 return get(Group.Alphabetic, c); 178 } 179 180 public String get(Group g, Component c) { 181 return fields[g.ordinal() * 5 + c.ordinal()]; 182 } 183 184 public void set(Component c, String s) { 185 set(Group.Alphabetic, c, s); 186 } 187 188 public void set(Group g, Component c, String s) { 189 set(g.ordinal(), c.ordinal(), s); 190 } 191 192 private void set(int gindex, int cindex, String s) { 193 fields[gindex * 5 + cindex] = trim(s); 194 } 195 196 public boolean isEmpty() { 197 for (Group g : Group.values()) 198 if (contains(g)) 199 return false; 200 return true; 201 } 202 203 public boolean contains(Group g) { 204 for (Component c : Component.values()) 205 if (contains(g, c)) 206 return true; 207 return false; 208 } 209 210 public boolean contains(Group g, Component c) { 211 return get(g, c) != null; 212 } 213 214 public boolean contains(Component c) { 215 return contains(Group.Alphabetic, c); 216 } 217 218 private static String trim(String s) { 219 return s == null || (s = s.trim()).isEmpty() ? null : s; 220 } 221 222 @Override 223 public int hashCode() { 224 return Arrays.hashCode(fields); 225 } 226 227 @Override 228 public boolean equals(Object obj) { 229 if (obj == this) 230 return true; 231 232 if (!(obj instanceof PersonName)) 233 return false; 234 235 PersonName other = (PersonName) obj; 236 return Arrays.equals(fields, other.fields); 237 } 238 239}