Fix FN when empty (with a configurable option) + some i18n
[jvcard.git] / src / be / nikiroo / jvcard / Contact.java
index 948fd8447965a87d06663db2b4513d6bea022d92..4b46eab8afa3dcc6aa840d8c89952d0c4ef8b3b5 100644 (file)
@@ -7,10 +7,11 @@ import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.UUID;
 
 import be.nikiroo.jvcard.parsers.Format;
 import be.nikiroo.jvcard.parsers.Parser;
-import be.nikiroo.jvcard.tui.StringUtils;
+import be.nikiroo.jvcard.resources.StringUtils;
 
 /**
  * A contact is the information that represent a contact person or organisation.
@@ -46,13 +47,9 @@ public class Contact extends BaseClass<Data> {
                for (Data data : getData(name)) {
                        if (first == null)
                                first = data;
-                       for (int index = 0; index < data.size(); index++) {
-                               TypeInfo type = data.get(index);
-                               if (type.getName().equals("TYPE")
-                                               && type.getValue().equals("pref")) {
-                                       return data;
-                               }
-                       }
+
+                       if (data.isPreferred())
+                               return data;
                }
 
                return first;
@@ -102,45 +99,89 @@ public class Contact extends BaseClass<Data> {
         */
        public String toString(Format format, int startingBKey) {
                updateBKeys(false);
-               return Parser.toString(this, format, startingBKey);
+
+               StringBuilder builder = new StringBuilder();
+               for (String line : Parser.toStrings(this, format, startingBKey)) {
+                       builder.append(line);
+                       builder.append("\r\n");
+               }
+
+               return builder.toString();
        }
 
        /**
         * Return a {@link String} representation of this contact formated
         * accordingly to the given format.
         * 
+        * <p>
         * The format is basically a list of field names separated by a pipe and
-        * optionally parametrised. The parameters allows you to:
+        * optionally parametrised with the 'at' (@) symbol. The parameters allows
+        * you to:
         * <ul>
         * <li>@x: show only a present/not present info</li>
         * <li>@n: limit the size to a fixed value 'n'</li>
         * <li>@+: expand the size of this field as much as possible</li>
         * </ul>
+        * </p>
+        * 
+        * <p>
+        * In case of lists or multiple-fields values, you can select a specific
+        * list or field with:
+        * <ul>
+        * <li>FIELD@(0): select the first value in a list</li>
+        * <li>FIELD@[1]: select the second field in a multiple-fields value</li>
+        * </ul>
+        * </p>
         * 
-        * Example: "N@10|FN@20|NICK@+|PHOTO@x"
+        * <p>
+        * You can also add a fixed text if it starts with a simple-quote (').
+        * </p>
+        * 
+        * <p>
+        * Example: "'Contact: |N@10|FN@20|NICK@+|PHOTO@x"
+        * </p>
         * 
         * @param format
         *            the format to use
+        * @param separator
+        *            the separator {@link String} to use between fields
         * 
         * @return the {@link String} representation
         */
