/*
* ____.____ __.____ ___ _____
* | | |/ _| | \ / _ \ ______ ______
* | | < | | / / /_\ \\____ \\____ \
* /\__| | | \| | / / | \ |_> > |_> >
* \________|____|__ \______/ \____|__ / __/| __/
* \/ \/|__| |__|
*
* Copyright (c) 2014-2015 Paul "Marunjar" Pretsch
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package org.voidsink.anewjkuapp.provider;
import android.accounts.Account;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import org.voidsink.anewjkuapp.KusssContentContract;
import org.voidsink.anewjkuapp.analytics.Analytics;
import org.voidsink.anewjkuapp.kusss.Assessment;
import org.voidsink.anewjkuapp.kusss.Course;
import org.voidsink.anewjkuapp.kusss.Curriculum;
import org.voidsink.anewjkuapp.kusss.KusssHelper;
import org.voidsink.anewjkuapp.kusss.Term;
import org.voidsink.anewjkuapp.update.ImportAssessmentTask;
import org.voidsink.anewjkuapp.update.ImportCurriculaTask;
import org.voidsink.anewjkuapp.utils.AppUtils;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class KusssContentProvider extends ContentProvider {
private static final int CODE_COURSE = 1;
private static final int CODE_COURSE_ID = 2;
private static final int CODE_EXAM = 3;
private static final int CODE_EXAM_ID = 4;
private static final int CODE_GRADE = 5;
private static final int CODE_GRADE_ID = 6;
private static final int CODE_CURRICULA = 7;
private static final int CODE_CURRICULA_ID = 8;
private static final Comparator<String> TermComparator = new Comparator<String>() {
@Override
public int compare(String lhs, String rhs) {
return rhs.compareTo(lhs);
}
};
private static final UriMatcher sUriMatcher = new UriMatcher(
UriMatcher.NO_MATCH);
// private static final String TAG = KusssContentProvider.class.getSimpleName();
static {
sUriMatcher.addURI(KusssContentContract.AUTHORITY,
KusssContentContract.Course.PATH, CODE_COURSE);
sUriMatcher.addURI(KusssContentContract.AUTHORITY,
KusssContentContract.Course.PATH + "/#", CODE_COURSE_ID);
sUriMatcher.addURI(KusssContentContract.AUTHORITY,
KusssContentContract.Exam.PATH, CODE_EXAM);
sUriMatcher.addURI(KusssContentContract.AUTHORITY,
KusssContentContract.Exam.PATH + "/#", CODE_EXAM_ID);
sUriMatcher.addURI(KusssContentContract.AUTHORITY,
KusssContentContract.Assessment.PATH, CODE_GRADE);
sUriMatcher.addURI(KusssContentContract.AUTHORITY,
KusssContentContract.Assessment.PATH + "/#", CODE_GRADE_ID);
sUriMatcher.addURI(KusssContentContract.AUTHORITY,
KusssContentContract.Curricula.PATH, CODE_CURRICULA);
sUriMatcher.addURI(KusssContentContract.AUTHORITY,
KusssContentContract.Curricula.PATH + "/#", CODE_CURRICULA_ID);
}
@Override
public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {
SQLiteDatabase db = KusssDatabaseHelper.getInstance(getContext()).getWritableDatabase();
String whereIdClause;
int rowsDeleted;
switch (sUriMatcher.match(uri)) {
case CODE_COURSE:
rowsDeleted = db.delete(KusssContentContract.Course.TABLE_NAME,
selection, selectionArgs);
break;
case CODE_EXAM:
rowsDeleted = db.delete(KusssContentContract.Exam.TABLE_NAME,
selection, selectionArgs);
break;
case CODE_GRADE:
rowsDeleted = db.delete(
KusssContentContract.Assessment.TABLE_NAME, selection,
selectionArgs);
break;
case CODE_CURRICULA:
rowsDeleted = db.delete(
KusssContentContract.Curricula.TABLE_NAME, selection,
selectionArgs);
break;
case CODE_COURSE_ID:
whereIdClause = KusssContentContract.Course.COL_ID + "="
+ uri.getLastPathSegment();
if (!TextUtils.isEmpty(selection))
whereIdClause += " AND " + selection;
rowsDeleted = db.delete(KusssContentContract.Course.TABLE_NAME,
whereIdClause, selectionArgs);
break;
case CODE_EXAM_ID:
whereIdClause = KusssContentContract.Exam.COL_ID + "="
+ uri.getLastPathSegment();
if (!TextUtils.isEmpty(selection))
whereIdClause += " AND " + selection;
rowsDeleted = db.delete(KusssContentContract.Exam.TABLE_NAME,
whereIdClause, selectionArgs);
break;
case CODE_GRADE_ID:
whereIdClause = KusssContentContract.Assessment.COL_ID + "="
+ uri.getLastPathSegment();
if (!TextUtils.isEmpty(selection))
whereIdClause += " AND " + selection;
rowsDeleted = db.delete(
KusssContentContract.Assessment.TABLE_NAME, whereIdClause,
selectionArgs);
break;
case CODE_CURRICULA_ID:
whereIdClause = KusssContentContract.Curricula.COL_ID + "="
+ uri.getLastPathSegment();
if (!TextUtils.isEmpty(selection))
whereIdClause += " AND " + selection;
rowsDeleted = db.delete(
KusssContentContract.Curricula.TABLE_NAME, whereIdClause,
selectionArgs);
break;
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
// Notifying the changes, if there are any
if (rowsDeleted != -1)
getContext().getContentResolver().notifyChange(uri, null);
return rowsDeleted;
}
@Override
public String getType(@NonNull Uri uri) {
switch (sUriMatcher.match(uri)) {
case CODE_COURSE:
return KusssContentContract.CONTENT_TYPE_DIR + "/"
+ KusssContentContract.Course.PATH;
case CODE_COURSE_ID:
return KusssContentContract.CONTENT_TYPE_ITEM + "/"
+ KusssContentContract.Course.PATH;
case CODE_EXAM:
return KusssContentContract.CONTENT_TYPE_DIR + "/"
+ KusssContentContract.Exam.PATH;
case CODE_EXAM_ID:
return KusssContentContract.CONTENT_TYPE_ITEM + "/"
+ KusssContentContract.Exam.PATH;
case CODE_GRADE:
return KusssContentContract.CONTENT_TYPE_DIR + "/"
+ KusssContentContract.Assessment.PATH;
case CODE_GRADE_ID:
return KusssContentContract.CONTENT_TYPE_ITEM + "/"
+ KusssContentContract.Assessment.PATH;
case CODE_CURRICULA:
return KusssContentContract.CONTENT_TYPE_DIR + "/"
+ KusssContentContract.Curricula.PATH;
case CODE_CURRICULA_ID:
return KusssContentContract.CONTENT_TYPE_ITEM + "/"
+ KusssContentContract.Curricula.PATH;
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
}
@Override
public Uri insert(@NonNull Uri uri, ContentValues values) {
SQLiteDatabase db = KusssDatabaseHelper.getInstance(getContext()).getWritableDatabase();
switch (sUriMatcher.match(uri)) {
case CODE_COURSE: {
long id = db.insert(KusssContentContract.Course.TABLE_NAME, null,
values);
if (id != -1)
getContext().getContentResolver().notifyChange(uri, null);
return KusssContentContract.Course.CONTENT_URI.buildUpon()
.appendPath(String.valueOf(id)).build();
}
case CODE_EXAM: {
long id = db.insert(KusssContentContract.Exam.TABLE_NAME,
null, values);
if (id != -1)
getContext().getContentResolver().notifyChange(uri, null);
return KusssContentContract.Exam.CONTENT_URI.buildUpon()
.appendPath(String.valueOf(id)).build();
}
case CODE_GRADE: {
long id = db.insert(KusssContentContract.Assessment.TABLE_NAME,
null, values);
if (id != -1)
getContext().getContentResolver().notifyChange(uri, null);
return KusssContentContract.Assessment.CONTENT_URI.buildUpon()
.appendPath(String.valueOf(id)).build();
}
case CODE_CURRICULA: {
long id = db.insert(KusssContentContract.Curricula.TABLE_NAME,
null, values);
if (id != -1)
getContext().getContentResolver().notifyChange(uri, null);
return KusssContentContract.Curricula.CONTENT_URI.buildUpon()
.appendPath(String.valueOf(id)).build();
}
default: {
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
}
}
@Override
public boolean onCreate() {
return true;
}
@Override
public Cursor query(@NonNull Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteDatabase db = KusssDatabaseHelper.getInstance(getContext()).getReadableDatabase();
SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
/*
* Choose the table to query and a sort order based on the code returned
* for the incoming URI. Here, too, only the statements for table 3 are
* shown.
*/
switch (sUriMatcher.match(uri)) {
case CODE_COURSE_ID:
builder.appendWhere(KusssContentContract.Course.COL_ID + "="
+ uri.getLastPathSegment());
case CODE_COURSE:
if (TextUtils.isEmpty(sortOrder))
sortOrder = KusssContentContract.Course.COL_ID + " ASC";
builder.setTables(KusssContentContract.Course.TABLE_NAME);
return builder.query(db, projection, selection, selectionArgs,
null, null, sortOrder);
case CODE_EXAM_ID:
builder.appendWhere(KusssContentContract.Exam.COL_ID + "="
+ uri.getLastPathSegment());
case CODE_EXAM:
if (TextUtils.isEmpty(sortOrder))
sortOrder = KusssContentContract.Exam.COL_ID + " ASC";
builder.setTables(KusssContentContract.Exam.TABLE_NAME);
return builder.query(db, projection, selection, selectionArgs,
null, null, sortOrder);
case CODE_GRADE_ID:
builder.appendWhere(KusssContentContract.Assessment.COL_ID + "="
+ uri.getLastPathSegment());
case CODE_GRADE:
if (TextUtils.isEmpty(sortOrder))
sortOrder = KusssContentContract.Assessment.COL_ID + " ASC";
builder.setTables(KusssContentContract.Assessment.TABLE_NAME);
return builder.query(db, projection, selection, selectionArgs,
null, null, sortOrder);
case CODE_CURRICULA_ID:
builder.appendWhere(KusssContentContract.Curricula.COL_ID + "="
+ uri.getLastPathSegment());
case CODE_CURRICULA:
if (TextUtils.isEmpty(sortOrder))
sortOrder = KusssContentContract.Curricula.COL_ID + " ASC";
builder.setTables(KusssContentContract.Curricula.TABLE_NAME);
return builder.query(db, projection, selection, selectionArgs,
null, null, sortOrder);
default:
throw new IllegalArgumentException("URI " + uri
+ " is not supported.");
}
}
@Override
public int update(@NonNull Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
SQLiteDatabase db = KusssDatabaseHelper.getInstance(getContext()).getWritableDatabase();
switch (sUriMatcher.match(uri)) {
case CODE_COURSE: {
return db.update(KusssContentContract.Course.TABLE_NAME, values,
selection, selectionArgs);
}
case CODE_EXAM: {
return db.update(KusssContentContract.Exam.TABLE_NAME, values,
selection, selectionArgs);
}
case CODE_GRADE: {
return db.update(KusssContentContract.Assessment.TABLE_NAME,
values, selection, selectionArgs);
}
case CODE_CURRICULA: {
return db.update(KusssContentContract.Curricula.TABLE_NAME,
values, selection, selectionArgs);
}
case CODE_COURSE_ID: {
String whereIdClause = KusssContentContract.Course.COL_ID + "="
+ uri.getLastPathSegment();
if (!TextUtils.isEmpty(selection))
whereIdClause += " AND " + selection;
return db.update(KusssContentContract.Course.TABLE_NAME, values,
whereIdClause, selectionArgs);
}
case CODE_EXAM_ID: {
String whereIdClause = KusssContentContract.Exam.COL_ID + "="
+ uri.getLastPathSegment();
if (!TextUtils.isEmpty(selection))
whereIdClause += " AND " + selection;
return db.update(KusssContentContract.Exam.TABLE_NAME, values,
whereIdClause, selectionArgs);
}
case CODE_GRADE_ID: {
String whereIdClause = KusssContentContract.Assessment.COL_ID + "="
+ uri.getLastPathSegment();
if (!TextUtils.isEmpty(selection))
whereIdClause += " AND " + selection;
return db.update(KusssContentContract.Assessment.TABLE_NAME,
values, whereIdClause, selectionArgs);
}
case CODE_CURRICULA_ID: {
String whereIdClause = KusssContentContract.Curricula.COL_ID + "="
+ uri.getLastPathSegment();
if (!TextUtils.isEmpty(selection))
whereIdClause += " AND " + selection;
return db.update(KusssContentContract.Curricula.TABLE_NAME,
values, whereIdClause, selectionArgs);
}
default:
throw new IllegalArgumentException("URI " + uri
+ " is not supported.");
}
}
public static List<Assessment> getAssessmentsFromCursor(Context context, Cursor data) {
List<Assessment> mAssessments = new ArrayList<>();
if (data != null) {
data.moveToFirst();
data.moveToPrevious();
try {
while (data.moveToNext()) {
mAssessments.add(KusssHelper.createAssessment(data));
}
} catch (ParseException e) {
Analytics.sendException(context, e, false);
mAssessments.clear();
}
}
return mAssessments;
}
private static List<Assessment> getAssessments(Context context) {
List<Assessment> mAssessments = new ArrayList<>();
Account mAccount = AppUtils.getAccount(context);
if (mAccount != null) {
ContentResolver cr = context.getContentResolver();
Cursor c = cr.query(KusssContentContract.Assessment.CONTENT_URI,
ImportAssessmentTask.ASSESSMENT_PROJECTION, null, null,
KusssContentContract.Assessment.TABLE_NAME + "."
+ KusssContentContract.Assessment.COL_TYPE
+ " ASC,"
+ KusssContentContract.Assessment.TABLE_NAME + "."
+ KusssContentContract.Assessment.COL_DATE
+ " DESC");
if (c != null) {
mAssessments = getAssessmentsFromCursor(context, c);
c.close();
}
}
return mAssessments;
}
public static List<Course> getCoursesFromCursor(Context context, Cursor c) {
List<Course> courses = new ArrayList<>();
if (c != null) {
c.moveToFirst();
c.moveToPrevious();
try {
while (c.moveToNext()) {
courses.add(KusssHelper.createCourse(c));
}
} catch (ParseException e) {
Analytics.sendException(context, e, false);
courses.clear();
}
}
return courses;
}
public static List<Curriculum> getCurriculaFromCursor(Context context, Cursor c) {
List<Curriculum> mCurriculum = new ArrayList<>();
if (c != null) {
c.moveToFirst();
c.moveToPrevious();
while (c.moveToNext()) {
mCurriculum.add(KusssHelper.createCurricula(c));
}
AppUtils.sortCurricula(mCurriculum);
}
return mCurriculum;
}
private static List<Curriculum> getCurricula(Context context) {
List<Curriculum> mCurriculum = new ArrayList<>();
Account mAccount = AppUtils.getAccount(context);
if (mAccount != null) {
ContentResolver cr = context.getContentResolver();
Cursor c = cr.query(KusssContentContract.Curricula.CONTENT_URI,
ImportCurriculaTask.CURRICULA_PROJECTION, null, null,
KusssContentContract.Curricula.COL_DT_START + " DESC");
if (c != null) {
mCurriculum = getCurriculaFromCursor(context, c);
c.close();
}
}
return mCurriculum;
}
public static List<Term> getTerms(Context context) {
List<String> terms = new ArrayList<>();
Calendar cal = Calendar.getInstance();
List<Curriculum> mCurriculum = getCurricula(context);
if (mCurriculum == null) {
mCurriculum = new ArrayList<>();
}
if (mCurriculum.size() == 0) {
ExecutorService es = Executors.newSingleThreadExecutor();
try {
es.submit(new ImportCurriculaTask(AppUtils.getAccount(context), context)).get();
} catch (InterruptedException | ExecutionException e) {
Analytics.sendException(context, e, true);
} finally {
es.shutdown();
}
try {
List<Assessment> assessments = getAssessments(context);
Date dtStart = null;
for (Assessment assessment : assessments) {
Date date = assessment.getDate();
if (date != null) {
if (dtStart == null || date.before(dtStart)) {
dtStart = date;
}
}
}
if (dtStart != null) {
// subtract -1 term for sure
cal.setTime(dtStart);
cal.add(Calendar.MONTH, -6);
dtStart = cal.getTime();
mCurriculum.add(new Curriculum(dtStart, null));
}
} catch (Exception e) {
Analytics.sendException(context, e, false);
}
}
// always load current term, subtract -1 term for sure
cal.setTime(new Date());
cal.add(Calendar.MONTH, -6);
mCurriculum.add(new Curriculum(cal.getTime(), null));
if (mCurriculum.size() > 0) {
// calculate terms from curricula duration
cal.setTime(new Date());
cal.add(Calendar.MONTH, 1);
Date then = cal.getTime();
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
int year = 2010;
cal.set(Calendar.YEAR, year);
cal.set(Calendar.MONTH, Calendar.MARCH);
cal.set(Calendar.DAY_OF_MONTH, 1);
Date startSS = cal.getTime(); // 1.3.
cal.set(Calendar.YEAR, year);
cal.set(Calendar.MONTH, Calendar.OCTOBER);
cal.set(Calendar.DAY_OF_MONTH, 1);
Date startWS = cal.getTime(); // 1.10.
while (startSS.before(then) || startWS.before(then)) {
if (startSS.before(then) && dateInRange(startSS, mCurriculum)) {
terms.add(String.format(Locale.GERMAN, "%dS", year));
}
if (startWS.before(then) && dateInRange(startWS, mCurriculum)) {
terms.add(String.format(Locale.GERMAN, "%dW", year));
}
// inc year
year++;
cal.setTime(startSS);
cal.set(Calendar.YEAR, year);
startSS.setTime(cal.getTimeInMillis());
cal.setTime(startWS);
cal.set(Calendar.YEAR, year);
startWS.setTime(cal.getTimeInMillis());
}
}
/*
if (terms.size() == 0) {
// get Terms from Data, may take a little bit longer
}
*/
Collections.sort(terms, TermComparator);
List<Term> objects = new ArrayList<>();
try {
for (String term : terms) {
objects.add(Term.parseTerm(term));
}
} catch (ParseException e) {
Analytics.sendException(context, e, true);
objects.clear();
}
return Collections.unmodifiableList(objects);
}
public static Term getLastTerm(Context c) {
List<Term> terms = getTerms(c);
if (terms.size() == 0) {
return null;
}
return terms.get(0);
}
private static boolean dateInRange(Date date, List<Curriculum> curricula) {
for (Curriculum curriculum : curricula) {
if (curriculum.dateInRange(date)) {
return true;
}
}
return false;
}
}