package com.oreilly.demo.android.pa.searchdemo; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import android.content.Context; public class SearchLogic implements SearchLogicInterface { private Sonnet[] sonnets; private HashMap<String, HashSet<SonnetRef>> termindex; public SearchLogic(Context context, int resourceId) throws Exception { termindex = new HashMap<String, HashSet<SonnetRef>>(); sonnets = readInSonnets(context, resourceId, termindex); if(sonnets == null) throw new Exception("No Sonnets!"); } public Sonnet getSonnet(int i) { return sonnets != null ? sonnets[i] : null; } @SuppressWarnings("unchecked") public SonnetFragment[] search(String query) { if(query == null || query.trim().length() < 1) return new SonnetFragment[0]; query = query.trim().toLowerCase(); ArrayList<SonnetFragment> frags = new ArrayList<SonnetFragment>(); String[] terms = query.split(" "); if(terms == null) terms = new String[]{query}; ArrayList<HashSet<SonnetRef>> sets = new ArrayList<HashSet<SonnetRef>>(); for(String term: terms) { if(termindex.containsKey(term)) { sets.add((HashSet<SonnetRef>) (termindex.get(term).clone())); } } if(!sets.isEmpty()) { HashSet<SonnetRef> main = null; for(HashSet<SonnetRef> set: sets) { if(main == null) main = set; else { main.retainAll(set); } } if(main != null && !main.isEmpty()) { Iterator<SonnetRef> it = main.iterator(); while(it.hasNext()) { SonnetRef s = it.next(); Sonnet son = sonnets[s.num]; frags.add(new SonnetFragment(s.num, son.lines[s.line])); } } } return frags.isEmpty() ? new SonnetFragment[0] : frags.toArray(new SonnetFragment[frags.size()]); } private static Sonnet[] readInSonnets(Context context, int resourceId, HashMap<String, HashSet<SonnetRef>> index) throws Exception { ArrayList<Sonnet> sons = new ArrayList<Sonnet>(); BufferedReader br = null; try { br = new BufferedReader( new InputStreamReader(context.getResources().openRawResource(resourceId))); String line = null; String num = null; ArrayList<String> ls = new ArrayList<String>(); while ((line = br.readLine()) != null) { if(line.length() < 15 && line.endsWith(".".intern())) { String curnum = line.substring(0, line.length() - 1); if(num != null) { int size = ls.size(); Sonnet sonnet = new Sonnet(num, ls.toArray(new String[size])); sons.add(sonnet); if(index != null) { for(int i=0;i<size;i++) { String[] words = sonnet.lines[i].split(" ".intern()); if(words != null) { for(String word: words) { while(word.endsWith(",".intern()) || word.endsWith(".".intern()) || word.endsWith("?".intern())) { word = word.substring(0, word.length() - 1); } word = word.trim().toLowerCase(); HashSet<SonnetRef> set = null; if(index.containsKey(word)) { set = index.get(word); } else set = new HashSet<SonnetRef>(); set.add(new SonnetRef(sons.size() - 1, i)); index.put(word, set); } } } } } num = curnum; ls.clear(); } else if(line.trim().length() > 1) { ls.add(line); } } } finally { try { if(br != null) { br.close(); } } catch (IOException e) { e.printStackTrace(); } } return !sons.isEmpty() ? sons.toArray(new Sonnet[sons.size()]) : null; } private static class SonnetRef { int num; int line; public SonnetRef(int n, int l) { num = n; line = l; } @Override public boolean equals(Object ob) { if(super.equals(ob)) return true; if(ob != null && ob instanceof SonnetRef) { SonnetRef s = (SonnetRef) ob; return num == s.num && line == s.line; } return false; } @Override public int hashCode() { int hash = 1; hash = hash * 17 + num; hash = hash * 31 + line; return hash; } } }