ca.cmput301f13t03.adventure_datetime.model.StoryDB.java Source code

Java tutorial

Introduction

Here is the source code for ca.cmput301f13t03.adventure_datetime.model.StoryDB.java

Source

/*
 * Copyright (c) 2013 Andrew Fontaine, James Finlay, Jesse Tucker, Jacob Viau, and
 * Evan DeGraff
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

package ca.cmput301f13t03.adventure_datetime.model;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.provider.BaseColumns;
import android.util.Log;
import ca.cmput301f13t03.adventure_datetime.model.Interfaces.ILocalStorage;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import java.lang.reflect.Type;
import java.util.*;

/**
 * The local database containing all stories, fragments, bookmarks, and subscriptions
 *
 * @author Andrew Fontaine
 * @version 1.0
 * @since 28/10/13
 */
public class StoryDB implements BaseColumns, ILocalStorage {

    private static final String TAG = "StoryDB";

    public static final String COLUMN_GUID = "GUID";

    public static final String STORY_TABLE_NAME = "Story";
    public static final String STORY_COLUMN_AUTHOR = "Author";
    public static final String STORY_COLUMN_HEAD_FRAGMENT = "HeadFragment";
    public static final String STORY_COLUMN_TIMESTAMP = "Timestamp";
    public static final String STORY_COLUMN_SYNOPSIS = "Synopsis";
    public static final String STORY_COLUMN_THUMBNAIL = "Thumbnail";
    public static final String STORY_COLUMN_TITLE = "Title";

    public static final String STORYFRAGMENT_TABLE_NAME = "StoryFragment";
    public static final String STORYFRAGMENT_COLUMN_STORYID = "StoryID";
    public static final String STORYFRAGMENT_COLUMN_CONTENT = "Content";
    public static final String STORYFRAGMENT_COLUMN_CHOICES = "Choices";
    public static final String STORYFRAGMENT_COLUMN_IMAGES = "Images";

    public static final String BOOKMARK_TABLE_NAME = "Bookmark";
    public static final String BOOKMARK_COLUMN_STORYID = "StoryID";
    public static final String BOOKMARK_COLUMN_FRAGMENTID = "FragmentID";
    public static final String BOOKMARK_COLUMN_DATE = "Date";

    public static final String AUTHORED_STORY_TABLE_NAME = "AuthoredStory";

    public static final String STORY_IMAGE_TABLE_NAME = "StoryImage";
    public static final String STORY_IMAGE_COLUMN_IMAGE = "Image";

    private StoryDBHelper mDbHelper;

    public StoryDB(Context context) {
        mDbHelper = new StoryDBHelper(context);
    }

    /* (non-Javadoc)
     * @see ca.cmput301f13t03.adventure_datetime.model.ILocalDatabase#getStory(java.util.UUID)
     */
    @Override
    public Story getStory(UUID id) {
        SQLiteDatabase db = mDbHelper.getReadableDatabase();

        Cursor cursor = db.query(STORY_TABLE_NAME,
                new String[] { _ID, COLUMN_GUID, STORY_COLUMN_TITLE, STORY_COLUMN_AUTHOR, STORY_COLUMN_TITLE,
                        STORY_COLUMN_HEAD_FRAGMENT, STORY_COLUMN_SYNOPSIS, STORY_COLUMN_TIMESTAMP,
                        STORY_COLUMN_THUMBNAIL },
                COLUMN_GUID + " = ?", new String[] { id.toString() }, null, null, null, "1");

        Story story;

        if (cursor.moveToFirst()) {
            Log.v(TAG, "Story with UUID " + id + " retrieved");
            story = createStory(cursor);
        } else {
            story = null;
            Log.v(TAG, "No story found");
        }

        cursor.close();
        db.close();
        return story;
    }

    /* (non-Javadoc)
     * @see ca.cmput301f13t03.adventure_datetime.model.ILocalDatabase#getStories()
     */
    @Override
    public ArrayList<Story> getStories() {
        SQLiteDatabase db = mDbHelper.getReadableDatabase();

        Cursor cursor = db.query(STORY_TABLE_NAME,
                new String[] { _ID, COLUMN_GUID, STORY_COLUMN_AUTHOR, STORY_COLUMN_TITLE,
                        STORY_COLUMN_HEAD_FRAGMENT, STORY_COLUMN_SYNOPSIS, STORY_COLUMN_TIMESTAMP,
                        STORY_COLUMN_THUMBNAIL },
                null, null, null, null, null);
        ArrayList<Story> stories = new ArrayList<Story>();

        if (cursor.moveToFirst()) {
            do {
                Log.v(TAG, "Story with id " + cursor.getString(cursor.getColumnIndex(COLUMN_GUID)) + " retrieved");
                stories.add(createStory(cursor));
            } while (cursor.moveToNext());
        }

        Log.v(TAG, stories.size() + " stories retrieved");

        cursor.close();
        db.close();
        return stories;
    }

    /* (non-Javadoc)
     * @see ca.cmput301f13t03.adventure_datetime.model.ILocalDatabase#getStoriesAuthoredBy(java.lang.String)
     */
    @Override
    public ArrayList<Story> getStoriesAuthoredBy(String author) {
        SQLiteDatabase db = mDbHelper.getReadableDatabase();

        Cursor cursor = db.query(STORY_TABLE_NAME,
                new String[] { _ID, COLUMN_GUID, STORY_COLUMN_AUTHOR, STORY_COLUMN_HEAD_FRAGMENT,
                        STORY_COLUMN_SYNOPSIS, STORY_COLUMN_TIMESTAMP, STORY_COLUMN_THUMBNAIL },
                STORY_COLUMN_AUTHOR + " = ?", new String[] { author }, null, null, null);
        ArrayList<Story> stories = new ArrayList<Story>();

        if (cursor.moveToFirst()) {
            do {
                Log.v(TAG, "Story with id " + cursor.getString(cursor.getColumnIndex(COLUMN_GUID)) + " retrieved");
                stories.add(createStory(cursor));
            } while (cursor.moveToNext());
        }

        Log.v(TAG, stories.size() + " stories retrieved");

        cursor.close();
        db.close();
        return stories;
    }

