package com.kaltura.playersdk.helpers;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import java.util.ArrayList;
import java.util.HashMap;
import static com.kaltura.playersdk.utils.LogUtils.LOGD;
import static com.kaltura.playersdk.utils.LogUtils.LOGE;
/**
* Created by nissimpardo on 26/10/15.
*/
public class CacheSQLHelper extends SQLiteOpenHelper {
private static final int DATABASE_VERSION = 1;
private static final String DATABASE_NAME = "KCache.db";
private static final String TAG = "CacheSQLHelper";
private final String TABLE_NAME = "KCacheTable";
private final String COL_FILEID = "_id";
public static final String COL_ENCODING = "Encoding";
public static final String COL_MIMETYPE = "MimeType";
public static final String COL_LASTUSED = "LastUsed";
public static final String COL_SIZE = "Size";
private SQLiteDatabase mDatabase;
public interface KSQLHelperDeleteListener {
void fileDeleted(String fileId);
}
public CacheSQLHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
String CREATE_PRODUCTS_TABLE = "Create table IF NOT EXISTS " +
TABLE_NAME + "("
+ COL_FILEID + " TEXT," + COL_ENCODING
+ " TEXT," + COL_MIMETYPE + " TEXT," + COL_LASTUSED + " INTEGER," + COL_SIZE + " INTEGER)";
db.execSQL(CREATE_PRODUCTS_TABLE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
onCreate(db);
}
private SQLiteDatabase db() {
// Keep db open.
if (mDatabase == null || !mDatabase.isOpen()) {
synchronized (this) {
if (mDatabase == null || !mDatabase.isOpen()) {
mDatabase = getWritableDatabase();
}
}
}
return mDatabase;
}
@Override
protected void finalize() throws Throwable {
// Finalizers are unpredictable, but Android's CloseGuards use them.
try {
if (mDatabase != null) {
mDatabase.close();
mDatabase = null;
}
} finally {
super.finalize();
}
}
@Override
public synchronized void close() {
if (mDatabase != null) {
mDatabase.close();
mDatabase = null;
}
super.close();
}
public void addFile(String fileId, String mimeType, String encoding) {
ContentValues values = new ContentValues();
values.put(COL_FILEID, fileId);
values.put(COL_MIMETYPE, mimeType);
values.put(COL_ENCODING, encoding);
values.put(COL_LASTUSED, 0);
values.put(COL_SIZE, 0);
try {
if (entryExists(fileId)) {
db().update(TABLE_NAME, values, this.COL_FILEID + "=?", new String[]{fileId});
} else {
db().insert(TABLE_NAME, null, values);
}
} catch (SQLiteException e) {
LOGE(TAG, "Error adding file, fileId=" + fileId);
}
}
private boolean entryExists(String fileId) {
Cursor c = null;
try {
c = db().query(TABLE_NAME, null, this.COL_FILEID + "=?", new String[]{fileId}, null, null, null);
return c.getCount() > 0;
} finally {
quietClose(c);
}
}
public boolean removeFile(String fileId) {
try {
SQLiteDatabase db = db();
db.delete(TABLE_NAME, COL_FILEID + "=?", new String[]{fileId});
db.close();
return true;
} catch (SQLiteException e) {
return false;
}
}
public long cacheSize() {
String query = "SELECT SUM(Size) FROM KCacheTable";
Cursor cursor = null;
long size = 0;
try {
cursor = db().rawQuery(query, null);
if (cursor.moveToFirst()) {
size = cursor.getInt(0);
}
} catch (Exception e) {
LOGE(TAG, "Error getting total cache size", e);
} finally {
quietClose(cursor);
}
return size;
}
public void updateDate(String fileId) {
ContentValues data = new ContentValues();
data.put(COL_LASTUSED, System.currentTimeMillis());
try {
db().update(TABLE_NAME, data, COL_FILEID + "=?", new String[]{fileId});
} catch (SQLiteException e) {
LOGE(TAG, "Error updating entry date", e);
}
}
public void updateFileSize(String fileId, long fileSize) {
ContentValues data = new ContentValues();
data.put(COL_SIZE, fileSize);
data.put(COL_LASTUSED, System.currentTimeMillis());
try {
db().update(TABLE_NAME, data, COL_FILEID + "=?", new String[]{fileId});
} catch (SQLiteException e) {
LOGE(TAG, "Error updating entry size", e);
}
}
private void quietClose(Cursor c) {
try {
if (c != null) {
c.close();
}
} catch (Exception e) {
LOGE(TAG, "Failed closing " + c);
}
}
public long sizeForId(String fileId) {
Cursor cursor = null;
long size = 0;
try {
cursor = db().query(TABLE_NAME, new String[]{COL_SIZE}, COL_FILEID + "=?", new String[]{fileId}, null, null, null);
if (cursor.moveToFirst()) {
size = cursor.getInt(0);
}
} finally {
quietClose(cursor);
}
return size;
}
public void deleteLessUsedFiles(long sizeToDelete, KSQLHelperDeleteListener listener) {
SQLiteDatabase db = db();
ArrayList<String> deletedIds = new ArrayList<>();
Cursor cursor = null;
try {
cursor = db.query(TABLE_NAME, new String[]{COL_FILEID, COL_SIZE}, null, null, null, null, COL_LASTUSED + " DESC");
while (cursor.moveToNext()) {
String fileId = cursor.getString(0);
int size = cursor.getInt(1);
deletedIds.add(fileId);
sizeToDelete -= size;
if (sizeToDelete <= 0) {
break;
}
}
} catch (SQLiteException e) {
LOGE(TAG, "Error getting list of files to delete");
} finally {
quietClose(cursor);
}
for (String fileId : deletedIds) {
try {
db.delete(TABLE_NAME, COL_FILEID + "=?", new String[]{fileId});
listener.fileDeleted(fileId);
} catch (SQLiteException e) {
LOGE(TAG, "Error deleting entry (lessUsed) " + fileId);
}
}
}
public HashMap<String, Object> fetchParamsForFile(String fileId) {
SQLiteDatabase db = db();
Cursor cursor = null;
HashMap<String, Object> params = null;
try {
cursor = db.query(TABLE_NAME, new String[]{COL_FILEID, COL_ENCODING, COL_MIMETYPE}, COL_FILEID + "=?", new String[]{fileId}, null, null, null);
if (cursor.moveToFirst()) {
params = new HashMap<>();
params.put(COL_ENCODING, cursor.getString(1));
params.put(COL_MIMETYPE, cursor.getString(2));
}
} catch (SQLiteException e) {
LOGE(TAG, "Error fetching params for " + fileId);
} finally {
quietClose(cursor);
}
return params;
}
}