/*********************************************************************************
* TotalCross Software Development Kit *
* Copyright (C) 2003 Fabian Kroeher *
* 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.ce.builtin.pimal;
import totalcross.pim.ce.builtin.*;
import totalcross.pim.*;
import totalcross.util.*;
/**
* abstract superclass for all PocketPCRecords
* used to minimize code in the subclasses (see setFields() and getFields())
* @author Fabian Kroeher
*
*/
public abstract class PocketPCRecord
{
protected IObject source;
protected Vector fields;
/**
* creates a new instance of PocketPCRecord with a given IObject source
* @param source the IObject the PocketPCRecord wraps
*/
public PocketPCRecord(IObject source)
{
this.source = source;
this.fields = new Vector();
}
/**
* this methods gets the POOM fields from the source (IObject) and maps them to Address-, Date- or ToDoField
* @return a Vector with Address-, Date- or ToDoFields of this record
*/
public Vector getFields()
{
// clear the fields Vector
fields.removeAllElements();
// first refresh the source with data from the device
source.refresh();
// go through the AddressField-Templates and replace the fieldnames with values
int n = templates();
for (int i = 0; i < n; i++)
{
VersitField tmp = template(i);
String[] values = tmp.getValues();
String[] newValues = new String[values.length];
boolean addField = false;
for (int j = 0; j < values.length; j++)
{
String fieldName = values[j];
newValues[j] = source.getValue(fieldName);
if (newValues[j].length() > 0)
addField = true;
}
tmp.setValues(newValues);
// only add the field if not all of the values are empty
if (addField)
fields.addElement(tmp);
}
// add exceptional fields (which are stored in the not e.g.)
addExceptionalFields(fields);
// finally return the retVal Vector
return fields;
}
/**
* sets the fields of this record to fields
* @param fields a Vector which contains Address-, Date- or ToDoFields
*/
public void setFields(Vector fields)
{
// delete all the existing fields from the source
source.reset();
// set the fields Vector to the new one (this should be the same anyway)
this.fields = fields;
// reorder the given fields; put the one with PREF at the beginning
// (they are saved first) -> this way a PREF email-Address gets into email1-field
// on the device (and not into email3 i.e.)
Vector sortedFields = new Vector();
// new Vetor for those fields which cannot be mapped
Vector exceptionalFields = new Vector();
int n = fields.size();
for (int i = 0; i < n; i++)
{
VersitField tmp = (VersitField)fields.items[i];
// tmp has PREF an is inserted at the beginning
if (tmp.hasOption("TYPE", "PREF"))
sortedFields.insertElementAt(tmp, 0);
// tmp does not have pref and is appended
else
sortedFields.addElement(tmp);
}
// first, get a copy of the fieldTemplates
Vector fieldTemplates = getTemplates();
// go through the given (sorted) fields
n = sortedFields.size();
for (int i = 0; i < n; i++)
{
VersitField tmpSortedField = (VersitField)sortedFields.items[i];
// now we need to estimate which one of the fieldTemplates (from
// which we know how to map it) fits best to tmp (the actual field from the
// given sorted fields)
// Therefore we give a score for matching properties and assign tmp to the
// fieldTemplate it fits best (highest score). How many points for a
// matching property are given depends on the property and is defined in VersitField
// the field must at least match with score higher than highscore to
// be assigned to each other
int highscore = 0;
VersitField matchingTemplate = null;
// go through the AddressFieldTemplates
int nn = fieldTemplates.size();
for (int j = 0; j < nn; j++)
{
VersitField tmpTemplate = (VersitField)fieldTemplates.items[j];
int matchingScore = tmpSortedField.match(tmpTemplate);
// the tmpTemplate matches better than anything before!
if (matchingScore > highscore)
{
// set highscore to new score
highscore = matchingScore;
// set the matchingTemplate to tmpTemplate
matchingTemplate = tmpTemplate;
}
}
// check if we found a matching template at all
if (matchingTemplate == null)
// the tmpSortedField cannot be mapped because we found no matching temlate
exceptionalFields.addElement(tmpSortedField);
else
{
// we found out the best matching template for tmpSortedField
// it will be used for mapping the tmpSortedField to source,
// but first we must delete the matchingTemplate
// from the templates to ensure that it cannot be used again (if the template would be
// used again, the corresponding fields on the device would be overwritten instantly)
fieldTemplates.removeElement(matchingTemplate);
map(tmpSortedField, matchingTemplate);
}
}
// finally, after mapping all the values to the source we store it on the device
source.save();
// after that, we handle the exceptional fields (if a handler is registered)
handleExceptionalFields(exceptionalFields);
}
/**
* the values of the AddressField values will be stored in the IObject source
* according to the given template
* please note that if the value has too many fields (that means is not after the vCard spec)
* the additional values will be DROPPED!
* please do also note that the source should be resetted before starting to insert new values!
* @param value the AddressField which contains the values
* @param template the AddressField which contains the fieldnames on the device for the values
*/
protected void map(VersitField value, VersitField template)
{
try
{
String templates[] = template.getValues();
String values[] = value.getValues();
for (int i = 0; i < templates.length; i++)
source.setValue(templates[i], values[i]);
}
catch(ArrayIndexOutOfBoundsException aioobe)
{
// well, this should not occur - it means that either the value VersitField
// has to many values or not enough values
// but if it occurs -> do nothing (there is no more value to map)
}
}
/**
* reads the note directly from the device and returns it
* @return the note directly read from the device
*/
public String rawReadNote()
{
// refresh the source from the device
// source.refresh(); - guich: when inserting new todobooks, the record CANNOT be refreshed, or the old information will be losted. if something else fails bc of this, we must put a flag in order to keep the ToDoNSHNote.write working
// get the note and pass it back
return source.getValue("(String)note");
}
/**
* writes the note directly to the device
* @param note the note to be written on the device
*/
public void rawWriteNote(String note)
{
// set the new value for source
source.setValue("(String)note", note);
// save the source to the device
source.save();
}
/**
* returns the first field of the fieldname Vector (this should be the id!)
* @return the id of this Record
*/
public String getId()
{
return source.getValue(field(0));
}
/**
* deletes this Record from the device
*/
public void delete()
{
source.delete();
}
/**
* returns the size of the corresponding *FieldTemplates Vector of class Constant
* @return the number of templates for the object
*/
abstract public int templates();
/**
* returns the template at the given position from the corresponding template Vector
* from class Constant
* @param position the index of the template
* @return the template at the given index
*/
abstract public VersitField template(int position);
/**
* returns a cloned copy of the corresponding *FieldTemplates Vector of class Constant
* @return all the corresponding templates in a Vector
*/
abstract public Vector getTemplates();
/**
* return the field_name_ of a *FieldTemplate at a given position
* @param position the index of the fieldname to return
* @return the fieldname at given index
*/
abstract public String field(int position);
/**
* adds the exceptional fields to the given Vector; exceptional fields can mean that
* they have been read out of the note e.g.
* @param alreadyFoundFields the Vector of the "regular" fields where the exceptional fields can be added
*/
abstract public void addExceptionalFields(Vector alreadyFoundFields);
/**
* handles the fields that could not be stored on the device (writes them in the note e.g.)
* @param exceptionalFields a Vector of the fields that could not be mapped to the device
*/
abstract public void handleExceptionalFields(Vector exceptionalFields);
}