    /* (non-Javadoc)
     * @see ca.cmput301f13t03.adventure_datetime.model.ILocalDatabase#getStoryFragment(java.util.UUID)
     */
    @Override
    public StoryFragment getStoryFragment(UUID id) {
        SQLiteDatabase db = mDbHelper.getReadableDatabase();

        Cursor cursor = db.query(STORYFRAGMENT_TABLE_NAME,
                new String[] { _ID, COLUMN_GUID, STORYFRAGMENT_COLUMN_STORYID, STORYFRAGMENT_COLUMN_CHOICES,
                        STORYFRAGMENT_COLUMN_CONTENT, STORYFRAGMENT_COLUMN_IMAGES },
                COLUMN_GUID + " = ?", new String[] { id.toString() }, null, null, "1");

        StoryFragment frag;
        if (cursor.moveToFirst()) {
            Log.v(TAG, "StoryFragment " + id + " retrieved");
            frag = createStoryFragment(cursor);
        } else {
            frag = null;
            Log.v(TAG, "No fragment found");
        }
        cursor.close();
        db.close();
        return frag;
    }

    /* (non-Javadoc)
     * @see ca.cmput301f13t03.adventure_datetime.model.ILocalDatabase#getStoryFragments(java.util.UUID)
     */
    @Override
    public ArrayList<StoryFragment> getStoryFragments(UUID storyid) {
        SQLiteDatabase db = mDbHelper.getReadableDatabase();

        Cursor cursor = db.query(STORYFRAGMENT_TABLE_NAME,
                new String[] { _ID, COLUMN_GUID, STORYFRAGMENT_COLUMN_STORYID, STORYFRAGMENT_COLUMN_CHOICES,
                        STORYFRAGMENT_COLUMN_CONTENT, STORYFRAGMENT_COLUMN_IMAGES },
                STORYFRAGMENT_COLUMN_STORYID + " = ?", new String[] { storyid.toString() }, null, null, null);

        ArrayList<StoryFragment> fragments = new ArrayList<StoryFragment>();

        if (cursor.moveToFirst()) {
            do {
                Log.v(TAG, "StoryFragment with id " + cursor.getString(cursor.getColumnIndex(COLUMN_GUID))
                        + " retrieved");
                fragments.add(createStoryFragment(cursor));
            } while (cursor.moveToNext());
        }

        Log.v(TAG, fragments.size() + " StoryFragments retrieved");

        cursor.close();
        db.close();
        return fragments;
    }

    private ArrayList<UUID> getStoryFragmentIDs(UUID storyID) {
        SQLiteDatabase db = mDbHelper.getReadableDatabase();

        Cursor cursor = db.query(STORYFRAGMENT_TABLE_NAME, new String[] { COLUMN_GUID },
                STORYFRAGMENT_COLUMN_STORYID + " = ?", new String[] { storyID.toString() }, null, null, null);

        ArrayList<UUID> fragmentIDs = new ArrayList<UUID>();

        if (cursor.moveToFirst()) {
            do {
                Log.v(TAG, "StoryFragment with id " + cursor.getString(cursor.getColumnIndex(COLUMN_GUID))
                        + " retrieved");
                fragmentIDs.add(UUID.fromString(cursor.getString(cursor.getColumnIndex(COLUMN_GUID))));
            } while (cursor.moveToNext());
        }

        Log.v(TAG, fragmentIDs.size() + " StoryFragments retrieved");

        cursor.close();
        db.close();
        return fragmentIDs;
    }

    /* (non-Javadoc)
     * @see ca.cmput301f13t03.adventure_datetime.model.ILocalDatabase#getBookmark(java.util.UUID)
     */
    @Override
    public Bookmark getBookmark(UUID storyid) {
        SQLiteDatabase db = mDbHelper.getReadableDatabase();

        Cursor cursor = db.query(BOOKMARK_TABLE_NAME,
                new String[] { _ID, BOOKMARK_COLUMN_STORYID, BOOKMARK_COLUMN_FRAGMENTID, BOOKMARK_COLUMN_DATE },
                BOOKMARK_COLUMN_STORYID + " = ?", new String[] { storyid.toString() }, null, null, null);

        Bookmark bookmark;

        if (cursor.moveToFirst()) {
            Log.v(TAG, "Bookmark with Story id " + cursor.getString(cursor.getColumnIndex(BOOKMARK_COLUMN_STORYID))
                    + "retrieved");
            bookmark = createBookmark(cursor);
        } else {
            Log.v(TAG, "No bookmark found");
            bookmark = null;
        }

        cursor.close();
        db.close();
        return bookmark;
    }

