/* * Copyright (C) 2015 Simon Vig Therkildsen * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.simonvt.cathode.provider; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.net.Uri; import javax.inject.Inject; import net.simonvt.cathode.CathodeApp; import net.simonvt.cathode.api.entity.Season; import net.simonvt.cathode.provider.DatabaseContract.EpisodeColumns; import net.simonvt.cathode.provider.DatabaseContract.SeasonColumns; import net.simonvt.cathode.provider.ProviderSchematic.Seasons; import net.simonvt.schematic.Cursors; public final class SeasonDatabaseHelper { private static volatile SeasonDatabaseHelper instance; public static SeasonDatabaseHelper getInstance(Context context) { if (instance == null) { synchronized (SeasonDatabaseHelper.class) { if (instance == null) { instance = new SeasonDatabaseHelper(context.getApplicationContext()); } } } return instance; } private static final Object LOCK_ID = new Object(); @Inject ShowDatabaseHelper showHelper; private Context context; private ContentResolver resolver; private SeasonDatabaseHelper(Context context) { this.context = context; resolver = context.getContentResolver(); CathodeApp.inject(context, this); } public long getId(long showId, int season) { synchronized (LOCK_ID) { Cursor c = null; try { c = resolver.query(Seasons.SEASONS, new String[] { SeasonColumns.ID, }, SeasonColumns.SHOW_ID + "=? AND " + SeasonColumns.SEASON + "=?", new String[] { String.valueOf(showId), String.valueOf(season), }, null); return !c.moveToFirst() ? -1L : Cursors.getLong(c, SeasonColumns.ID); } finally { if (c != null) c.close(); } } } public int getNumber(long seasonId) { Cursor c = null; try { c = resolver.query(Seasons.withId(seasonId), new String[] { SeasonColumns.SEASON, }, null, null, null); if (c.moveToFirst()) { return c.getInt(0); } return -1; } finally { if (c != null) c.close(); } } public long getShowId(long seasonId) { Cursor c = null; try { c = resolver.query(Seasons.withId(seasonId), new String[] { SeasonColumns.SHOW_ID, }, null, null, null); if (c.moveToFirst()) { return c.getLong(0); } return -1L; } finally { if (c != null) c.close(); } } public static final class IdResult { public long id; public boolean didCreate; public IdResult(long id, boolean didCreate) { this.id = id; this.didCreate = didCreate; } } public IdResult getIdOrCreate(long showId, int season) { synchronized (LOCK_ID) { long id = getId(showId, season); if (id == -1L) { id = create(showId, season); return new IdResult(id, true); } else { return new IdResult(id, false); } } } private long create(long showId, int season) { ContentValues cv = new ContentValues(); cv.put(SeasonColumns.SHOW_ID, showId); cv.put(SeasonColumns.SEASON, season); cv.put(SeasonColumns.NEEDS_SYNC, 1); Uri uri = resolver.insert(Seasons.SEASONS, cv); return Seasons.getId(uri); } public long updateSeason(long showId, Season season) { IdResult result = getIdOrCreate(showId, season.getNumber()); final long seasonId = result.id; ContentValues cv = getSeasonCVs(season); resolver.update(Seasons.withId(seasonId), cv, null, null); return seasonId; } public void setWatched(long traktId, int season, boolean watched, long watchedAt) { final long showId = showHelper.getId(traktId); final long seasonId = getId(showId, season); if (seasonId == -1L) { return; } setWatched(showId, seasonId, watched, watchedAt); } public void setWatched(long showId, long seasonId, boolean watched, long watchedAt) { Cursor episodes = resolver.query(ProviderSchematic.Episodes.fromSeason(seasonId), new String[] { EpisodeColumns.ID, EpisodeColumns.WATCHED, }, null, null, null); ContentValues cv = new ContentValues(); cv.put(EpisodeColumns.WATCHED, watched); while (episodes.moveToNext()) { final boolean isWatched = Cursors.getBoolean(episodes, EpisodeColumns.WATCHED); if (isWatched != watched) { final long episodeId = Cursors.getLong(episodes, EpisodeColumns.ID); resolver.update(ProviderSchematic.Episodes.withId(episodeId), cv, null, null); } } if (watched) { Cursor c = resolver.query(ProviderSchematic.Shows.withId(showId), new String[] { DatabaseContract.ShowColumns.LAST_WATCHED_AT, }, null, null, null); c.moveToFirst(); final long lastWatched = Cursors.getLong(c, DatabaseContract.ShowColumns.LAST_WATCHED_AT); c.close(); if (watchedAt > lastWatched) { cv = new ContentValues(); cv.put(DatabaseContract.ShowColumns.LAST_WATCHED_AT, watchedAt); resolver.update(ProviderSchematic.Shows.withId(showId), cv, null, null); } } episodes.close(); } public void setIsInCollection(long showTraktId, int seasonNumber, boolean collected, long collectedAt) { final long showId = showHelper.getId(showTraktId); final long seasonId = getId(showId, seasonNumber); setIsInCollection(seasonId, collected, collectedAt); } public void setIsInCollection(long seasonId, boolean collected, long collectedAt) { Cursor episodes = resolver.query(ProviderSchematic.Episodes.fromSeason(seasonId), new String[] { EpisodeColumns.ID, EpisodeColumns.IN_COLLECTION, }, null, null, null); ContentValues cv = new ContentValues(); cv.put(EpisodeColumns.IN_COLLECTION, collected); cv.put(EpisodeColumns.COLLECTED_AT, collectedAt); while (episodes.moveToNext()) { final boolean isCollected = Cursors.getBoolean(episodes, EpisodeColumns.IN_COLLECTION); if (isCollected != collected) { final long episodeId = Cursors.getLong(episodes, EpisodeColumns.ID); resolver.update(ProviderSchematic.Episodes.withId(episodeId), cv, null, null); } } episodes.close(); } private static ContentValues getSeasonCVs(Season season) { ContentValues cv = new ContentValues(); cv.put(SeasonColumns.NEEDS_SYNC, 0); cv.put(SeasonColumns.SEASON, season.getNumber()); cv.put(SeasonColumns.TVDB_ID, season.getIds().getTvdb()); cv.put(SeasonColumns.TMDB_ID, season.getIds().getTmdb()); cv.put(SeasonColumns.TVRAGE_ID, season.getIds().getTvrage()); if (season.getRating() != null) { cv.put(SeasonColumns.RATING, season.getRating()); } if (season.getVotes() != null) { cv.put(SeasonColumns.VOTES, season.getVotes()); } return cv; } }