1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.tv.dvr.provider;
18
19import android.content.ContentValues;
20import android.content.Context;
21import android.database.Cursor;
22import android.database.sqlite.SQLiteDatabase;
23import android.database.sqlite.SQLiteOpenHelper;
24import android.database.sqlite.SQLiteQueryBuilder;
25import android.util.Log;
26
27import com.android.tv.dvr.ScheduledRecording;
28import com.android.tv.dvr.provider.DvrContract.Recordings;
29
30import java.util.ArrayList;
31import java.util.List;
32
33/**
34 * A data class for one recorded contents.
35 */
36public class DvrDatabaseHelper extends SQLiteOpenHelper {
37    private static final String TAG = "DvrDatabaseHelper";
38    private static final boolean DEBUG = true;
39
40    private static final int DATABASE_VERSION = 4;
41    private static final String DB_NAME = "dvr.db";
42
43    private static final String SQL_CREATE_RECORDINGS =
44            "CREATE TABLE " + Recordings.TABLE_NAME + "("
45            + Recordings._ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
46            + Recordings.COLUMN_PRIORITY + " INTEGER DEFAULT " + Long.MAX_VALUE + ","
47            + Recordings.COLUMN_TYPE + " TEXT NOT NULL,"
48            + Recordings.COLUMN_CHANNEL_ID + " INTEGER NOT NULL,"
49            + Recordings.COLUMN_PROGRAM_ID + " INTEGER ,"
50            + Recordings.COLUMN_START_TIME_UTC_MILLIS + " INTEGER NOT NULL,"
51            + Recordings.COLUMN_END_TIME_UTC_MILLIS + " INTEGER NOT NULL,"
52            + Recordings.COLUMN_STATE + " TEXT NOT NULL)";
53
54    private static final String SQL_DROP_RECORDINGS = "DROP TABLE IF EXISTS "
55            + Recordings.TABLE_NAME;
56    public static final String WHERE_RECORDING_ID_EQUALS = Recordings._ID + " = ?";
57
58    public DvrDatabaseHelper(Context context) {
59        super(context.getApplicationContext(), DB_NAME, null, DATABASE_VERSION);
60    }
61
62    @Override
63    public void onConfigure(SQLiteDatabase db) {
64        db.setForeignKeyConstraintsEnabled(true);
65    }
66
67    @Override
68    public void onCreate(SQLiteDatabase db) {
69        if (DEBUG) Log.d(TAG, "Executing SQL: " + SQL_CREATE_RECORDINGS);
70        db.execSQL(SQL_CREATE_RECORDINGS);
71    }
72
73    @Override
74    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
75        if (DEBUG) Log.d(TAG, "Executing SQL: " + SQL_DROP_RECORDINGS);
76        db.execSQL(SQL_DROP_RECORDINGS);
77        onCreate(db);
78    }
79
80    /**
81     * Handles the query request and returns a {@link Cursor}.
82     */
83    public Cursor query(String tableName, String[] projections) {
84        SQLiteDatabase db = getReadableDatabase();
85        SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
86        builder.setTables(tableName);
87        return builder.query(db, projections, null, null, null, null, null);
88    }
89
90    /**
91     * Inserts recordings.
92     *
93     * @return The list of recordings with id set.  The id will be -1 if there was an error.
94     */
95    public List<ScheduledRecording> insertRecordings(ScheduledRecording... scheduledRecordings) {
96        updateChannelsFromRecordings(scheduledRecordings);
97
98        SQLiteDatabase db = getReadableDatabase();
99        List<ScheduledRecording> results = new ArrayList<>();
100        for (ScheduledRecording r : scheduledRecordings) {
101            ContentValues values = ScheduledRecording.toContentValues(r);
102            long id = db.insert(Recordings.TABLE_NAME, null, values);
103            results.add(ScheduledRecording.buildFrom(r).setId(id).build());
104        }
105        return results;
106    }
107
108    /**
109     * Update recordings.
110     *
111     * @return The list of row update counts.  The count will be -1 if there was an error or 0
112     * if no match was found.  The count is expected to be exactly 1 for each recording.
113     */
114    public List<Integer> updateRecordings(ScheduledRecording[] scheduledRecordings) {
115        updateChannelsFromRecordings(scheduledRecordings);
116        SQLiteDatabase db = getWritableDatabase();
117        List<Integer> results = new ArrayList<>();
118        for (ScheduledRecording r : scheduledRecordings) {
119            ContentValues values = ScheduledRecording.toContentValues(r);
120            int updated = db.update(Recordings.TABLE_NAME, values, Recordings._ID + " = ?",
121                    new String[] {String.valueOf(r.getId())});
122            results.add(updated);
123        }
124        return results;
125    }
126
127    private void updateChannelsFromRecordings(ScheduledRecording[] scheduledRecordings) {
128       // TODO(DVR) implement/
129       // TODO(DVR) consider not deleting channels instead of keeping a separate table.
130    }
131
132    /**
133     * Delete recordings.
134     *
135     * @return The list of row update counts.  The count will be -1 if there was an error or 0
136     * if no match was found.  The count is expected to be exactly 1 for each recording.
137     */
138    public List<Integer> deleteRecordings(ScheduledRecording[] scheduledRecordings) {
139        SQLiteDatabase db = getWritableDatabase();
140        List<Integer> results = new ArrayList<>();
141        for (ScheduledRecording r : scheduledRecordings) {
142            int deleted = db.delete(Recordings.TABLE_NAME, WHERE_RECORDING_ID_EQUALS,
143                    new String[] {String.valueOf(r.getId())});
144            results.add(deleted);
145        }
146        return results;
147    }
148}
149