    /* (non-Javadoc)
     * @see ca.cmput301f13t03.adventure_datetime.model.ILocalDatabase#getAllBookmarks()
     */
    @Override
    public ArrayList<Bookmark> getAllBookmarks() {
        SQLiteDatabase db = mDbHelper.getReadableDatabase();
        Cursor cursor = db.query(BOOKMARK_TABLE_NAME,
                new String[] { BOOKMARK_COLUMN_STORYID, BOOKMARK_COLUMN_FRAGMENTID, BOOKMARK_COLUMN_DATE }, null,
                null, null, null, null);

        ArrayList<Bookmark> bookmarks = new ArrayList<Bookmark>();
        if (cursor.moveToFirst()) {
            do {
                Log.v(TAG, "Bookmark with Story id "
                        + cursor.getString(cursor.getColumnIndex(BOOKMARK_COLUMN_STORYID)) + " retrieved");
                bookmarks.add(createBookmark(cursor));
            } while (cursor.moveToNext());
        }

        Log.v(TAG, bookmarks.size() + " bookmarks retrieved");

        return bookmarks;
    }

    @Override
    public boolean getAuthoredStory(UUID storyId) {
        SQLiteDatabase db = mDbHelper.getReadableDatabase();
        Cursor cursor = db.query(AUTHORED_STORY_TABLE_NAME, new String[] { COLUMN_GUID }, COLUMN_GUID + " = ?",
                new String[] { storyId.toString() }, null, null, null);

        boolean authoredStory = cursor.moveToFirst();
        cursor.close();
        db.close();

        return authoredStory;
    }

    @Override
    public ArrayList<UUID> getAuthoredStories() {
        SQLiteDatabase db = mDbHelper.getReadableDatabase();
        Cursor cursor = db.query(AUTHORED_STORY_TABLE_NAME, new String[] { COLUMN_GUID }, null, null, null, null,
                null);

        ArrayList<UUID> authoredStories = new ArrayList<UUID>();

        if (cursor.moveToFirst()) {
            do {
                authoredStories.add(UUID.fromString(cursor.getString(cursor.getColumnIndex(COLUMN_GUID))));
            } while (cursor.moveToNext());
        }
        cursor.close();
        db.close();

        return authoredStories;
    }

    public Image getImage(UUID imageID) {
        Cursor cursor = getImageCursor(imageID);

        Image image;
        if (cursor.moveToFirst()) {
            image = createImage(cursor);
        } else {
            image = null;
        }

        cursor.close();
        return image;
    }

    private Cursor getImageCursor(UUID imageID) {
        SQLiteDatabase db = mDbHelper.getReadableDatabase();
        return db.query(STORY_IMAGE_TABLE_NAME, new String[] { COLUMN_GUID, STORY_IMAGE_COLUMN_IMAGE },
                COLUMN_GUID + " = ?", new String[] { imageID.toString() }, null, null, null);
    }

    public ArrayList<Image> getImages(ArrayList<UUID> imageIDs) {
        ArrayList<Image> images = new ArrayList<Image>();
        if (imageIDs == null)
            return images;
        Cursor cursor;

        for (UUID imageID : imageIDs) {
            cursor = getImageCursor(imageID);
            if (cursor.moveToFirst())
                images.add(createImage(cursor));
            cursor.close();
        }

        return images;
    }

    /* (non-Javadoc)
     * @see ca.cmput301f13t03.adventure_datetime.model.ILocalDatabase#setBookmark(ca.cmput301f13t03.adventure_datetime.model.Bookmark)
     */
    @Override
    public boolean setBookmark(Bookmark bookmark) {
        SQLiteDatabase db = mDbHelper.getWritableDatabase();

        Cursor cursor = db.query(BOOKMARK_TABLE_NAME,
                new String[] { _ID, BOOKMARK_COLUMN_FRAGMENTID, BOOKMARK_COLUMN_STORYID, BOOKMARK_COLUMN_DATE },
                BOOKMARK_COLUMN_STORYID + " = ?", new String[] { bookmark.getStoryID().toString() }, null, null,
                null);

        ContentValues values = new ContentValues();

        values.put(BOOKMARK_COLUMN_STORYID, bookmark.getStoryID().toString());
        values.put(BOOKMARK_COLUMN_FRAGMENTID, bookmark.getFragmentID().toString());
        values.put(BOOKMARK_COLUMN_DATE, bookmark.getTimestamp() / 1000);

        long updated;
        if (cursor.moveToFirst()) {
            Bookmark bookmark1 = createBookmark(cursor);
            if (bookmark.getTimestamp() > bookmark1.getTimestamp()) {
                updated = db.update(BOOKMARK_TABLE_NAME, values, BOOKMARK_COLUMN_STORYID + " = ?",
                        new String[] { BOOKMARK_COLUMN_STORYID });
                Log.v(TAG, updated + " Bookmarks updated");
                cursor.close();
                db.close();
                return updated == 1;
            }
            Log.v(TAG, "No Bookmarks updated");
            cursor.close();
            db.close();
            return false;
        }
        updated = db.insert(BOOKMARK_TABLE_NAME, null, values);
        Log.v(TAG, updated + " Bookmark inserted");
        cursor.close();
        db.close();
        return updated != -1;
    }