-       public String toString(String format) {
-               return toString(format, "|", null, -1, true, false);
+       public String toString(String format, String separator) {
+               return toString(format, separator, null, -1, true, false);
        }
 
        /**
         * Return a {@link String} representation of this contact formated
         * accordingly to the given format.
         * 
+        * <p>
         * The format is basically a list of field names separated by a pipe and
         * optionally parametrised. The parameters allows you to:
         * <ul>
-        * <li>@x: (the 'x' is the letter 'x') show only a present/not present info</li>
+        * <li>@x: show only a present/not present info</li>
         * <li>@n: limit the size to a fixed value 'n'</li>
         * <li>@+: expand the size of this field as much as possible</li>
         * </ul>
+        * </p>
+        * 
+        * <p>
+        * In case of lists or multiple-fields values, you can select a specific
+        * list or field with:
+        * <ul>
+        * <li>FIELD@(0): select the first value in a list</li>
+        * <li>FIELD@[1]: select the second field in a multiple-fields value</li>
+        * </ul>
+        * </p>
+        * 
+        * <p>
+        * You can also add a fixed text if it starts with a simple-quote (').
+        * </p>
         * 
-        * Example: "N@10|FN@20|NICK@+|PHOTO@x"
+        * <p>
+        * Example: "'Contact: |N@10|FN@20|NICK@+|PHOTO@x"
+        * </p>
         * 
         * @param format
         *            the format to use
@@ -172,6 +213,7 @@ public class Contact extends BaseClass<Data> {
         * Return a {@link String} representation of this contact formated
         * accordingly to the given format, part by part.
         * 
+        * <p>
         * The format is basically a list of field names separated by a pipe and
         * optionally parametrised. The parameters allows you to:
         * <ul>
@@ -179,8 +221,24 @@ public class Contact extends BaseClass<Data> {
         * <li>@n: limit the size to a fixed value 'n'</li>
         * <li>@+: expand the size of this field as much as possible</li>
         * </ul>
+        * </p>
+        * 
+        * <p>
+        * In case of lists or multiple-fields values, you can select a specific
+        * list or field with:
+        * <ul>
+        * <li>FIELD@(0): select the first value in a list</li>
+        * <li>FIELD@[1]: select the second field in a multiple-fields value</li>
+        * </ul>
+        * </p>
+        * 
+        * <p>
+        * You can also add a fixed text if it starts with a simple-quote (').
+        * </p>
         * 
-        * Example: "N@10|FN@20|NICK@+|PHOTO@x"
+        * <p>
+        * Example: "'Contact: |N@10|FN@20|NICK@+|PHOTO@x"
+        * </p>
         * 
         * @param format
         *            the format to use
@@ -232,6 +290,7 @@ public class Contact extends BaseClass<Data> {
         * Return a {@link String} representation of this contact formated
         * accordingly to the given format, part by part.
         * 
+        * <p>
         * The format is basically a list of field names separated by a pipe and
         * optionally parametrised. The parameters allows you to:
         * <ul>
@@ -239,8 +298,24 @@ public class Contact extends BaseClass<Data> {
         * <li>@n: limit the size to a fixed value 'n'</li>
         * <li>@+: expand the size of this field as much as possible</li>
         * </ul>
+        * </p>
         * 
-        * Example: "N@10|FN@20|NICK@+|PHOTO@x"
+        * <p>
+        * In case of lists or multiple-fields values, you can select a specific
+        * list or field with:
+        * <ul>
+        * <li>FIELD@(0): select the first value in a list</li>
+        * <li>FIELD@[1]: select the second field in a multiple-fields value</li>
+        * </ul>
+        * </p>
+        * 
+        * <p>
+        * You can also add a fixed text if it starts with a simple-quote (').
+        * </p>
+        * 
+        * <p>
+        * Example: "'Contact: |N@10|FN@20|NICK@+|PHOTO@x"
+        * </p>
         * 
         * @param format
         *            the format to use
@@ -275,8 +350,11 @@ public class Contact extends BaseClass<Data> {
                        int size = -1;
                        boolean binary = false;
                        boolean expand = false;
+                       int fieldNum = -1;
+                       int valueNum = -1;
 
-                       if (field.contains("@")) {
+                       if (field.length() > 0 && field.charAt(0) != '\''
+                                       && field.contains("@")) {
                                String[] opts = field.split("@");
                                if (opts.length > 0)
                                        field = opts[0];
@@ -287,16 +365,44 @@ public class Contact extends BaseClass<Data> {
                                        } else if (opt.equals("+")) {
                                                expand = true;
                                                numOfFieldsToExpand++;
+                                       } else if (opt.length() > 0 && opt.charAt(0) == '(') {
+                                               try {
+                                                       opt = opt.substring(1, opt.length() - 1);
+                                                       valueNum = Integer.parseInt(opt);
+                                               } catch (Exception e) {
+                                               }
+                                       } else if (opt.length() > 0 && opt.charAt(0) == '[') {
+                                               try {
+                                                       opt = opt.substring(1, opt.length() - 1);
+                                                       fieldNum = Integer.parseInt(opt);
+                                               } catch (Exception e) {
+                                               }
                                        } else {
                                                try {
                                                        size = Integer.parseInt(opt);
-                                               } catch (Exception e) {
+                                               } catch (NumberFormatException e) {
                                                }
                                        }
                                }
                        }
 
-                       String value = getPreferredDataValue(field);
+                       String value = null;
+                       if (field.length() > 0 && field.charAt(0) == '\'') {
+                               value = field.substring(1);
+                       } else if (valueNum >= 0) {
+                               List<String> vv = getPreferredData(field).getValues();
+                               if (valueNum < vv.size()) {
+                                       value = vv.get(valueNum);
+                               }
+                       } else if (fieldNum >= 0) {
+                               List<String> ff = getPreferredData(field).getFields();
+                               if (fieldNum < ff.size()) {
+                                       value = ff.get(fieldNum);
+                               }
+                       } else {
+                               value = getPreferredDataValue(field);
+                       }
+
                        if (value == null) {
                                value = "";
                        } else {
@@ -403,6 +509,16 @@ public class Contact extends BaseClass<Data> {
                this.nextBKey = vc.nextBKey;
        }
 
+       @Override
+       public String getId() {
+               return "" + getPreferredDataValue("UID");
+       }
+
+       @Override
+       public String getState() {
+               return getId();
+       }
+
        /**
         * Return a {@link String} representation of this contact, in vCard 2.1,
         * without BKeys.
@@ -455,12 +571,15 @@ public class Contact extends BaseClass<Data> {
 
                boolean fn = false;
                boolean n = false;
+               boolean uid = false;
                if (content != null) {
                        for (Data data : content) {
                                if (data.getName().equals("N")) {
                                        n = true;
                                } else if (data.getName().equals("FN")) {
                                        fn = true;
+                               } else if (data.getName().equals("UID")) {
+                                       uid = true;
                                }
 
                                if (!data.getName().equals("VERSION")) {
@@ -470,12 +589,12 @@ public class Contact extends BaseClass<Data> {
                }
 
                // required fields:
-               if (!n) {
+               if (!n) // required since vCard 3.0, supported in 2.1
                        datas.add(new Data(null, "N", "", null));
-               }
-               if (!fn) {
+               if (!fn) // not required anymore but still supported in 4.0
                        datas.add(new Data(null, "FN", "", null));
-               }
+               if (!uid) // supported by vCard, required by this program
+                       datas.add(new Data(null, "UID", UUID.randomUUID().toString(), null));
 
                return datas;
        }