package cri.sanity.util;
import java.util.Calendar;
import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract.PhoneLookup;
import cri.sanity.*;
public final class CallFilter
{
private static CallFilter instance;
private static String[] proj;
private Cursor cursor;
private String lastNum, lastName;
private String[] lastGroups;
//---- public api
public final static CallFilter instance() {
if(instance == null) instance = new CallFilter();
return instance;
}
public final static void shutdown() {
if(instance != null)
instance.close();
}
public final boolean includes(String num, String sect, boolean resultIfDisabled) {
if(!A.is("filter_enable_"+sect) || skipDateTime(sect)) return resultIfDisabled;
// check if this filter has all numbers
if(A.is("filter_all_"+sect)) return res(true, sect);
// check for anonym number
if(num==null || num.length()<=0)
return res(A.is("filter_anonym_"+sect), sect);
// search contacts by number (skip duplicate search of the last number)
if(!query(num, num.equals(lastNum))) // no contact found: check inside explicit number list and check prefix
return res(A.is("filter_unknown_"+sect) || A.is("filter_num_"+num+sect) || skipPrefix(num,sect), sect);
// contact found: check for all contacts or if contact is starred
if(A.is("filter_allcontacts_"+sect) || (A.is("filter_star_"+sect) && isStarred()))
return res(true, sect);
// check found contact
final String con = cursor.getString(cursor.getColumnIndex(PhoneLookup._ID));
if(A.is("filter_contact_"+con+sect))
return res(true, sect);
// check found contact groups if any
if(A.geti("filter_groups_count_"+sect) > 0) {
//synchronized(this) {
if(lastGroups == null) lastGroups = Contacts.groups(con);
//}
for(String group : lastGroups)
if(A.is("filter_group_"+group+sect)) return res(true, sect);
}
// check number prefix
return res(skipPrefix(num,sect), sect);
}
// get display name of given phone number
public final synchronized String searchName(String num) {
if(num==null || num.length()<=0) return null;
final boolean cached = num.equals(lastNum);
if(cached && lastName!=null) return lastName;
if(!query(num, cached)) return lastName = "";
return lastName = cursor.getString(cursor.getColumnIndex(PhoneLookup.DISPLAY_NAME));
}
public final String lastNum () { return lastNum; }
public final String lastName() { return lastName; }
public final synchronized void close() {
if(cursor == null) return;
cursor.close();
cursor = null;
lastNum = null;
lastName = null;
lastGroups = null;
}
//---- private api
private static boolean res(boolean found, String sect) {
return A.geti("filter_mode_"+sect)==0 ? found : !found;
}
private static boolean skipDateTime(String sect) {
if(!A.is("filter_dt_"+sect)) return false;
sect = '_' + sect;
final Calendar cal = Calendar.getInstance();
// date skip
//if(!A.is("filter_dt_day"+cal.get(Calendar.DAY_OF_WEEK)+sect)) return true;
final String days = A.gets("filter_dt_days"+sect);
if(days.length()>0 && days.indexOf(Integer.toString(cal.get(Calendar.DAY_OF_WEEK)))<0) return true;
// time skip
final int cnt = A.geti("filter_dt_time_count"+sect);
if(cnt <= 0) return false;
final int h = cal.get(Calendar.HOUR_OF_DAY);
final int m = cal.get(Calendar.MINUTE);
for(int i=1; i<=cnt; i++) {
final int t = A.geti("filter_dt_time"+i+sect);
final int h1 = (t >> 24) & 0xff;
if(h < h1) continue;
final int m1 = (t >> 16) & 0xff;
if(h==h1 && m<m1) continue;
final int h2 = (t >> 8) & 0xff;
if(h > h2) continue;
final int m2 = t & 0xff;
if(h==h2 && m>m2) continue;
return false;
}
return true;
}
private static boolean skipPrefix(String num, String sect) {
final String prefix = A.gets("filter_prefix_"+sect);
final int len = prefix.length();
if(len <= 0) return false;
String pre;
int end, beg = 0;
do {
end = prefix.indexOf(Conf.FILTER_SEP, beg);
if(end < 0) pre = prefix.substring(beg);
else if(beg == end) break;
else pre = prefix.substring(beg, end);
if(num.startsWith(pre)) return true;
beg = end + 1;
} while(beg>0 && beg<len);
return false;
}
private synchronized boolean query(String num, boolean cached) {
if(!cached) {
if(cursor != null) cursor.close();
lastGroups = null;
lastNum = num;
//if(num.charAt(0) == '+') num = "%2B"+num.substring(1); // like Uri.encode(num) but faster for phone numbers
num = Uri.encode(num);
if(proj == null) proj = new String[]{ PhoneLookup._ID, PhoneLookup.DISPLAY_NAME, PhoneLookup.STARRED };
cursor = A.resolver().query(Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, num), proj, null, null, null);
}
return cursor!=null && cursor.moveToFirst();
}
private boolean isStarred() {
return cursor.getString(cursor.getColumnIndex(PhoneLookup.STARRED)).equals("1");
}
}