    /* (non-Javadoc)
     * @see ca.cmput301f13t03.adventure_datetime.model.ILocalDatabase#setStory(ca.cmput301f13t03.adventure_datetime.model.Story)
     */
    @Override
    public boolean setStory(Story story) {

        SQLiteDatabase db = mDbHelper.getWritableDatabase();
        ContentValues values = new ContentValues();
        values.put(STORY_COLUMN_TITLE, story.getTitle());
        values.put(STORY_COLUMN_AUTHOR, story.getAuthor());
        values.put(STORY_COLUMN_HEAD_FRAGMENT, story.getHeadFragmentId().toString());
        values.put(STORY_COLUMN_SYNOPSIS, story.getSynopsis());
        values.put(STORY_COLUMN_TIMESTAMP, story.getTimestamp());
        values.put(STORY_COLUMN_THUMBNAIL,
                (story.getThumbnail() == null ? null : story.getThumbnail().getId().toString()));
        values.put(COLUMN_GUID, story.getId().toString());

        Cursor cursor = db.query(STORY_TABLE_NAME, new String[] { _ID }, COLUMN_GUID + " = ?",
                new String[] { story.getId().toString() }, null, null, null);
        if (cursor.moveToFirst()) {
            int updated;
            updated = db.update(STORY_TABLE_NAME, values, COLUMN_GUID + " = ?",
                    new String[] { story.getId().toString() });
            Log.v(TAG, updated + " stories updated");
            cursor.close();
            db.close();
            return updated == 1 && setImage(story.getThumbnail());
        }
        cursor.close();
        long inserted;
        inserted = db.insert(STORY_TABLE_NAME, null, values);
        Log.v(TAG, inserted + " story inserted");
        db.close();
        return inserted != -1 && setImage(story.getThumbnail());
    }

    /* (non-Javadoc)
     * @see ca.cmput301f13t03.adventure_datetime.model.ILocalDatabase#setStoryFragment(ca.cmput301f13t03.adventure_datetime.model.StoryFragment)
     */
    @Override
    public boolean setStoryFragment(StoryFragment frag) {
        SQLiteDatabase db = mDbHelper.getWritableDatabase();
        ContentValues values = new ContentValues();
        values.put(STORYFRAGMENT_COLUMN_STORYID, frag.getStoryID().toString());
        values.put(STORYFRAGMENT_COLUMN_CONTENT, frag.getStoryText());
        values.put(STORYFRAGMENT_COLUMN_CHOICES, frag.getChoicesInJson());
        values.put(COLUMN_GUID, frag.getFragmentID().toString());
        values.put(STORYFRAGMENT_COLUMN_IMAGES, frag.getStoryMediaInJson());

        Cursor cursor = db.query(STORYFRAGMENT_TABLE_NAME, new String[] { _ID, STORYFRAGMENT_COLUMN_STORYID },
                COLUMN_GUID + " = ? AND " + STORYFRAGMENT_COLUMN_STORYID + " = ?",
                new String[] { frag.getFragmentID().toString(), frag.getStoryID().toString() }, null, null, null);
        if (cursor.moveToFirst()) {
            int updated;
            updated = db.update(STORYFRAGMENT_TABLE_NAME, values,
                    COLUMN_GUID + " = ? AND " + STORYFRAGMENT_COLUMN_STORYID + " = ?",
                    new String[] { frag.getFragmentID().toString(), frag.getStoryID().toString() });
            Log.v(TAG, updated + " fragments updated");
            cursor.close();
            db.close();
            return updated == 1 && setImages(frag.getStoryMedia());
        }
        long inserted;
        inserted = db.insert(STORYFRAGMENT_TABLE_NAME, null, values);
        Log.v(TAG, inserted + " fragment inserted");
        db.close();
        return inserted != -1 && setImages(frag.getStoryMedia());

    }

    @Override
    public boolean setAuthoredStory(Story story) {
        Story story2 = getStory(story.getId());

        if (story2 == null) {
            Log.v(TAG, "Story doesn't exist in local DB!");
            return false;
        }

        if (getAuthoredStory(story.getId())) {
            Log.v(TAG, "Story already in AuthoredStory table");
            return true;
        }

        SQLiteDatabase db = mDbHelper.getWritableDatabase();

        ContentValues values = new ContentValues();

        values.put(COLUMN_GUID, story.getId().toString());

        long insert = db.insert(AUTHORED_STORY_TABLE_NAME, null, values);

        db.close();

        return insert != -1;
    }

    public boolean setImage(Image image) {
        SQLiteDatabase db = mDbHelper.getWritableDatabase();
        Image image2 = getImage(image.getId());
        ContentValues values = new ContentValues();
        values.put(COLUMN_GUID, image.getId().toString());
        values.put(STORY_IMAGE_COLUMN_IMAGE, image.getEncodedBitmap());
        long inserted;
        if (image2 == null) {
            inserted = db.insert(STORY_IMAGE_TABLE_NAME, null, values);
            db.close();
            return inserted != -1;
        } else {
            inserted = db.update(STORY_IMAGE_TABLE_NAME, values, COLUMN_GUID + " = ?",
                    new String[] { image.getId().toString() });
            db.close();
            return inserted == 1;
        }
    }

    public boolean setImages(ArrayList<Image> images) {
        boolean result = true;
        for (Image image : images) {
            result &= setImage(image);
        }

        return result;
    }

    /* (non-Javadoc)
     * @see ca.cmput301f13t03.adventure_datetime.model.ILocalDatabase#deleteStory(java.util.UUID)
     */
    public boolean deleteStory(UUID id) {
        boolean fragments;
        fragments = deleteStoryFragments(id);
        deleteBookmarkByStory(id);
        deleteAuthoredStory(id);
        SQLiteDatabase db = mDbHelper.getWritableDatabase();
        int story;
        story = db.delete(STORY_TABLE_NAME, COLUMN_GUID + " = ?", new String[] { id.toString() });
        Log.v(TAG, story + " deleted, had UUID " + id);
        db.close();
        return story == 1 && fragments;
    }

