package org.tvbrowser.utils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.tvbrowser.content.TvBrowserContentProvider;
import org.tvbrowser.devplugin.Channel;
import org.tvbrowser.devplugin.PluginHandler;
import org.tvbrowser.devplugin.PluginServiceConnection;
import org.tvbrowser.devplugin.Program;
import org.tvbrowser.settings.SettingConstants;
import org.tvbrowser.tvbrowser.Favorite;
import org.tvbrowser.tvbrowser.MarkingsUpdateListener;
import org.tvbrowser.tvbrowser.R;
import org.tvbrowser.tvbrowser.WhereClause;
import android.content.BroadcastReceiver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.database.Cursor;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.os.Binder;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v4.util.SparseArrayCompat;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.style.ImageSpan;
public class ProgramUtils {
public static final String[] DATA_CHANNEL_PROJECTION = {
TvBrowserContentProvider.KEY_ID,
TvBrowserContentProvider.CHANNEL_KEY_CHANNEL_ID,
TvBrowserContentProvider.CHANNEL_KEY_NAME,
TvBrowserContentProvider.CHANNEL_KEY_LOGO,
TvBrowserContentProvider.DATA_KEY_STARTTIME,
TvBrowserContentProvider.DATA_KEY_ENDTIME,
TvBrowserContentProvider.DATA_KEY_TITLE,
TvBrowserContentProvider.DATA_KEY_SHORT_DESCRIPTION,
TvBrowserContentProvider.DATA_KEY_DESCRIPTION,
TvBrowserContentProvider.DATA_KEY_EPISODE_TITLE,
TvBrowserContentProvider.DATA_KEY_DONT_WANT_TO_SEE
};
public static final String[] DATA_PROJECTION = {
TvBrowserContentProvider.KEY_ID,
TvBrowserContentProvider.DATA_KEY_STARTTIME,
TvBrowserContentProvider.DATA_KEY_ENDTIME,
TvBrowserContentProvider.DATA_KEY_TITLE,
TvBrowserContentProvider.DATA_KEY_SHORT_DESCRIPTION,
TvBrowserContentProvider.DATA_KEY_DESCRIPTION,
TvBrowserContentProvider.DATA_KEY_EPISODE_TITLE,
TvBrowserContentProvider.DATA_KEY_DONT_WANT_TO_SEE
};
public static final Program createProgramFromDataCursor(Context context, Cursor cursor) {
Program result = null;
if(IOUtils.prepareAccessFirst(cursor) && cursor.getColumnIndex(TvBrowserContentProvider.DATA_KEY_STARTTIME) != -1) {
Channel channel = createChannelFromCursor(context, cursor);
if(channel != null) {
final long startTime = cursor.getLong(cursor.getColumnIndex(TvBrowserContentProvider.DATA_KEY_STARTTIME));
Calendar test = Calendar.getInstance();
test.add(Calendar.DAY_OF_YEAR, -1);
test.set(Calendar.HOUR_OF_DAY, 0);
test.set(Calendar.MINUTE, 0);
test.set(Calendar.SECOND, 0);
test.set(Calendar.MILLISECOND, 0);
if(test.getTimeInMillis() <= startTime) {
final long endTime = cursor.getLong(cursor.getColumnIndex(TvBrowserContentProvider.DATA_KEY_ENDTIME));
final String title = cursor.getString(cursor.getColumnIndex(TvBrowserContentProvider.DATA_KEY_TITLE));
final String shortDescription = cursor.getString(cursor.getColumnIndex(TvBrowserContentProvider.DATA_KEY_SHORT_DESCRIPTION));
final String description = cursor.getString(cursor.getColumnIndex(TvBrowserContentProvider.DATA_KEY_DESCRIPTION));
final String episodeTitle = cursor.getString(cursor.getColumnIndex(TvBrowserContentProvider.DATA_KEY_EPISODE_TITLE));
result = new Program(cursor.getLong(cursor.getColumnIndex(TvBrowserContentProvider.KEY_ID)), startTime, endTime, title, shortDescription, description, episodeTitle, channel);
}
}
}
return result;
}
public static final Program[] createProgramsFromDataCursor(Context context, Cursor cursor) {
ArrayList<Program> programsList = new ArrayList<Program>();
SparseArrayCompat<Channel> channelMap = new SparseArrayCompat<Channel>();
if(cursor != null && !cursor.isClosed() && cursor.moveToFirst() && cursor.getColumnIndex(TvBrowserContentProvider.DATA_KEY_STARTTIME) != -1) {
Calendar test = Calendar.getInstance();
test.add(Calendar.DAY_OF_YEAR, -1);
test.set(Calendar.HOUR_OF_DAY, 0);
test.set(Calendar.MINUTE, 0);
test.set(Calendar.SECOND, 0);
test.set(Calendar.MILLISECOND, 0);
int idColumnIndex = cursor.getColumnIndex(TvBrowserContentProvider.KEY_ID);
int startTimeColumnIndex = cursor.getColumnIndex(TvBrowserContentProvider.DATA_KEY_STARTTIME);
int endTimeColumnIndex = cursor.getColumnIndex(TvBrowserContentProvider.DATA_KEY_ENDTIME);
int titleColumnIndex = cursor.getColumnIndex(TvBrowserContentProvider.DATA_KEY_TITLE);
int shortDescriptionColumnIndex = cursor.getColumnIndex(TvBrowserContentProvider.DATA_KEY_SHORT_DESCRIPTION);
int descriptionColumnIndex = cursor.getColumnIndex(TvBrowserContentProvider.DATA_KEY_DESCRIPTION);
int episodeColumnIndex = cursor.getColumnIndex(TvBrowserContentProvider.DATA_KEY_EPISODE_TITLE);
int channelIdColumnIndex = cursor.getColumnIndex(TvBrowserContentProvider.CHANNEL_KEY_CHANNEL_ID);
do {
int channelId = cursor.getInt(channelIdColumnIndex);
Channel channel = channelMap.get(channelId);
if(channel == null) {
channel = createChannelFromCursor(context, cursor);
if(channel != null) {
channelMap.put(channelId, channel);
}
}
if(channel != null) {
final long startTime = cursor.getLong(startTimeColumnIndex);
if(test.getTimeInMillis() <= startTime) {
final long endTime = cursor.getLong(endTimeColumnIndex);
final String title = cursor.getString(titleColumnIndex);
final String shortDescription = cursor.getString(shortDescriptionColumnIndex);
final String description = cursor.getString(descriptionColumnIndex);
final String episodeTitle = cursor.getString(episodeColumnIndex);
programsList.add(new Program(cursor.getLong(idColumnIndex), startTime, endTime, title, shortDescription, description, episodeTitle, channel));
}
}
}while(cursor.moveToNext());
}
return programsList.isEmpty() ? null : programsList.toArray(new Program[programsList.size()]);
}
public static final Channel createChannelFromCursor(Context context, Cursor cursor) {
Channel result = null;
if(IOUtils.isDatabaseAccessible(context) && cursor != null && !cursor.isClosed() && cursor.moveToFirst()) {
int nameColumn = cursor.getColumnIndex(TvBrowserContentProvider.CHANNEL_KEY_NAME);
if(nameColumn == -1) {
int channelId = cursor.getInt(cursor.getColumnIndex(TvBrowserContentProvider.CHANNEL_KEY_CHANNEL_ID));
if(channelId >= 0) {
Cursor channelCursor = context.getContentResolver().query(TvBrowserContentProvider.CONTENT_URI_CHANNELS, null, TvBrowserContentProvider.KEY_ID + "=" + channelId, null, null);
try {
if(IOUtils.prepareAccessFirst(channelCursor)) {
result = new Channel(channelCursor.getInt(channelCursor.getColumnIndex(TvBrowserContentProvider.KEY_ID)), channelCursor.getString(channelCursor.getColumnIndex(TvBrowserContentProvider.CHANNEL_KEY_NAME)), channelCursor.getBlob(channelCursor.getColumnIndex(TvBrowserContentProvider.CHANNEL_KEY_LOGO)));
}
}finally {
IOUtils.close(channelCursor);
}
}
}
else {
int startTimeColumn = cursor.getColumnIndex(TvBrowserContentProvider.DATA_KEY_STARTTIME);
String keyColumnName = TvBrowserContentProvider.KEY_ID;
if(startTimeColumn != -1) {
keyColumnName = TvBrowserContentProvider.CHANNEL_KEY_CHANNEL_ID;
}
result = new Channel(cursor.getInt(cursor.getColumnIndex(keyColumnName)), cursor.getString(nameColumn), cursor.getBlob(cursor.getColumnIndex(TvBrowserContentProvider.CHANNEL_KEY_LOGO)));
}
}
return result;
}
public static final boolean markProgram(Context context, Program program, String pluginId) {
boolean result = false;
if(IOUtils.isDatabaseAccessible(context)) {
final long token = Binder.clearCallingIdentity();
final Cursor programs = context.getContentResolver().query(ContentUris.withAppendedId(TvBrowserContentProvider.CONTENT_URI_DATA, program.getId()), new String[] {TvBrowserContentProvider.DATA_KEY_MARKING_MARKING}, null, null, null);
try {
if(IOUtils.prepareAccessFirst(programs)) {
if(programs.getInt(programs.getColumnIndex(TvBrowserContentProvider.DATA_KEY_MARKING_MARKING)) == 0) {
ContentValues mark = new ContentValues();
mark.put(TvBrowserContentProvider.DATA_KEY_MARKING_MARKING, true);
if(pluginId == null) {
pluginId = "#unknownID";
}
result = markProgram(context, program.getId(), pluginId);
UiUtils.sendMarkingChangedBroadcast(context, program.getId(), false);
}
else {
if(pluginId != null) {
result = markProgram(context, program.getId(), pluginId);
if(result) {
UiUtils.sendMarkingChangedBroadcast(context, program.getId(), true);
}
}
else {
result = true;
}
}
}
}finally {
IOUtils.close(programs);
Binder.restoreCallingIdentity(token);
}
}
return result;
}
public static final boolean unmarkProgram(Context context, Program program, String pluginId) {
boolean result = false;
if(IOUtils.isDatabaseAccessible(context)) {
final long token = Binder.clearCallingIdentity();
Cursor programs = context.getContentResolver().query(ContentUris.withAppendedId(TvBrowserContentProvider.CONTENT_URI_DATA, program.getId()), new String[] {TvBrowserContentProvider.DATA_KEY_MARKING_MARKING}, null, null, null);
try {
if(IOUtils.prepareAccessFirst(programs)) {
if(programs.getInt(programs.getColumnIndex(TvBrowserContentProvider.DATA_KEY_MARKING_MARKING)) == 1 && !PluginHandler.isMarkedByPlugins(program.getId())) {
ContentValues mark = new ContentValues();
mark.put(TvBrowserContentProvider.DATA_KEY_MARKING_MARKING, false);
if(pluginId == null) {
pluginId = "#unknownID";
}
result = unmarkProgram(context, program.getId(), pluginId);
UiUtils.sendMarkingChangedBroadcast(context, program.getId(), false);
}
else {
if(pluginId != null) {
result = unmarkProgram(context, program.getId(), pluginId);
if(result) {
UiUtils.sendMarkingChangedBroadcast(context, program.getId(), true);
}
}
else {
result = true;
}
}
}
}finally {
IOUtils.close(programs);
Binder.restoreCallingIdentity(token);
}
}
return result;
}
public static boolean isMarkedByPluginWithIcon(Context context, long programId, String pluginId) {
boolean marked = false;
SharedPreferences pref = PrefUtils.getSharedPreferences(PrefUtils.TYPE_PREFERENCES_MARKINGS, context);
marked = pref.contains(String.valueOf(programId));
if(marked && pluginId != null) {
marked = pref.getString(String.valueOf(programId), "").contains(pluginId);
}
if(marked && pluginId != null) {
PluginServiceConnection[] plugins = PluginHandler.getAvailablePlugins();
for(PluginServiceConnection plugin : plugins) {
if(pluginId.equals(plugin.getId())) {
if(!plugin.isActivated()) {
marked = false;
}
break;
}
}
}
return marked;
}
public static boolean isMarkedWithIcon(Context context, long programId) {
boolean marked = false;
marked = PrefUtils.getSharedPreferences(PrefUtils.TYPE_PREFERENCES_MARKINGS, context).contains(String.valueOf(programId));
return marked;
}
private static synchronized boolean markProgram(Context context, long programId, String pluginId) {
boolean result = false;
SharedPreferences pref = PrefUtils.getSharedPreferences(PrefUtils.TYPE_PREFERENCES_MARKINGS, context);
String value = pref.getString(String.valueOf(programId), "").trim();
if(!value.contains(pluginId)) {
if(!value.isEmpty()) {
value += ";";
}
else {
ContentValues values = new ContentValues();
values.put(TvBrowserContentProvider.DATA_KEY_MARKING_MARKING, true);
TvBrowserContentProvider.INFORM_FOR_CHANGES = false;
context.getContentResolver().update(ContentUris.withAppendedId(TvBrowserContentProvider.CONTENT_URI_DATA, programId), values, null, null);
TvBrowserContentProvider.INFORM_FOR_CHANGES = true;
}
value += pluginId;
String[] parts = value.split(";");
Arrays.sort(parts);
value = TextUtils.join(";", parts);
Editor edit = pref.edit();
edit.putString(String.valueOf(programId), value);
result = edit.commit();
}
else {
result = true;
}
return result;
}
private static synchronized boolean unmarkProgram(Context context, long programId, String pluginId) {
boolean result = false;
SharedPreferences pref = PrefUtils.getSharedPreferences(PrefUtils.TYPE_PREFERENCES_MARKINGS, context);
String value = pref.getString(String.valueOf(programId), null).trim();
if(value != null) {
value = value.replaceAll(pluginId+";*", "").replaceAll(";{2,}", "");
Editor edit = pref.edit();
if(value.trim().isEmpty() || value.equals(";")) {
edit.remove(String.valueOf(programId));
ContentValues values = new ContentValues();
values.put(TvBrowserContentProvider.DATA_KEY_MARKING_MARKING, false);
TvBrowserContentProvider.INFORM_FOR_CHANGES = false;
context.getContentResolver().update(ContentUris.withAppendedId(TvBrowserContentProvider.CONTENT_URI_DATA, programId), values, null, null);
TvBrowserContentProvider.INFORM_FOR_CHANGES = true;
}
else {
edit.putString(String.valueOf(programId), value);
}
result = edit.commit();
}
else {
result = true;
}
return result;
}
public static final void handleFirstAndLastKnownProgramId(Context context, long firstProgramId, long lastProgramId) {
handleKnownIdInternal(context, firstProgramId, lastProgramId, PrefUtils.TYPE_PREFERENCES_MARKINGS);
handleKnownIdInternal(context, firstProgramId, lastProgramId, PrefUtils.TYPE_PREFERENCES_MARKING_REMINDERS);
handleKnownIdInternal(context, firstProgramId, lastProgramId, PrefUtils.TYPE_PREFERENCES_MARKING_SYNC);
}
private static final void handleKnownIdInternal(Context context, long firstProgramId, long lastProgramId, int prefType) {
SharedPreferences pref = PrefUtils.getSharedPreferences(prefType, context);
Editor edit = pref.edit();
if(firstProgramId == -1) {
edit.clear();
}
else {
Map<String,?> prefMap = pref.getAll();
Set<String> keys = prefMap.keySet();
for(String key : keys) {
Long id = Long.parseLong(key);
if(id < firstProgramId || (lastProgramId > firstProgramId && id > lastProgramId)) {
edit.remove(key);
}
}
}
edit.commit();
}
private static ImageSpan ICON_REMINDER;
private static ImageSpan ICON_SYNC;
private static final String KEY_ICON_REMINDER = "org.tvbrowser.tvbrowser.REMINDER";
private static final String KEY_ICON_SYNC = "org.tvbrowser.tvbrowser.SYNC";
public static void resetReminderAndSyncMarkIcon(boolean isDarkTheme) {
if(!isDarkTheme) {
if(ICON_REMINDER != null) {
ICON_REMINDER.getDrawable().setColorFilter(new PorterDuffColorFilter(Color.BLACK, PorterDuff.Mode.MULTIPLY));
}
if(ICON_SYNC != null) {
ICON_SYNC.getDrawable().setColorFilter(new PorterDuffColorFilter(Color.BLACK, PorterDuff.Mode.MULTIPLY));
}
}
else {
if(ICON_REMINDER != null) {
ICON_REMINDER.getDrawable().setColorFilter(null);
}
if(ICON_SYNC != null) {
ICON_SYNC.getDrawable().setColorFilter(null);
}
}
}
public static CharSequence getMarkIcons(Context context, long programId, String title) {
CharSequence result = title;
if(PrefUtils.getBooleanValue(R.string.PREF_MARK_ICON_SHOW, R.bool.pref_mark_icon_show_default)) {
SpannableStringBuilder markIcons = new SpannableStringBuilder();
int favoriteMarkIconType = Favorite.getFavoriteMarkIconType(context, programId);
if(favoriteMarkIconType >= 1) {
markIcons.append(" ");
markIcons.append(Favorite.KEY_MARKING_ICON);
markIcons.setSpan(Favorite.getMarkIcon(context, favoriteMarkIconType), markIcons.length()-Favorite.KEY_MARKING_ICON.length(), markIcons.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if(PrefUtils.getSharedPreferences(PrefUtils.TYPE_PREFERENCES_MARKING_REMINDERS, context).contains(String.valueOf(programId))) {
markIcons.append(" ");
markIcons.append(KEY_ICON_REMINDER);
if(ICON_REMINDER == null) {
ICON_REMINDER = UiUtils.createImageSpan(context, R.drawable.ic_action_alarms);
}
markIcons.setSpan(ICON_REMINDER, markIcons.length()-KEY_ICON_REMINDER.length(), markIcons.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if(PrefUtils.getSharedPreferences(PrefUtils.TYPE_PREFERENCES_MARKING_SYNC, context).contains(String.valueOf(programId))) {
markIcons.append(" ");
markIcons.append(KEY_ICON_SYNC);
if(ICON_SYNC == null) {
ICON_SYNC = UiUtils.createImageSpan(context, R.drawable.ic_action_cloud);
}
markIcons.setSpan(ICON_SYNC, markIcons.length()-KEY_ICON_SYNC.length(), markIcons.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
SharedPreferences pref = PrefUtils.getSharedPreferences(PrefUtils.TYPE_PREFERENCES_MARKINGS, context);
String value = pref.getString(String.valueOf(programId), null);
if(value != null && !value.trim().isEmpty()) {
String[] plugins = value.split(";");
for(String plugin : plugins) {
PluginServiceConnection connection = PluginHandler.getConnectionForId(plugin);
if(connection != null && connection.isActivated()) {
ImageSpan icon = connection.getPluginMarkIcon();
if(icon != null) {
markIcons.append(" ");
markIcons.append(plugin);
markIcons.setSpan(icon, markIcons.length()-plugin.length(), markIcons.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
}
}
if(markIcons.length() > 0) {
markIcons.insert(0, title);
result = markIcons;
}
}
return result;
}
public static final WhereClause getPluginMarkingsSelection(Context context) {
WhereClause result = new WhereClause(TvBrowserContentProvider.DATA_KEY_MARKING_MARKING, null);
if(context != null) {
SharedPreferences pref = PrefUtils.getSharedPreferences(PrefUtils.TYPE_PREFERENCES_MARKINGS, context);
Map<String,?> prefMap = pref.getAll();
Set<String> keySet = prefMap.keySet();
if(keySet.size() < 500) {
StringBuilder where = new StringBuilder();
String[] selectionArgs = new String[prefMap.size()];
Iterator<String> keys = keySet.iterator();
for(int i=0; i < keySet.size(); i++) {
if(where.length() > 0) {
where.append(", ");
}
where.append("?");
selectionArgs[i] = keys.next();
}
if(where.length() > 0) {
where.insert(0, TvBrowserContentProvider.KEY_ID + " IN ( ");
where.append(" ) ");
result = new WhereClause(where.toString(), selectionArgs);
}
}
}
return result;
}
private static BroadcastReceiver mRefreshReceiver;
private static ArrayList<MarkingsUpdateListener> mMarkingsListener;
public static final void registerMarkingsListener(Context context, MarkingsUpdateListener listener) {
if(mRefreshReceiver == null) {
if(mMarkingsListener != null) {
mMarkingsListener.clear();
}
else {
mMarkingsListener = new ArrayList<MarkingsUpdateListener>();
}
mRefreshReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
//if(intent.getBooleanExtra(SettingConstants.EXTRA_MARKINGS_ONLY_UPDATE,false)) {
if(mMarkingsListener != null) {
for(MarkingsUpdateListener listener : mMarkingsListener) {
listener.refreshMarkings();
}
}
//}
}
};
IntentFilter filter = new IntentFilter(SettingConstants.MARKINGS_CHANGED);
LocalBroadcastManager.getInstance(context.getApplicationContext()).registerReceiver(mRefreshReceiver, filter);
listener.refreshMarkings();
}
mMarkingsListener.add(listener);
}
public static final void unregisterMarkingsListener(Context context, MarkingsUpdateListener listener) {
if(mMarkingsListener != null && !mMarkingsListener.isEmpty()) {
mMarkingsListener.remove(listener);
if(mMarkingsListener.isEmpty()) {
LocalBroadcastManager.getInstance(context.getApplicationContext()).unregisterReceiver(mRefreshReceiver);
mRefreshReceiver = null;
mMarkingsListener = null;
}
}
}
public static final void addReminderId(Context context, long programId) {
addMarkId(context, programId, PrefUtils.TYPE_PREFERENCES_MARKING_REMINDERS);
}
public static final void addReminderIds(Context context, ArrayList<String> idList) {
addMarkIds(context, idList, PrefUtils.TYPE_PREFERENCES_MARKING_REMINDERS);
}
public static final void removeReminderId(Context context, long programId) {
removeMarkId(context, programId, PrefUtils.TYPE_PREFERENCES_MARKING_REMINDERS);
}
public static final void removeReminderIds(Context context, ArrayList<String> idList) {
removeMarkIds(context, idList, PrefUtils.TYPE_PREFERENCES_MARKING_REMINDERS);
}
public static final void addSyncIds(Context context, ArrayList<String> idList) {
addMarkIds(context, idList, PrefUtils.TYPE_PREFERENCES_MARKING_SYNC);
}
public static final void removeSyncId(Context context, long programId) {
removeMarkId(context, programId, PrefUtils.TYPE_PREFERENCES_MARKING_SYNC);
}
private static final void addMarkId(Context context, long programId, int type) {
Editor edit = PrefUtils.getSharedPreferences(type, context).edit();
edit.putBoolean(String.valueOf(programId), true);
edit.commit();
}
private static final void addMarkIds(Context context, ArrayList<String> idList, int type) {
Editor edit = PrefUtils.getSharedPreferences(type, context).edit();
for(String programId : idList) {
edit.putBoolean(programId, true);
}
edit.commit();
}
private static final void removeMarkId(Context context, long programId, int type) {
Editor edit = PrefUtils.getSharedPreferences(type, context).edit();
edit.remove(String.valueOf(programId));
edit.commit();
}
private static final void removeMarkIds(Context context, ArrayList<String> idList, int type) {
Editor edit = PrefUtils.getSharedPreferences(type, context).edit();
for(String programId : idList) {
edit.remove(programId);
}
edit.commit();
}
}