1package autotest.tko;
2
3import autotest.common.Utils;
4
5import com.google.gwt.json.client.JSONArray;
6import com.google.gwt.json.client.JSONObject;
7import com.google.gwt.json.client.JSONString;
8
9import java.util.ArrayList;
10import java.util.Collection;
11import java.util.Collections;
12import java.util.List;
13
14public abstract class ParameterizedField extends HeaderField {
15    private static class FieldIdentifier {
16        String type;
17        String value;
18
19        public FieldIdentifier(ParameterizedField field) {
20            this.type = field.getTypeName();
21            this.value = field.getValue();
22        }
23
24        @Override
25        public int hashCode() {
26            return type.hashCode() + 31 * value.hashCode();
27        }
28
29        @Override
30        public boolean equals(Object obj) {
31            if (obj == null || !(obj instanceof FieldIdentifier)) {
32                return false;
33            }
34
35            FieldIdentifier other = (FieldIdentifier) obj;
36            return type.equals(other.type) && value.equals(other.value);
37        }
38    }
39
40    private static final ParameterizedField[] prototypes = new ParameterizedField[] {
41        // add all ParameterizedField subclasses here.  these instances should never escape.
42        new MachineLabelField(),
43        new IterationResultField(),
44        new TestAttributeField(),
45        new TestLabelField(),
46        new JobKeyvalField(),
47        new IterationAttributeField(),
48    };
49
50    private static final List<String> prototypeNames = new ArrayList<String>();
51    static {
52        for (ParameterizedField prototype : prototypes) {
53            prototypeNames.add(prototype.getTypeName());
54        }
55    }
56
57    private String value;
58
59    protected ParameterizedField() {
60        super("", "");
61    }
62
63    public static ParameterizedField newInstance(String typeName, String value) {
64        ParameterizedField prototype = getPrototype(typeName);
65        ParameterizedField newField = prototype.freshInstance();
66        newField.setValue(value);
67        return newField;
68    }
69
70    public static Collection<String> getFieldTypeNames() {
71        return Collections.unmodifiableCollection(prototypeNames);
72    }
73
74    private static ParameterizedField getPrototype(String name) {
75        for (ParameterizedField prototype : prototypes) {
76            if (name.startsWith(prototype.getTypeName())) {
77                return prototype;
78            }
79        }
80
81        throw new IllegalArgumentException("No prototype found for " + name);
82    }
83
84    @Override
85    public String getSqlName() {
86        return getBaseSqlName() + getValue();
87    }
88
89    @Override
90    public void addQueryParameters(JSONObject parameters) {
91        JSONArray fieldValueList =
92            Utils.setDefaultValue(parameters, getFieldParameterName(), new JSONArray()).isArray();
93        fieldValueList.set(fieldValueList.size(), new JSONString(getValue()));
94    }
95
96    /**
97     * @return the prefix of the SQL name generated for each field
98     */
99    protected abstract String getBaseSqlName();
100
101    /**
102     * @return name of the parameter to pass with a list of field names for this field type
103     */
104    protected abstract String getFieldParameterName();
105
106    /**
107     * @return a string identifying this type of field
108     */
109    public abstract String getTypeName();
110
111    /**
112     * @return a new instance of the subclass type.
113     */
114    protected abstract ParameterizedField freshInstance();
115
116    @Override
117    public String getName() {
118        return getTypeName() + ": " + getValue();
119    }
120
121    public String getValue() {
122        return value;
123    }
124
125    public void setValue(String value) {
126        this.value = value;
127    }
128
129    public Object getIdentifier() {
130        return new FieldIdentifier(this);
131    }
132
133    /**
134     * Get the exact field to use in a SQL WHERE clause to filter on this field.
135     *
136     * This is a necessary artifact of the way we directly expose SQL WHERE clauses to the user.  It
137     * will hopefully be possible to get rid of this in the future if that changes.
138     */
139    public abstract String getFilteringName();
140}
141