    /* (non-Javadoc)
     * @see ca.cmput301f13t03.adventure_datetime.model.ILocalDatabase#deleteStoryFragments(java.util.UUID)
     */
    public boolean deleteStoryFragments(UUID storyID) {
        int fragments;
        deleteBookmarkByStory(storyID);
        SQLiteDatabase db = mDbHelper.getWritableDatabase();
        fragments = db.delete(STORYFRAGMENT_TABLE_NAME, STORYFRAGMENT_COLUMN_STORYID + " = ?",
                new String[] { storyID.toString() });
        Log.v(TAG, fragments + " deleted from DB, all with StoryID " + storyID);
        db.close();

        return fragments > 0;
    }

    /* (non-Javadoc)
    * @see ca.cmput301f13t03.adventure_datetime.model.ILocalDatabase#deleteStoryFragment(java.util.UUID)
    */
    public boolean deleteStoryFragment(UUID fragmentID) {
        int fragment;
        deleteBookmarkByFragment(fragmentID);
        SQLiteDatabase db = mDbHelper.getWritableDatabase();
        fragment = db.delete(STORYFRAGMENT_TABLE_NAME, COLUMN_GUID + " = ?",
                new String[] { fragmentID.toString() });
        Log.v(TAG, fragment + " fragment deleted, with fragmentID " + fragmentID);
        db.close();

        return fragment == 1;
    }

    /* (non-Javadoc)
    * @see ca.cmput301f13t03.adventure_datetime.model.ILocalDatabase#deleteBookmarkByStory(java.util.UUID)
    */
    public boolean deleteBookmarkByStory(UUID storyID) {
        int bookmark;
        SQLiteDatabase db = mDbHelper.getWritableDatabase();
        bookmark = db.delete(BOOKMARK_TABLE_NAME, BOOKMARK_COLUMN_STORYID + " = ?",
                new String[] { storyID.toString() });
        Log.v(TAG, bookmark + " bookmark deleted, with storyID " + storyID);
        db.close();
        return bookmark == 1;
    }

    /* (non-Javadoc)
    * @see ca.cmput301f13t03.adventure_datetime.model.ILocalDatabase#deleteBookmarkByFragment(java.util.UUID)
    */
    public boolean deleteBookmarkByFragment(UUID fragmentID) {
        int bookmark;
        SQLiteDatabase db = mDbHelper.getWritableDatabase();
        bookmark = db.delete(BOOKMARK_TABLE_NAME, BOOKMARK_COLUMN_FRAGMENTID + " = ?",
                new String[] { fragmentID.toString() });
        Log.v(TAG, bookmark + " bookmark deleted, with fragmentID " + fragmentID);
        db.close();
        return bookmark == 1;
    }

    @Override
    public boolean deleteAuthoredStory(UUID storyID) {
        int authoredStory;
        SQLiteDatabase db = mDbHelper.getWritableDatabase();
        authoredStory = db.delete(AUTHORED_STORY_TABLE_NAME, COLUMN_GUID + " = ?",
                new String[] { storyID.toString() });
        Log.v(TAG, authoredStory + " authored story deleted, with storyId " + storyID);
        db.close();
        return authoredStory == 1;
    }

    public boolean deleteImage(UUID id) {
        int images;
        SQLiteDatabase db = mDbHelper.getWritableDatabase();
        images = db.delete(STORY_IMAGE_TABLE_NAME, COLUMN_GUID + " = ?", new String[] { id.toString() });
        Log.v(TAG, images + " images deleted, with UUID " + id);

        return images != 0;
    }

    /**
     * Creates story from a cursor
     *
     * @param cursor A Cursor pointing to a Story
     *
     * @return A Story instance from the Database
     */
    private Story createStory(Cursor cursor) {
        String title, author, synopsis;
        UUID headFragmentId, id;
        long timestamp;
        Image thumbnail;

        id = UUID.fromString(cursor.getString(cursor.getColumnIndex(StoryDB.COLUMN_GUID)));
        title = cursor.getString(cursor.getColumnIndex(StoryDB.STORY_COLUMN_TITLE));
        headFragmentId = UUID
                .fromString(cursor.getString(cursor.getColumnIndex(StoryDB.STORY_COLUMN_HEAD_FRAGMENT)));
        author = cursor.getString(cursor.getColumnIndex(StoryDB.STORY_COLUMN_AUTHOR));
        synopsis = cursor.getString(cursor.getColumnIndex(StoryDB.STORY_COLUMN_SYNOPSIS));
        timestamp = cursor.getLong(cursor.getColumnIndex(StoryDB.STORY_COLUMN_TIMESTAMP));

        thumbnail = getImage(id);

        Story newStory = new Story(headFragmentId, id, author, timestamp, synopsis, thumbnail, title);

        ArrayList<UUID> referencedFragments = this.getStoryFragmentIDs(id);

        for (UUID frag : referencedFragments) {
            newStory.addFragment(frag);
        }

        return newStory;
    }

    /**
     * Creates a StoryFragment from a cursor
     *
     * @param cursor A Cursor pointing to a StoryFragment
     *
     * @return A StoryFragment instance from the Database
     */
    private StoryFragment createStoryFragment(Cursor cursor) {
        UUID storyID, fragmentID;
        String storyText;
        ArrayList<Choice> choices;
        ArrayList<Image> images;
        ArrayList<UUID> uuids;
        storyID = UUID.fromString(cursor.getString(cursor.getColumnIndex(StoryDB.STORYFRAGMENT_COLUMN_STORYID)));
        fragmentID = UUID.fromString(cursor.getString(cursor.getColumnIndex(StoryDB.COLUMN_GUID)));
        storyText = cursor.getString(cursor.getColumnIndex(StoryDB.STORYFRAGMENT_COLUMN_CONTENT));
        String json = cursor.getString(cursor.getColumnIndex(StoryDB.STORYFRAGMENT_COLUMN_CHOICES));
        Gson gson = new Gson();
        Type collectionType = new TypeToken<Collection<Choice>>() {
        }.getType();
        choices = gson.fromJson(json, collectionType);
        json = cursor.getString(cursor.getColumnIndex(STORYFRAGMENT_COLUMN_IMAGES));
        collectionType = new TypeToken<Collection<UUID>>() {
        }.getType();
        uuids = gson.fromJson(json, collectionType);
        images = getImages(uuids);

        return new StoryFragment(storyID, fragmentID, storyText, images, choices);
    }

