/********************************************************************************* * TotalCross Software Development Kit * * Copyright (C) 2003 Gilbert Fridgen * * Copyright (C) 2003-2012 SuperWaba Ltda. * * All Rights Reserved * * * * This library and virtual machine is distributed in the hope that it will * * be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * * * This file is covered by the GNU LESSER GENERAL PUBLIC LICENSE VERSION 3.0 * * A copy of this license is located in file license.txt at the root of this * * SDK or can be downloaded here: * * http://www.gnu.org/licenses/lgpl-3.0.txt * * * *********************************************************************************/ package totalcross.pim; import totalcross.util.*; /** * Abstract superclass for Field-classes that use the vCard or vCalendar standard. Contains methods for handling key-option-value triples * Please refer to vCard and vCalendar specification for more information * @author Gilbert Fridgen */ public abstract class VersitField { final public static int X = 9999; protected int key = -1; protected String[] values; protected Hashtable options; protected String[] optionsAsArray; // to clone the Object properly /** * Saves the key and the values in arrays and the options in a hashtable * @param key a field's key * @param options options to store * @param values values to store */ public VersitField(int key, String[] options, String[] values) { /* this.key = key; this.optionsAsArray = options; this.values = (values == null) ? (new String[0]) : values; if (options == null) this.options = new Hashtable(13); else { this.options = new Hashtable(options.length); for (int i = 0;i < options.length;i++) { int equals = options[i].indexOf('='); // test if there's an equals-symbol in the option if (equals != -1) { // there is an equals int len = options[i].length(); if (len > 1) { // make sure that the String contains more than one "=" if (equals == len) { // is "=" the last character? addOption(options[i], ""); // must be an empty option } else if (equals == 0) { // is "=" the first character? addOption("", options[i].substring(1)); // must be the value of an empty option - strange... } else { // regular option=value addOption(options[i].substring(0, equals), options[i].substring(equals + 1)); } } } else { // when there's no "=" this must be a type-option if (options[i].length() > 0) addOption("TYPE", options[i]); } } }*/ this.key = key; this.optionsAsArray = options; this.values = (values==null) ? (new String[0]) : values; if(options == null){ this.options = new Hashtable(13); } else{ this.options = new Hashtable(options.length); for (int i = 0; i < options.length; i++) { int equals = options[i].indexOf('='); // test if there's an equals-symbol in the option if (equals != -1) // there is an equals { if(options[i].length() > 1){ // make sure that the String contains more than one "=" if (equals == options[i].length()) // is "=" the last character? { addOption(options[i].substring(0, equals), ""); // must be an empty option } else if (equals == 0){ // is "=" the first character? addOption("",options[i].substring(1)); // must be the value of an empty option - strange... } else // regular option=value { addOption(options[i].substring(0, equals), options[i].substring(equals + 1)); } } } else // when there's no "=" this must be a type-option if(options[i].length() > 0) addOption("TYPE", options[i]); } } } /** * Getter for the key * @return int this field's key */ public int getKey() { return key; } /** * Returns this field's options. You can manipulate this Hashtable, but it is recommended to use the methods addOption() and removeOption() instead. * * The data structure of the options is as follows: * There's a Hashtable of options. The hashtable's keys consist of the option's keys. The hashtables value is a Vector of Strings of the option's value(s). If you have a one-value-option the option is still saved in a one-element-Vector. * @return Hashtable options */ public Hashtable getOptions() { return options; } /** * Returns option-values for a specific option-key * @param key the option-key for which options should be returned * @return a Vector of option-values found for this option-key */ public Vector getOption(String key) { key = key.toUpperCase(); return (Vector)options.get(key); } /** * Getter for the values * @return A String[] of values */ public String[] getValues() { return values; } /** * Adds an option to this field. * Options have the format "OPTION-KEY=OPTION-VALUE". * @param key the option's key * @param value the option's value */ public void addOption(String key, String value) { key = key.toUpperCase(); Vector v = null; v = (Vector)options.get(key); //retrieve corresponding vector if (v == null) v = new Vector(); // create Vector if necessary // TODO parse comma separated list if (value.length() > 0) v.addElement(value.toUpperCase()); // add value options.put(key, v); } /** * Removes a specific option. * @param key the key, whose given value should be removed * @param value the value that should be removed */ public void removeOption(String key, String value) { key = key.toUpperCase(); Vector v = null; v = (Vector)options.get(key); //retrieve corresponding vector // added by kroehefa if (v != null) { v.removeElement(value); // remove option if (v.size() == 0) options.remove(key); // remove Vector from Hashtable if it's empty } } /** * Setter for the values * @param values values to set */ public void setValues(String[] values) { this.values = values; } /** * This method returns the String representative of this Object. * If you use this method of VersitField the key is missing in the String representative. * So please use the toString()-method of VCalField respective VCardField. * @author Kathrin Braunwarth * @see java.lang.Object#toString() */ public String toString() { StringBuffer asString = new StringBuffer(256); Hashtable ht = getOptions(); if (ht.size() > 0) asString.append(';'); Vector v = ht.getKeys(); int z = v.size(); for (int i = 0;i < z;i++) { String o = (String)v.items[i]; Vector a = (Vector)ht.get(o); int nj = a.size(); for (int j = 0;j < nj;j++) asString.append(o).append('=').append((String)a.items[j]).append(';'); } if (asString.length() > 0) // remove the last ; asString.setLength(asString.length()-1); asString.append(':'); String[] h = getValues(); z = h.length-1; for (int i = 0; i <= z; i++) { asString.append(h[i]); if (i < z) asString.append(";"); } return asString.toString(); } /** * Clones the options * @return the options' clone * @author Fabian Kroeher */ protected String[] cloneOptions() { String[] options = new String[optionsAsArray.length]; for (int j=0; j<this.optionsAsArray.length; j++) options[j]=this.optionsAsArray[j]; // Vm.copyArray(this.optionsAsArray,0,options,0, options.length); return options; } /** * Clones the values * @return the values' clone * @author Fabian Kroeher */ protected String[] cloneValues() { String[] values = new String[this.values.length]; // Vm.copyArray(this.values,0,values,0,this.values.length); for (int i=0; i<this.values.length; i++) values[i]= this.values[i]; return values; } /** * Checks of a spcific option is set * @param key the key of the option to check * @param value the value, that has to be set * @return <code>true</code>, if the value is found for the given option, otherwise <code>false</code> */ public boolean hasOption(String key, String value) { key = key.toUpperCase(); value = value.toUpperCase(); Vector v = (Vector)options.get(key); if (v != null) { int n = v.size(); for (int i = 0; i < n; i++) { // if Option is found, return true immediately if (((String)v.items[i]).toUpperCase().equals(value)) return true; } } // options has not been found, return false return false; } /** * Calculates a score, how similar to VersitFields are * @param fieldToMatch VersitField to compare this field to * @return the score */ public int match(VersitField fieldToMatch) { // the fields do not have the same key -> that means matching of 0 (no match) if (this.getKey() != fieldToMatch.getKey()) return 0; // the fields have the same key - so lets compare them int score = 1; // determine what kind of options the fieldToMatch has Vector keys = fieldToMatch.getOptions().getKeys(); // compare options for every key of the fieldToMatch compare int n = keys.size(); for (int i = 0;i < n; i++) { String tmpKey = (String)keys.items[i]; Vector tmpMyOptions = (Vector)this.getOption(tmpKey); Vector tmpFieldToMatchOptions = (Vector)fieldToMatch.getOption(tmpKey); if (tmpMyOptions == null || tmpMyOptions.size() == 0) { // tmpMyOptions does not contain options under this key -> no score } else { // both Objects have options corresponding to the tmpKey -> compare them int nj = tmpMyOptions.size(); for (int j = 0;j < nj;j++) { String tmpMyOption = (String)tmpMyOptions.items[j]; // go through the Options of tmpFieldToMatchOptions and compare int nk = tmpFieldToMatchOptions.size(); forLoop3:for (int k = 0;k < nk;k++) { String tmpFieldToMatchOption = (String)tmpFieldToMatchOptions.items[k]; if (tmpFieldToMatchOption.equals(tmpMyOption)) { // found Options that are equal -> increment score and break this loop if (tmpMyOption.equals("WORK") || tmpMyOption.equals("HOME")) score += 5; else if (tmpMyOption.startsWith("X-")) score += 9999; else score += 1; break forLoop3; } } } } } if (this.getKey() == VersitField.X) { if (score < 9999) return 0; else return score - 9999; } else return score; } }