/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.ptc.tifworkbench.reader;
import com.mks.api.Command;
import com.mks.api.response.APIException;
import com.mks.api.response.Field;
import com.mks.api.response.Item;
import com.mks.api.response.Response;
import com.mks.api.response.WorkItem;
import com.mks.api.response.WorkItemIterator;
import com.ptc.tifworkbench.integrity.IntegrityException;
import com.ptc.tifworkbench.integrity.IntegrityExceptionEx;
import com.ptc.tifworkbench.jaxbbinding.BackingIssueReference;
import com.ptc.tifworkbench.jaxbbinding.ColumnsDefinition;
import com.ptc.tifworkbench.jaxbbinding.ComputationDefinition;
import com.ptc.tifworkbench.jaxbbinding.DisplayAsType;
import com.ptc.tifworkbench.jaxbbinding.DisplayType;
import com.ptc.tifworkbench.jaxbbinding.FieldDefinition;
import com.ptc.tifworkbench.jaxbbinding.FieldType;
import com.ptc.tifworkbench.jaxbbinding.FieldsDefinitions;
import com.ptc.tifworkbench.jaxbbinding.PhaseDefinition;
import com.ptc.tifworkbench.jaxbbinding.PhasesDefinition;
import com.ptc.tifworkbench.jaxbbinding.ReverseRelationship;
import com.ptc.tifworkbench.jaxbbinding.StoreToHistoryFrequencyType;
import com.ptc.tifworkbench.jaxbbinding.Suggestion;
import com.ptc.tifworkbench.jaxbbinding.Suggestions;
import com.ptc.tifworkbench.jaxbbinding.ValueDefinition;
import com.ptc.tifworkbench.jaxbbinding.ValuesDefinition;
import com.ptc.tifworkbench.model.StandardFields;
import com.ptc.tifworkbench.model.StandardPhases;
import com.ptc.tifworkbench.worker.StatusReporter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
/**
*
* @author pbowden
*/
class FieldReader extends AdminObjectReader
{
private FieldsDefinitions fields;
public FieldReader(FieldsDefinitions fields, StatusReporter reporter) throws IntegrityExceptionEx
{
super(reporter);
this.fields=fields;
}
@Override
public void read()throws IntegrityException
{
HashMap<String, FieldDefinition> visited = new HashMap<String, FieldDefinition>(); // fields we have visited
List<String> ignore = StandardFields.getStandardFieldList();
log("Reading fields.");
reportStatus(0, "Reading field definitions.");
Command cmd = new Command(Command.IM, "fields");
Response resp;
List<String> names = new ArrayList<String>();
try
{
resp = getApi().execute(cmd);
WorkItemIterator wkIt = resp.getWorkItems();
while(wkIt.hasNext())
{
WorkItem wk = wkIt.next();
String fieldName = wk.getId();
log(" Found: " + fieldName + (ignore.contains(fieldName)?" IGNORE":""));
names.add(fieldName);
}
} catch (APIException ex)
{
throw IntegrityExceptionEx.create("Error reading list of fields", ex);
}
int count=0;
int numFields=names.size();
for(String fieldName : names)
{
int prog = (100 * count++)/numFields;
reportStatus(prog, "Read field: " + fieldName);
if (!visited.containsKey(fieldName) && !ignore.contains(fieldName))
{
try
{
// if we have not already been to this field...
FieldDefinition fdef = getFactory().createFieldDefinition();
fdef.setName(fieldName);
// One special case. We always edit the standard Shared Category field.
if("Shared Category".equals(fieldName))
fields.getEditField().add(fdef);
else
fields.getField().add(fdef);
readField(fdef, fieldName);
visited.put(fieldName, fdef); // record the fact that we've been to this field.
//if (!fld.equals(fieldName))
//{ // if we read another field as well (for relationships)...
// visited.put(fld,null); // ...record that field too.
// }
} catch (Exception ex)
{
log("Error reading field " + fieldName);
log(ex.getMessage());
// TODO: surface the errors to the UI.
}
}
}
// Join relationships in forward/backward pairs. Remove one of the pairs from the
// list of definitions.
fixupRelationships(visited);
}
/**
* Given the Element representing a field, build the rest of the field structure.
* @param typeEl
* @return
*/
protected void readField(FieldDefinition fdef, String fieldName) throws Exception
{
//String returnField = new String(); - avoid side-effects
log("Reading field " + fieldName);
try
{
Command cmd = new Command(Command.IM, "viewfield");
cmd.addSelection(fieldName);
Response resp = getApi().execute(cmd);
WorkItem wk = resp.getWorkItem(fieldName);
Field typeFld = wk.getField("type");
// All the attribs that may be on a field.
FieldType ftype = FieldType.fromValue(getSafeField("type", wk));
log("Field type=" + ftype.value());
fdef.setType(ftype);
fdef.setDescription(getSafeField("description", wk));
fdef.setDisplayName(getSafeField("displayName", wk));
if(specified("editabilityRule", wk))
fdef.setEditability(getSafeField("editabilityRule", wk));
if(specified("relevanceRule", wk))
fdef.setRelevance(getSafeField("relevanceRule", wk));
if(specified("multivalued", wk))
fdef.setMultivalued(getBooleanField("multivalued", wk));
if(specified("maxLength", wk))
fdef.setMaxLength(getIntegerField("maxLength", wk));
if(specified("loggingText", wk))
fdef.setLogging(getLoggingField("loggingText", wk));
if(specified("displayRows", wk))
fdef.setDisplayRows(getIntegerField("displayRows", wk));
if(specified("default", wk))
fdef.setDefault(getSafeField("default", wk));
if(specified("min", wk))
fdef.setMin(getSafeField("min", wk));
if(specified("max", wk))
fdef.setMax(getSafeField("max", wk));
if(specified("richContent", wk))
fdef.setRichContent(getBooleanField("richContent", wk));
if(specified("defaultAttachmentField", wk))
fdef.setDefaultAttachmentField(getSafeField("defaultAttachmentField", wk));
if(specified("displayPattern", wk))
fdef.setDisplayPattern(getSafeField("displayPattern", wk));
if(specified("showDateTime", wk))
fdef.setIncludeTime(getBooleanField("showDateTime", wk));
if(specified("displayTrueAs", wk))
fdef.setDisplayTrueAs(getSafeField("displayTrueAs", wk));
if(specified("displayFalseAs", wk))
fdef.setDisplayFalseAs(getSafeField("displayFalseAs", wk));
if(specified("displayAsProgress", wk))
fdef.setDisplayAsProgress(getBooleanField("displayAsProgress", wk));
if(specified("displayAsLink", wk))
fdef.setDisplayAsLink(getBooleanField("displayAsLink", wk));
if(specified("cycleDetection",wk))
fdef.setCycleDetection(getBooleanField("cycleDetection", wk));
if(specified("showTallRows",wk))
fdef.setShowVariableHeightRows(getBooleanField("showTallRows", wk));
if(specified("suggestions",wk))
readSuggestions(fdef,wk);
if(specified("paramSubstitution",wk))
fdef.setSubstituteParameters(getBooleanField("paramSubstitution", wk));
if(specified("displayAs",wk)){
String val = getSafeField("displayAs",wk);
DisplayAsType displayAs = (val.equals("Checkbox")) ? DisplayAsType.CHECKBOX : DisplayAsType.DROPDOWN;
fdef.setDisplayAs(displayAs);
}
if(specified("displayStyle",wk)){
String val = getSafeField("displayStyle",wk);
DisplayType displayStyle = (val.equals("table")) ? DisplayType.TABLE : DisplayType.CSV;
fdef.setDisplayType(displayStyle);
}
if(specified("storeToHistoryFrequency",wk)){
String val = getSafeField("storeToHistoryFrequency",wk);
StoreToHistoryFrequencyType frequencyType = StoreToHistoryFrequencyType.fromValue(val);
fdef.setStoreToHistoryFrequency(frequencyType);
}
readComputation(fdef, wk);
if (FieldType.PICK.equals(ftype))
{
ValuesDefinition vdefs = getFactory().createValuesDefinition();
fdef.setValues(vdefs);
readPickValues(vdefs, wk);
log("Writing a pick field.");
}
else if (FieldType.IBPL.equals(ftype))
{
BackingIssueReference bref = getFactory().createBackingIssueReference();
bref.setField(getSafeField("backingTextFormat", wk));
bref.setStates(getSafeField("backingStates", wk));
bref.setType(getSafeField("backingType", wk));
fdef.setBackingIssue(bref);
log("Writing a IBPL field.");
}
else if (FieldType.FVA.equals(ftype))
{
BackingIssueReference bref = getFactory().createBackingIssueReference();
Field backedByFld = wk.getField("backedBy").getItem().getField("backedBy"); //sic
String rel = backedByFld.getItem().getField("backingRelationship").getValueAsString();
String fld = backedByFld.getItem().getId();
String backedFieldType = backedByFld.getItem().getField("type").getValueAsString();
bref.setRelationship(rel);
bref.setField(fld);
bref.setType(backedFieldType);
fdef.setBackingIssue(bref);
log("Writing a FVA field");
}
else if (FieldType.QBR.equals(ftype))
{
fdef.setQuery(getSafeField("query", wk));
fdef.setCorrelation(getSafeField("correlation", wk));
log("Writing a QBR field");
}
else if (FieldType.PHASE.equals(ftype))
{
PhasesDefinition pdefs = getFactory().createPhasesDefinition();
fdef.setPhases(pdefs);
log("Writing a phase field.");
readPhaseValues(pdefs, wk);
}
else if (FieldType.RELATIONSHIP.equals(ftype))
{
log("Writing a relationship field.");
readBasicRelationshipFields(fdef, wk);
ReverseRelationship rev = getFactory().createReverseRelationship();
String pairedField = getSafeField("pairedField", wk);
rev.setName(pairedField);
fdef.setReverse(rev);
}
else
{
//returnField = typeFld.getString();
}
} catch(Exception e)
{
log("Failed to read field " + fieldName);
log("Exception message: " + e.getMessage());
throw new IntegrityException("Error reading field: " + fieldName, e);
}
//return returnField;
}
protected void readSuggestions(final FieldDefinition fdef, final WorkItem wk){
Suggestions fdefSuggestions = getFactory().createSuggestions();
Field suggestionsField = wk.getField("suggestions");
List<?> suggestions = suggestionsField.getList();
for(Object value : suggestions){
Suggestion suggestion = getFactory().createSuggestion();
suggestion.setName(value.toString());
fdefSuggestions.getSuggestion().add(suggestion);
}
fdef.setSuggestions(fdefSuggestions);
}
protected void readBasicRelationshipFields(FieldDefinition fdef, WorkItem wk)
{
fdef.setMultivalued(getBooleanField("isMultiValued", wk));
fdef.setShowVariableHeightRows(false); // Not supported by the API yet.
fdef.setDisplayRows(getIntegerField("displayRows", wk));
if(getSafeField("defaultBrowseQuery", wk).length()>0)
fdef.setQuery(getSafeField("defaultBrowseQuery", wk));
fdef.setRelates(getListOfListAsString("allowedTypes", wk));
fdef.setTrace(getBooleanField("trace", wk));
List<String> cols = getStringList("defaultColumns", wk);
if(cols.size() > 0)
{
ColumnsDefinition colsDef = getFactory().createColumnsDefinition();
for(String colName : cols)
colsDef.getColumn().add(colName);
fdef.setDefaultColumns(colsDef);
}
}
protected void fixupRelationships(HashMap<String, FieldDefinition>fmap)
{
List<FieldDefinition>fixed = new ArrayList<FieldDefinition>();
List<FieldDefinition>todelete = new ArrayList<FieldDefinition>();
for(FieldDefinition fdef : fields.getField())
{
if(fdef.getType() == FieldType.RELATIONSHIP)
{
FieldDefinition pairedField = fmap.get(fdef.getReverse().getName());
if(fixed.contains(pairedField)) // We've already processed this fields partner
{
todelete.add(fdef);
}
else
{
fdef.getReverse().setDisplay(pairedField.getDisplayName());
fdef.getReverse().setRelates(pairedField.getRelates());
fdef.getReverse().setMultivalued(pairedField.isMultivalued());
fdef.getReverse().setTrace(pairedField.isTrace());
fixed.add(fdef);
}
}
}
for(FieldDefinition delDef : todelete)
{
fields.getField().remove(delDef);
}
}
protected void readComputation(FieldDefinition fdef, WorkItem wk)
{
if(specified("computation", wk))
{
String val = wk.getField("computation").getString();
val = val.replaceAll("\n", "");
val = val.replaceAll("\r", "");
if (val != null && val.trim().length() > 0)
{
ComputationDefinition comp = getFactory().createComputationDefinition();
comp.setMode(getBooleanField("staticComputation", wk) ? "static" : "dynamic");
comp.setStore(getSafeField("storeToHistoryFrequency", wk));
comp.setValue(val);
fdef.setComputation(comp);
}
}
}
protected void readPickValues(ValuesDefinition vdef, WorkItem wk)
{
List itList = wk.getField("picks").getList();
if (itList != null)
{
Iterator iter = itList.iterator();
while(iter.hasNext())
{
Item item = (Item)iter.next();
String id = item.getId();
if(id != null && id.trim().length()>0)
{
ValueDefinition vd = getFactory().createValueDefinition();
id = escapeChar(id, ",");
id = escapeChar(id, ":");
id = escapeChar(id, ";"); // need to escape characters per 44896 --al 20100122
int index = getIntegerField("value", item);
vd.setIndex(index);
vd.setValue(id);
vdef.getValue().add(vd);
}
}
}
}
protected void readPhaseValues(PhasesDefinition pdef, WorkItem wk)
{
List<String> ignore = StandardPhases.getStandardPhaseList();
List itList = wk.getField("phases").getList();
if (itList != null)
{
Iterator iter = itList.iterator();
while(iter.hasNext())
{
Item item = (Item)iter.next();
String id = item.getId();
if(ignore.contains(id)) continue;
PhaseDefinition pd = getFactory().createPhaseDefinition();
pd.setName(id);
pdef.getPhase().add(pd);
List states = item.getField("states").getList();
StringBuilder buff = new StringBuilder();
for(Object o : states)
{
String state = o.toString();
buff.append(state).append(",");
}
buff.setLength(buff.length()-1);
pd.setStates(buff.toString());
}
}
}
}