    /**
     * Creates a Bookmark from a cursor
     *
     * @param cursor A Cursor pointing to a Bookmark
     *
     * @return A Bookmark instance from the Database
     */
    private Bookmark createBookmark(Cursor cursor) {
        UUID fragmentID, storyID;
        Date date;

        fragmentID = UUID.fromString(cursor.getString(cursor.getColumnIndex(StoryDB.BOOKMARK_COLUMN_FRAGMENTID)));
        storyID = UUID.fromString(cursor.getString(cursor.getColumnIndex(StoryDB.BOOKMARK_COLUMN_STORYID)));
        long unix = cursor.getLong(cursor.getColumnIndex(StoryDB.BOOKMARK_COLUMN_DATE));
        Calendar cal = Calendar.getInstance();
        cal.setTimeInMillis(unix);
        date = cal.getTime();

        return new Bookmark(fragmentID, storyID, date);
    }

    private Image createImage(Cursor cursor) {
        UUID id;
        String bitmap;
        id = UUID.fromString(cursor.getString(cursor.getColumnIndex(COLUMN_GUID)));
        bitmap = cursor.getString(cursor.getColumnIndex(STORY_IMAGE_COLUMN_IMAGE));

        return new Image(id, bitmap);
    }

    public class StoryDBHelper extends SQLiteOpenHelper {

        public static final int DATABASE_VERSION = 7;
        public static final String DATABASE_NAME = "adventure.database";

        private static final String TAG = "StoryDBHelper";

        private static final String CREATE_STORY_TABLE = "CREATE TABLE " + STORY_TABLE_NAME + " (" + _ID
                + " INTEGER PRIMARY KEY, " + COLUMN_GUID + " TEXT, " + STORY_COLUMN_TITLE + " TEXT, "
                + STORY_COLUMN_AUTHOR + " TEXT, " + STORY_COLUMN_SYNOPSIS + " TEXT, " + STORY_COLUMN_HEAD_FRAGMENT
                + " INTEGER, " + STORY_COLUMN_TIMESTAMP + " INTEGER, " + STORY_COLUMN_THUMBNAIL + " TEXT, "
                + "FOREIGN KEY(" + STORY_COLUMN_HEAD_FRAGMENT + ") REFERENCES " + STORYFRAGMENT_TABLE_NAME + "("
                + COLUMN_GUID + ") )";

        private static final String CREATE_STORYFRAGMENT_TABLE = "CREATE TABLE " + STORYFRAGMENT_TABLE_NAME + " ("
                + _ID + " INTEGER PRIMARY KEY, " + COLUMN_GUID + " TEXT, " + STORYFRAGMENT_COLUMN_STORYID
                + " INTEGER, " + STORYFRAGMENT_COLUMN_CONTENT + " TEXT, " + STORYFRAGMENT_COLUMN_CHOICES + " BLOB, "
                + STORYFRAGMENT_COLUMN_IMAGES + " BLOB, " + "FOREIGN KEY(" + STORYFRAGMENT_COLUMN_STORYID
                + ") REFERENCES " + STORY_TABLE_NAME + "(" + COLUMN_GUID + "))";

        private static final String CREATE_BOOKMARK_TABLE = "CREATE TABLE " + BOOKMARK_TABLE_NAME + " (" + _ID
                + " INTEGER PRIMARY KEY, " + BOOKMARK_COLUMN_FRAGMENTID + " INTEGER, " + BOOKMARK_COLUMN_STORYID
                + " INTEGER, " + BOOKMARK_COLUMN_DATE + " INTEGER, " + "FOREIGN KEY(" + BOOKMARK_COLUMN_FRAGMENTID
                + ") REFERENCES " + STORYFRAGMENT_TABLE_NAME + "(" + COLUMN_GUID + "), FOREIGN KEY ("
                + BOOKMARK_COLUMN_STORYID + ") REFERENCES " + STORY_TABLE_NAME + "(" + COLUMN_GUID + "))";

        private static final String CREATE_AUTHORED_STORY_TABLE = "CREATE TABLE " + AUTHORED_STORY_TABLE_NAME + " ("
                + _ID + " INTEGER PRIMARY KEY, " + COLUMN_GUID + " TEXT, " + "FOREIGN KEY(" + COLUMN_GUID
                + ") REFERENCES " + STORY_TABLE_NAME + "(" + COLUMN_GUID + "))";

        private static final String CREATE_STORY_IMAGE_TABLE = "CREATE TABLE " + STORY_IMAGE_TABLE_NAME + " (" + _ID
                + " INTEGER PRIMARY KEY, " + COLUMN_GUID + " TEXT, " + STORY_IMAGE_COLUMN_IMAGE + " TEXT)";

        private static final String DELETE_STORY_TABLE = "DROP TABLE IF EXISTS " + STORY_TABLE_NAME;

