001 package de.deepamehta.plugins.mail; 002 003 import static de.deepamehta.plugins.mail.MailPlugin.*; 004 005 import java.util.ArrayList; 006 import java.util.Collections; 007 import java.util.Comparator; 008 import java.util.HashMap; 009 import java.util.List; 010 import java.util.Map; 011 import java.util.Set; 012 import java.util.logging.Logger; 013 014 import de.deepamehta.core.RelatedTopic; 015 import de.deepamehta.core.Topic; 016 import de.deepamehta.core.model.CompositeValueModel; 017 import de.deepamehta.core.model.TopicModel; 018 import de.deepamehta.core.service.ClientState; 019 import de.deepamehta.core.service.DeepaMehtaService; 020 021 public class Autocomplete { 022 023 private static Logger log = Logger.getLogger(Autocomplete.class.getName()); 024 025 private final DeepaMehtaService dms; 026 027 private final MailConfigurationCache config; 028 029 public static final Comparator<TopicModel> VALUE_COMPARATOR = new Comparator<TopicModel>() { 030 @Override 031 public int compare(TopicModel a, TopicModel b) { 032 return a.getSimpleValue().toString().compareTo(b.getSimpleValue().toString()); 033 } 034 }; 035 036 public Autocomplete(DeepaMehtaService dms, MailConfigurationCache config) { 037 this.dms = dms; 038 this.config = config; 039 } 040 041 /** 042 * call a search on all configured topic types and on all email addresses 043 * 044 * @param query 045 * @param clientState 046 * 047 * @return topic list with email ID and contact type URI 048 */ 049 public List<TopicModel> search(String query, ClientState clientState) { 050 // search and hash parent results by ID (to overwrite duplicates) 051 Map<Long, Topic> parents = new HashMap<Long, Topic>(); 052 for (String uri : config.getSearchTypeUris()) { 053 for (Topic topic : dms.searchTopics(query, uri)) { 054 Topic parent = getParent(topic); 055 parents.put(parent.getId(), parent); 056 } 057 } 058 059 // get and hash addresses of each parent 060 Map<Long, TopicModel> addresses = new HashMap<Long, TopicModel>(); 061 for (Topic result : parents.values()) { 062 Topic parent = dms.getTopic(result.getId(), true); 063 for (TopicModel address : getEmailAddresses(parent, clientState)) { 064 putAddress(addresses, parent, address); 065 } 066 } 067 068 // search email directly afterwards and merge the results 069 Set<Topic> searchTopics = dms.searchTopics(query, EMAIL_ADDRESS); 070 for (Topic address : searchTopics) { 071 TopicModel model = address.getModel(); 072 if (addresses.containsKey(model.getId()) == false) { 073 putAddress(addresses, getParent(address), model); 074 } 075 } 076 077 // wrap, sort and return 078 List<TopicModel> result = new ArrayList<TopicModel>(addresses.values()); 079 Collections.sort(result, VALUE_COMPARATOR); 080 081 // FIXME inconsistent model => use a specific view model 082 return result; 083 } 084 085 /** 086 * 087 * @param topic 088 * @param clientState 089 * 090 * @return list of mail addresses with at minimum one empty address 091 */ 092 private List<TopicModel> getEmailAddresses(Topic topic, ClientState clientState) { 093 // FIXME attached value should support add(...) of child compositions 094 if (topic.getCompositeValue().has(EMAIL_ADDRESS) == false) { 095 log.warning("composite of " + topic.getSimpleValue() + " contains no email address"); 096 topic.setCompositeValue(new CompositeValueModel().add(EMAIL_ADDRESS, // 097 new TopicModel(EMAIL_ADDRESS)), clientState, null); 098 } 099 // return the existing or the newly created list of addresses 100 return topic.getCompositeValue().getModel().getTopics(EMAIL_ADDRESS); 101 } 102 103 private RelatedTopic getParent(Topic child) { 104 return child.getRelatedTopic(COMPOSITION, CHILD, PARENT, null, false, false); 105 } 106 107 /** 108 * puts an inconsistent model (address ID + contact type URI) of email 109 * address into the addresses map. 110 */ 111 private void putAddress(Map<Long, TopicModel> addresses, Topic parent, TopicModel address) { 112 // concatenate values 113 address.setSimpleValue(parent.getSimpleValue() + // 114 " <" + address.getSimpleValue() + ">"); 115 // replace type URI 116 address.setTypeUri(parent.getTypeUri()); 117 addresses.put(address.getId(), address); 118 } 119 }