package org.nutz.lang.segment; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import org.nutz.lang.Lang; import org.nutz.lang.Mirror; import org.nutz.lang.util.Context; import org.nutz.lang.util.NutMap; public class CharSegment implements Segment, Cloneable { public CharSegment() {} public CharSegment(String str) { valueOf(str); } @SuppressWarnings("unchecked") public Segment add(String key, Object v) { if (!context.has(key)) { context.set(key, v); return this; } Object val = context.get(key); if (val == null) { context.set(key, v); } else if (val instanceof Collection<?>) { ((Collection<Object>) val).add(v); } else { List<Object> objSet = new LinkedList<Object>(); objSet.add(val); objSet.add(v); context.set(key, objSet); } return this; } public void clearAll() { context.clear(); } public boolean contains(String key) { return keys.containsKey(key); } public Segment born() { return new CharSegment(this.getOrginalString()); } private String orgString; public String getOrginalString() { return orgString; } public Segment clone() { CharSegment cs = new CharSegment(); cs.parse(Lang.inr(orgString)); cs.context = this.context.clone(); return cs; } public Set<String> keys() { return this.keys.keySet(); } public int keyCount() { return this.keys.size(); } public boolean hasKey() { return !this.keys.isEmpty(); } public List<Object> values() { List<Object> re = new ArrayList<Object>(nodes.size()); for (SegmentNode node : nodes) { if (node.isKey()) re.add(context.get(node.getValue())); else re.add(node.getValue()); } return re; } public Segment setAll(Object v) { for (String key : keys()) context.set(key, v); return this; } public Segment setBy(Object obj) { Iterator<String> it = keys().iterator(); Class<?> klass = obj.getClass(); Mirror<?> mirror = Mirror.me(klass); // Primitive Type: set it to all PlugPoints if (mirror.isStringLike() || mirror.isBoolean() || mirror.isNumber() || mirror.isChar()) { this.setAll(obj); } // Map: set by key else if (mirror.isOf(Map.class)) { Map<?, ?> map = (Map<?, ?>) obj; while (it.hasNext()) { String key = it.next(); try { this.set(key, map.get(key)); } catch (Exception e) { this.set(key, ""); } } } // POJO: set by field else { while (it.hasNext()) { String key = it.next(); try { this.set(key, mirror.getValue(obj, key)); } catch (Exception e) { this.set(key, ""); } } } return this; } public Segment set(String key, Object v) { context.set(key, v); return this; } public List<SegmentNode> getNodes() { return nodes; } private Context context; private List<SegmentNode> nodes; private NutMap keys; public void parse(Reader reader) { nodes = new LinkedList<SegmentNode>(); context = Lang.context(); keys = new NutMap(); StringBuilder org = new StringBuilder(); StringBuilder sb = new StringBuilder(); int b; try { while (-1 != (b = reader.read())) { org.append((char) b); switch (b) { case '$': b = reader.read(); org.append((char) b); // Escape if (b == '$') { sb.append((char) b); } // In Plug Point else if (b == '{') { // Save before if (sb.length() > 0) { nodes.add(SegmentNode.val(sb.toString())); sb = new StringBuilder(); } // Search the end while (-1 != (b = reader.read())) { org.append((char) b); if (b == '}') break; sb.append((char) b); } if (b != '}') throw Lang.makeThrow("Error format around '%s'", sb); // Create Key String key = sb.toString(); nodes.add(SegmentNode.key(key)); keys.put(key, null); sb = new StringBuilder(); } // Normal else { sb.append('$').append((char) b); } break; default: sb.append((char) b); } } if (sb.length() > 0) nodes.add(SegmentNode.val(sb.toString())); // Store the Oraginal Value orgString = org.toString(); } catch (IOException e) { throw Lang.wrapThrow(e); } } public Segment valueOf(String str) { parse(new StringReader(str)); return this; } public CharSequence render() { return render(context); } public CharSequence render(Context context) { StringBuilder sb = new StringBuilder(); for (SegmentNode node : nodes) { Object val = node.isKey() ? context.get(node.getValue()) : node.getValue(); if (null == val) continue; if (val instanceof Collection<?>) { for (Object obj : (Collection<?>) val) { sb.append(obj); } } else { sb.append(val); } } return sb; } public Context getContext() { return context; } public void fillNulls(Context context) { for (String key : keys.keySet()) { Object val = context.get(key); if (null == val) context.set(key, "${" + key + "}"); } } public String toString() { return render().toString(); } }