        private static final String DELETE_STORYFRAGMENT_TABLE = "DROP TABLE IF EXISTS " + STORYFRAGMENT_TABLE_NAME;

        private static final String DELETE_BOOKMARK_TABLE = "DROP TABLE IF EXISTS " + BOOKMARK_TABLE_NAME;

        private static final String DELETE_AUTHORED_STORY_TABLE = "DROP TABLE IF EXISTS "
                + AUTHORED_STORY_TABLE_NAME;

        private static final String DELETE_STORY_IMAGE_TABLE = "DROP TABLE IF EXISTS " + STORY_IMAGE_TABLE_NAME;

        public StoryDBHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            Log.v(TAG, "Creating DB");
            db.execSQL(CREATE_STORY_TABLE);
            db.execSQL(CREATE_STORYFRAGMENT_TABLE);
            db.execSQL(CREATE_BOOKMARK_TABLE);
            db.execSQL(CREATE_AUTHORED_STORY_TABLE);
            db.execSQL(CREATE_STORY_IMAGE_TABLE);
            populateDB(db);
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            db.execSQL(DELETE_STORYFRAGMENT_TABLE);
            db.execSQL(DELETE_STORY_TABLE);
            db.execSQL(DELETE_BOOKMARK_TABLE);
            db.execSQL(DELETE_AUTHORED_STORY_TABLE);
            db.execSQL(DELETE_STORY_IMAGE_TABLE);
        }

