package de.qspool.clementineremote.backend.database;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.AsyncTask;
import java.util.LinkedList;
import de.qspool.clementineremote.R;
import de.qspool.clementineremote.backend.listener.OnSongSelectFinishedListener;
public abstract class DynamicSongQuery {
protected Context mContext;
private SQLiteDatabase mDatabase;
private int mMaxLevels;
private int mLevel;
private String[] mSelectedFields;
private String[] mSelection = new String[] {};
private String mSort;
private LinkedList<OnSongSelectFinishedListener> listeners = new LinkedList<>();
abstract protected String[] getSelectedFields();
abstract protected String getSorting();
abstract protected String getTable();
abstract protected SQLiteDatabase getReadableDatabase();
abstract public String getMatchesSubQuery(String match);
protected String getHiddenWhere() { return ""; }
public DynamicSongQuery(Context context) {
mContext = context;
mSelectedFields = getSelectedFields();
mSort = getSorting();
mMaxLevels = mSelectedFields.length;
}
public void openDatabase() {
mDatabase = getReadableDatabase();
}
public int getMaxLevels() {
return mMaxLevels;
}
public Cursor buildQuery(String fromTable) {
Cursor c1 = null;
StringBuilder query = new StringBuilder();
query.append("SELECT ");
query.append("ROWID as _id"); // _id for ListView
for (String field : mSelectedFields) {
query.append(", ");
query.append(field);
}
query.append(", cast(filename as TEXT) "); // URL
query.append(", artist, album ");
query.append(" FROM ");
query.append(fromTable);
// Append where clause
String hiddenWhere = getHiddenWhere();
if (mSelection.length > 0) {
query.append(" WHERE ");
for (int i = 0; i < mSelection.length; i++) {
query.append(mSelectedFields[i]);
query.append(" = ? ");
if (i < mSelection.length - 1)
query.append(" and ");
}
if (!hiddenWhere.isEmpty()) {
query.append(" and ");
query.append(hiddenWhere);
}
} else if (!hiddenWhere.isEmpty()) {
query.append(" WHERE ");
query.append(hiddenWhere);
}
if (isTitleLevel()) {
query.append(" ORDER BY ");
query.append(" album, disc, track ");
query.append(mSort);
} else {
query.append(" GROUP BY ");
query.append(mSelectedFields[mLevel]);
query.append(" ORDER BY ");
query.append(mSelectedFields[mLevel]);
query.append(" ");
query.append(mSort);
}
try {
c1 = mDatabase.rawQuery(query.toString(), mSelection);
} catch (Exception e) {
System.out.println("DATABASE ERROR " + e);
}
return c1;
}
private int countItems(String[] selection) {
int items = 0;
StringBuilder query = new StringBuilder();
query.append("SELECT ");
query.append(" COUNT(DISTINCT(");
query.append(mSelectedFields[selection.length]);
query.append("))");
query.append(" FROM ");
query.append(getTable());
String hiddenWhere = getHiddenWhere();
if (selection.length > 0) {
query.append(" WHERE ");
for (int i = 0; i < selection.length; i++) {
query.append(mSelectedFields[i]);
query.append(" = ? ");
if (i < selection.length - 1)
query.append(" and ");
}
if (!hiddenWhere.isEmpty()) {
query.append(" and ");
query.append(hiddenWhere);
}
} else if (!hiddenWhere.isEmpty()) {
query.append(" WHERE ");
query.append(hiddenWhere);
}
Cursor c = mDatabase.rawQuery(query.toString(), selection);
if (c != null && c.moveToFirst()) {
items = c.getInt(0);
c.close();
}
return items;
}
public SongSelectItem fillSongSelectItem(Cursor c) {
SongSelectItem item = new SongSelectItem();
String unknownItem = mContext.getString(R.string.unknown);
String[] values = new String[mSelectedFields.length];
for (int i=0;i<mSelectedFields.length;i++) {
values[i] = c.getString(i+1); // 0 is _id, selected fields begin at index 1!
}
// Get default fields
String url = c.getString(mSelectedFields.length+1);
String artist = c.getString(mSelectedFields.length+2);
String album = c.getString(mSelectedFields.length+3);
// Fill the selection and list items
String[] selection = new String[mLevel+1];
for (int i=0;i<=mLevel;i++) {
selection[i] = values[i];
}
item.setSelection(selection);
item.setUrl(url);
if (selection[mLevel].isEmpty()) {
item.setListTitle(unknownItem);
} else {
item.setListTitle(selection[mLevel]);
if (mSelectedFields[mLevel].equals("year")) {
item.setListTitle(selection[mLevel] + " - " + album);
}
}
if (isTitleLevel()) {
item.setListSubtitle((artist.isEmpty() ? unknownItem : artist)
+ " / " + (album.isEmpty() ? unknownItem : album));
} else {
int count = countItems(item.getSelection());
item.setListSubtitle(
mContext.getResources().getQuantityString(R.plurals.number_items,
count, count));
}
item.setLevel(mLevel);
return item;
}
private boolean isTitleLevel() {
return mLevel == mMaxLevels-1;
}
public void addOnLibrarySelectFinishedListener(
OnSongSelectFinishedListener l) {
listeners.add(l);
}
public Cursor buildQuery() {
return buildQuery(getTable());
}
public void selectDataAsync() {
new AsyncQueryTask().execute();
}
/**
* Select the data and returns a list of items
*
* @return The list of items
*/
public LinkedList<SongSelectItem> selectData() {
LinkedList<SongSelectItem> itemList = new LinkedList<>();
Cursor c = buildQuery();
if (c != null && c.getCount() != 0) {
c.moveToFirst();
do {
itemList.add(fillSongSelectItem(c));
} while (c.moveToNext());
c.close();
}
return itemList;
}
public int getLevel() {
return mLevel;
}
public void setLevel(int level) {
mLevel = level;
}
public String[] getSelection() {
return mSelection;
}
public void setSelection(String[] selection) {
mSelection = selection;
}
private class AsyncQueryTask extends
AsyncTask<Void, Void, LinkedList<SongSelectItem>> {
@Override
protected LinkedList<SongSelectItem> doInBackground(
Void... params) {
return selectData();
}
@Override
protected void onPostExecute(LinkedList<SongSelectItem> items) {
for (OnSongSelectFinishedListener l : listeners) {
l.OnSongSelectFinished(items);
}
}
}
}