        @Override
        public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            onUpgrade(db, oldVersion, newVersion);

        }

        private void populateDB(SQLiteDatabase db) {
            Bitmap bit = Bitmap.createBitmap(new int[] { Color.BLACK }, 1, 1, Bitmap.Config.ARGB_8888);
            Story story = new Story(UUID.fromString("5582f797-29b8-4d9d-83bf-88c434c1944a"),
                    UUID.fromString("fc662870-5d6a-4ae2-98f6-0cdfe36013bb"), "Andrew", 706232100,
                    "A guide to playing choose your own adventures\nPress 'Play Story' below to begin!", bit,
                    "Play me!");
            String storyText = "Welcome to Adventure.DateTime! To progress, press 'Actions' and select 'Next Tutorial'.";
            StoryFragment frag = new StoryFragment(story.getId(),
                    UUID.fromString("5582f797-29b8-4d9d-83bf-88c434c1944a"), storyText, new ArrayList<Image>(),
                    new ArrayList<Choice>());
            StoryFragment frag2 = new StoryFragment(story.getId(),
                    UUID.fromString("b10ef8ca-1180-44f6-b11b-170fef5ec071"),
                    "Great job! "
                            + "A new bookmark has automatically been created so you can pick up from where you left off later.\n"
                            + "Playing these is as simple as that! A few things to note:\n"
                            + "\tSometimes, these little story fragments,as we call them, contain pictures. "
                            + "If they do, you'll see this above all this text. Press one, and it'll open up a "
                            + "full-screen view."
                            + "\t 'I'm feeling lucky' is an option in every story fragment. If you can't decide which option to choose,"
                            + " it'll pick one for you at random.\n\n"
                            + "That's really about it. Now get playing! Hit 'The End' and 'Change Adventures' to find something else "
                            + "to play. I suggest looking in Online.",
                    new ArrayList<Image>(), new ArrayList<Choice>());
            Choice choice = new Choice("Next tutorial", frag2.getFragmentID());
            frag.addChoice(choice);
            story.addFragment(frag);
            story.setHeadFragmentId(frag);
            story.addFragment(frag2);
            Calendar cal = Calendar.getInstance();
            cal.setTimeInMillis(1383652800L * 1000L);

            db.beginTransaction();
            long inserted;

            ContentValues values = new ContentValues();
            values.put(STORY_COLUMN_TITLE, story.getTitle());
            values.put(STORY_COLUMN_AUTHOR, story.getAuthor());
            values.put(STORY_COLUMN_HEAD_FRAGMENT, story.getHeadFragmentId().toString());
            values.put(STORY_COLUMN_SYNOPSIS, story.getSynopsis());
            values.put(STORY_COLUMN_TIMESTAMP, story.getTimestamp());
            values.put(STORY_COLUMN_THUMBNAIL, story.getThumbnail().getId().toString());
            values.put(COLUMN_GUID, story.getId().toString());
            inserted = db.insert(STORY_TABLE_NAME, null, values);
            Log.d(TAG, String.valueOf(inserted));
            values = new ContentValues();
            values.put(COLUMN_GUID, story.getThumbnail().getId().toString());
            values.put(STORY_IMAGE_COLUMN_IMAGE, story.getThumbnail().getEncodedBitmap());
            inserted = db.insert(STORY_IMAGE_TABLE_NAME, null, values);
            Log.d(TAG, String.valueOf(inserted));
            values = new ContentValues();
            values.put(STORYFRAGMENT_COLUMN_STORYID, frag.getStoryID().toString());
            values.put(STORYFRAGMENT_COLUMN_CONTENT, frag.getStoryText());
            values.put(STORYFRAGMENT_COLUMN_CHOICES, frag.getChoicesInJson());
            values.put(COLUMN_GUID, frag.getFragmentID().toString());
            inserted = db.insert(STORYFRAGMENT_TABLE_NAME, null, values);
            Log.d(TAG, String.valueOf(inserted));
            values = new ContentValues();
            values.put(STORYFRAGMENT_COLUMN_STORYID, frag2.getStoryID().toString());
            values.put(STORYFRAGMENT_COLUMN_CONTENT, frag2.getStoryText());
            values.put(STORYFRAGMENT_COLUMN_CHOICES, frag2.getChoicesInJson());
            values.put(COLUMN_GUID, frag2.getFragmentID().toString());
            inserted = db.insert(STORYFRAGMENT_TABLE_NAME, null, values);
            Log.d(TAG, String.valueOf(inserted));
            db.setTransactionSuccessful();
            db.endTransaction();

            story = new Story(UUID.fromString("9b135456-ecc9-4619-89ca-94f21aefd5b5"),
                    UUID.fromString("6395015f-d63d-416f-8be6-eb4ff5c99c4c"), "Andrew", 706232100,
                    "A guide to creating choose your own adventures\nPress the pencil in the top right, and meet me over in "
                            + "Author!\n\nI'm going to assume you're there now. If you are, pressing on that little black square next to the title"
                            + " will allow you to change this "
                            + "story's thumbnail to something a little more suitable. You should also notice that the author's name is now you! Unless this "
                            + "isn't your phone, that is. The pencil, which is where we're going next, allows us to edit the interior of the story. "
                            + "The floppy disk saves your changes, although we generally handle the saving for you. The arrow uploads your story to our"
                            + " servers to share with everyone. The trash can deletes your story, but beware, if you upload your story, there's no eliminating it."
                            + "\n\n When you're ready, hit that pencil!",
                    bit, "Edit me!");
            storyText = "Scroll over to Edit...\n\n"
                    + "Hey there! You're editing the head fragment of your story. This is the first part your readers will encounter. "
                    + "We have a few things you can do here, namely, editing this text, as well as editing the choices connecting it to "
                    + "other fragments. There should already be a choice sitting there. "
                    + "There isn't much here... let's change that. We want to add a new choice. "
                    + "To add a choice, we need a new fragment to "
                    + "connect it to. Go back to 'Overview,' and press the 'Add' button in the top right. "
                    + "REMEMBER! To change the fragment you're editing, press on its node in Overview. Press the other node once "
                    + "you have a new fragment.";
            frag = new StoryFragment(story.getId(), UUID.fromString("6395015f-d63d-416f-8be6-eb4ff5c99c4c"),
                    storyText, new ArrayList<Image>(), new ArrayList<Choice>());

            storyText = "Good you made it back. I was worried for a moment. To connect your new fragment to this one, hit "
                    + "the add choice button. You'll have to fill out what you want your choice's text to be. When you hit "
                    + "'Okay', you'll jump over to the Overview, where you can press on the node the choice will lead to. "
                    + "Easy, right? To add pictures to your super cool story, press the Organize Media button above this. "
                    + "You'll be able to select pictures from your gallery or take new ones. To take a look at what your fragment "
                    + "will look like, head over to the Preview! Have fun creating!";

            frag2 = new StoryFragment(story.getId(), UUID.fromString("dd868b19-d3bc-4c3b-beff-2c5bdad4026c"),
                    storyText, new ArrayList<Image>(), new ArrayList<Choice>());

            choice = new Choice("Next tutorial", frag2.getFragmentID());
            frag.addChoice(choice);
            story.addFragment(frag);
            story.addFragment(frag2);
            story.setHeadFragmentId(frag);
            cal = Calendar.getInstance();
            cal.setTimeInMillis(1383652800L * 1000L);

            db.beginTransaction();

            values = new ContentValues();
            values.put(STORY_COLUMN_TITLE, story.getTitle());
            values.put(STORY_COLUMN_AUTHOR, story.getAuthor());
            values.put(STORY_COLUMN_HEAD_FRAGMENT, story.getHeadFragmentId().toString());
            values.put(STORY_COLUMN_SYNOPSIS, story.getSynopsis());
            values.put(STORY_COLUMN_TIMESTAMP, story.getTimestamp());
            values.put(STORY_COLUMN_THUMBNAIL, story.getThumbnail().getId().toString());
            values.put(COLUMN_GUID, story.getId().toString());
            inserted = db.insert(STORY_TABLE_NAME, null, values);
            Log.d(TAG, String.valueOf(inserted));
            values = new ContentValues();
            values.put(COLUMN_GUID, story.getThumbnail().getId().toString());
            values.put(STORY_IMAGE_COLUMN_IMAGE, story.getThumbnail().getEncodedBitmap());
            inserted = db.insert(STORY_IMAGE_TABLE_NAME, null, values);
            Log.d(TAG, String.valueOf(inserted));
            values = new ContentValues();
            values.put(STORYFRAGMENT_COLUMN_STORYID, frag.getStoryID().toString());
            values.put(STORYFRAGMENT_COLUMN_CONTENT, frag.getStoryText());
            values.put(STORYFRAGMENT_COLUMN_CHOICES, frag.getChoicesInJson());
            values.put(COLUMN_GUID, frag.getFragmentID().toString());
            inserted = db.insert(STORYFRAGMENT_TABLE_NAME, null, values);
            Log.d(TAG, String.valueOf(inserted));
            values = new ContentValues();
            values.put(STORYFRAGMENT_COLUMN_STORYID, frag2.getStoryID().toString());
            values.put(STORYFRAGMENT_COLUMN_CONTENT, frag2.getStoryText());
            values.put(STORYFRAGMENT_COLUMN_CHOICES, frag2.getChoicesInJson());
            values.put(COLUMN_GUID, frag2.getFragmentID().toString());
            inserted = db.insert(STORYFRAGMENT_TABLE_NAME, null, values);
            Log.d(TAG, String.valueOf(inserted));
            db.setTransactionSuccessful();
            db.endTransaction();
        }
    }
}