/*
     This test uses the database directly to insert and then uses the ContentProvider to
     read out the data.  Uncomment this test to see if your location queries are
     performing correctly.
  */
  public void testBasicLocationQueries() {
    // insert our test records into the database
    WeatherDbHelper dbHelper = new WeatherDbHelper(mContext);
    SQLiteDatabase db = dbHelper.getWritableDatabase();

    ContentValues testValues = TestUtilities.createNorthPoleLocationValues();
    long locationRowId = TestUtilities.insertNorthPoleLocationValues(mContext);

    // Test the basic content provider query
    Cursor locationCursor =
        mContext.getContentResolver().query(LocationEntry.CONTENT_URI, null, null, null, null);

    // Make sure we get the correct cursor out of the database
    TestUtilities.validateCursor(
        "testBasicLocationQueries, location query", locationCursor, testValues);

    // Has the NotificationUri been set correctly? --- we can only test this easily against API
    // level 19 or greater because getNotificationUri was added in API level 19.
    if (Build.VERSION.SDK_INT >= 19) {
      assertEquals(
          "Error: Location Query did not properly set NotificationUri",
          locationCursor.getNotificationUri(),
          LocationEntry.CONTENT_URI);
    }
  }
  @Override
  public Cursor query(
      Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
    // Here's the switch statement that, given a URI, will determine what kind of request it is,
    // and query the database accordingly.
    Cursor retCursor;
    switch (sUriMatcher.match(uri)) {
        // "weather/*/*"
      case WEATHER_WITH_LOCATION_AND_DATE:
        {
          retCursor = getWeatherByLocationSettingAndDate(uri, projection, sortOrder);
          break;
        }
        // "weather/*"
      case WEATHER_WITH_LOCATION:
        {
          retCursor = getWeatherByLocationSetting(uri, projection, sortOrder);
          break;
        }
        // "weather"
      case WEATHER:
        {
          retCursor =
              mOpenHelper
                  .getReadableDatabase()
                  .query(
                      WeatherContract.WeatherEntry.TABLE_NAME,
                      projection,
                      selection,
                      selectionArgs,
                      null,
                      null,
                      sortOrder);

          break;
        }
        // "location"
      case LOCATION:
        {
          retCursor =
              mOpenHelper
                  .getReadableDatabase()
                  .query(
                      WeatherContract.LocationEntry.TABLE_NAME,
                      projection,
                      selection,
                      selectionArgs,
                      null,
                      null,
                      sortOrder);
          break;
        }

      default:
        throw new UnsupportedOperationException("Unknown uri: " + uri);
    }
    retCursor.setNotificationUri(getContext().getContentResolver(), uri);
    return retCursor;
  }
  /*
     Students: This is a helper method for the testWeatherTable quiz. You can move your
     code from testLocationTable to here so that you can call this code from both
     testWeatherTable and testLocationTable.
  */
  public long insertLocation() {
    // First step: Get reference to writable database
    // If there's an error in those massive SQL table creation Strings,
    // errors will be thrown here when you try to get a writable database.
    WeatherDbHelper dbHelper = new WeatherDbHelper(mContext);
    SQLiteDatabase db = dbHelper.getWritableDatabase();

    // Second Step: Create ContentValues of what you want to insert
    // (you can use the createNorthPoleLocationValues if you wish)
    ContentValues testValues = TestUtilities.createNorthPoleLocationValues();

    // Third Step: Insert ContentValues into database and get a row ID back
    long locationRowId = db.insert(WeatherContract.LocationEntry.TABLE_NAME, null, testValues);

    // Verify we got a row back.
    assertTrue(locationRowId != -1);

    // Data's inserted.  IN THEORY.  Now pull some out to stare at it and verify it made
    // the round trip.

    // Fourth Step: Query the database and receive a Cursor back
    // A cursor is your primary interface to the query results.
    Cursor cursor =
        db.query(
            WeatherContract.LocationEntry.TABLE_NAME, // Table to Query
            null, // all columns
            null, // Columns for the "where" clause
            null, // Values for the "where" clause
            null, // columns to group by
            null, // columns to filter by row groups
            null // sort order
            );

    // Move the cursor to a valid database row and check to see if we got any records back
    // from the query
    assertTrue("Error: No Records returned from location query", cursor.moveToFirst());

    // Fifth Step: Validate data in resulting Cursor with the original ContentValues
    // (you can use the validateCurrentRecord function in TestUtilities to validate the
    // query if you like)
    TestUtilities.validateCurrentRecord(
        "Error: Location Query Validation Failed", cursor, testValues);

    // Move the cursor to demonstrate that there is only one record in the database
    assertFalse("Error: More than one record returned from location query", cursor.moveToNext());

    // Sixth Step: Close Cursor and Database
    cursor.close();
    db.close();

    return locationRowId; // if error getting a row back: -1L
  }
  /*
     Students: You can uncomment this function once you have finished creating the
     LocationEntry part of the WeatherContract as well as the WeatherDbHelper.
  */
  static long insertNorthPoleLocationValues(Context context) {
    // insert our test records into the database
    WeatherDbHelper dbHelper = new WeatherDbHelper(context);
    SQLiteDatabase db = dbHelper.getWritableDatabase();
    ContentValues testValues = TestUtilities.createNorthPoleLocationValues();

    long locationRowId;
    locationRowId = db.insert(WeatherContract.LocationEntry.TABLE_NAME, null, testValues);

    // Verify we got a row back.
    Assert.assertTrue("Error: Failure to insert North Pole Location Values", locationRowId != -1);

    return locationRowId;
  }
 @Override
 public int bulkInsert(Uri uri, ContentValues[] values) {
   final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
   final int match = sUriMatcher.match(uri);
   switch (match) {
     case WEATHER:
       db.beginTransaction();
       int returnCount = 0;
       try {
         for (ContentValues value : values) {
           normalizeDate(value);
           long _id = db.insert(WeatherContract.WeatherEntry.TABLE_NAME, null, value);
           if (_id != -1) {
             returnCount++;
           }
         }
         db.setTransactionSuccessful();
       } finally {
         db.endTransaction();
       }
       getContext().getContentResolver().notifyChange(uri, null);
       return returnCount;
     default:
       return super.bulkInsert(uri, values);
   }
 }
  @Override
  public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
    // Student: This is a lot like the delete function.  We return the number of rows impacted
    // by the update.
    SQLiteDatabase db = mOpenHelper.getWritableDatabase();
    int rows;

    switch (sUriMatcher.match(uri)) {
      case WEATHER:
        {
          rows =
              db.update(WeatherContract.WeatherEntry.TABLE_NAME, values, selection, selectionArgs);
          break;
        }
      case LOCATION:
        {
          rows =
              db.update(WeatherContract.LocationEntry.TABLE_NAME, values, selection, selectionArgs);
          break;
        }
      default:
        throw new UnsupportedOperationException("Unknown uri: " + uri);
    }

    if (selection == null || rows != 0) {
      getContext().getContentResolver().notifyChange(uri, null);
    }

    return rows;
  }
  /*
     Student: Add the ability to insert Locations to the implementation of this function.
  */
  @Override
  public Uri insert(Uri uri, ContentValues values) {
    final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
    final int match = sUriMatcher.match(uri);
    Uri returnUri;

    switch (match) {
      case WEATHER:
        {
          normalizeDate(values);
          long _id = db.insert(WeatherContract.WeatherEntry.TABLE_NAME, null, values);
          if (_id > 0) returnUri = WeatherContract.WeatherEntry.buildWeatherUri(_id);
          else throw new android.database.SQLException("Failed to insert row into " + uri);
          break;
        }
      case LOCATION:
        {
          long _id = db.insert(WeatherContract.LocationEntry.TABLE_NAME, null, values);
          if (_id > 0) returnUri = WeatherContract.LocationEntry.buildLocationUri(_id);
          else throw new android.database.SQLException("Failed to insert row into " + uri);
          break;
        }
      default:
        throw new UnsupportedOperationException("Unknown uri: " + uri);
    }
    getContext().getContentResolver().notifyChange(uri, null);
    return returnUri;
  }
  private Cursor getWeatherByLocationSettingAndDate(
      Uri uri, String[] projection, String sortOrder) {
    String locationSetting = WeatherContract.WeatherEntry.getLocationSettingFromUri(uri);
    long date = WeatherContract.WeatherEntry.getDateFromUri(uri);

    return sWeatherByLocationSettingQueryBuilder.query(
        mOpenHelper.getReadableDatabase(),
        projection,
        sLocationSettingAndDaySelection,
        new String[] {locationSetting, Long.toString(date)},
        null,
        null,
        sortOrder);
  }
  /*
     This test uses the database directly to insert and then uses the ContentProvider to
     read out the data.  Uncomment this test to see if the basic weather query functionality
     given in the ContentProvider is working correctly.
  */
  public void testBasicWeatherQuery() {
    // insert our test records into the database
    WeatherDbHelper dbHelper = new WeatherDbHelper(mContext);
    SQLiteDatabase db = dbHelper.getWritableDatabase();

    ContentValues testValues = TestUtilities.createNorthPoleLocationValues();
    long locationRowId = TestUtilities.insertNorthPoleLocationValues(mContext);

    // Fantastic.  Now that we have a location, add some weather!
    ContentValues weatherValues = TestUtilities.createWeatherValues(locationRowId);

    long weatherRowId = db.insert(WeatherEntry.TABLE_NAME, null, weatherValues);
    assertTrue("Unable to Insert WeatherEntry into the Database", weatherRowId != -1);

    db.close();

    // Test the basic content provider query
    Cursor weatherCursor =
        mContext.getContentResolver().query(WeatherEntry.CONTENT_URI, null, null, null, null);

    // Make sure we get the correct cursor out of the database
    TestUtilities.validateCursor("testBasicWeatherQuery", weatherCursor, weatherValues);
  }
  @Override
  public int delete(Uri uri, String selection, String[] selectionArgs) {
    final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
    final int match = sUriMatcher.match(uri);

    int rowsDeleted;

    if (null == selection) selection = "1";
    switch (match) {
      case WEATHER:
        {
          rowsDeleted =
              db.delete(WeatherContract.WeatherEntry.TABLE_NAME, selection, selectionArgs);
          break;
        }

      case LOCATION:
        {
          rowsDeleted =
              db.delete(WeatherContract.LocationEntry.TABLE_NAME, selection, selectionArgs);
          break;
        }

      default:
        throw new UnsupportedOperationException("Unknown uri: " + uri);
    }

    if (rowsDeleted != 0) {
      getContext().getContentResolver().notifyChange(uri, null);
    }
    // Student: Use the uriMatcher to match the WEATHER and LOCATION URI's we are going to
    // handle.  If it doesn't match these, throw an UnsupportedOperationException.

    // Student: A null value deletes all rows.  In my implementation of this, I only notified
    // the uri listeners (using the content resolver) if the rowsDeleted != 0 or the selection
    // is null.
    // Oh, and you should notify the listeners here.

    // Student: return the actual rows deleted
    return rowsDeleted;
  }
  @Override
  public int delete(Uri uri, String selection, String[] selectionArgs) {
    // Student: Start by getting a writable database
    SQLiteDatabase db = mOpenHelper.getWritableDatabase();
    int rows;

    // Student: Use the uriMatcher to match the WEATHER and LOCATION URI's we are going to
    // handle.  If it doesn't match these, throw an UnsupportedOperationException.

    // Allows delete() to return number of rows that were deleted if ALL rows are deleted.
    if (selection == null) selection = "1";
    switch (sUriMatcher.match(uri)) {
      case WEATHER:
        {
          rows = db.delete(WeatherContract.WeatherEntry.TABLE_NAME, selection, selectionArgs);
          break;
        }
      case LOCATION:
        {
          rows = db.delete(WeatherContract.LocationEntry.TABLE_NAME, selection, selectionArgs);
          break;
        }
      default:
        {
          throw new UnsupportedOperationException("Unknown uri: " + uri);
        }
    }

    // Student: A null value deletes all rows.  In my implementation of this, I only notified
    // the uri listeners (using the content resolver) if the rowsDeleted != 0 or the selection
    // is null.
    if (rows != 0) {
      getContext().getContentResolver().notifyChange(uri, null);
    }
    // Student: return the actual rows deleted
    return rows;
  }
  private Cursor getWeatherByLocationSetting(Uri uri, String[] projection, String sortOrder) {
    String locationSetting = WeatherContract.WeatherEntry.getLocationSettingFromUri(uri);
    long startDate = WeatherContract.WeatherEntry.getStartDateFromUri(uri);

    String[] selectionArgs;
    String selection;

    if (startDate == 0) {
      selection = sLocationSettingSelection;
      selectionArgs = new String[] {locationSetting};
    } else {
      selectionArgs = new String[] {locationSetting, Long.toString(startDate)};
      selection = sLocationSettingWithStartDateSelection;
    }

    return sWeatherByLocationSettingQueryBuilder.query(
        mOpenHelper.getReadableDatabase(),
        projection,
        selection,
        selectionArgs,
        null,
        null,
        sortOrder);
  }
 // You do not need to call this method. This is a method specifically to assist the testing
 // framework in running smoothly. You can read more at:
 // http://developer.android.com/reference/android/content/ContentProvider.html#shutdown()
 @Override
 @TargetApi(11)
 public void shutdown() {
   mOpenHelper.close();
   super.shutdown();
 }
  /*
     Students:  Here is where you will build code to test that we can insert and query the
     database.  We've done a lot of work for you.  You'll want to look in TestUtilities
     where you can use the "createWeatherValues" function.  You can
     also make use of the validateCurrentRecord function from within TestUtilities.
  */
  public void testWeatherTable() {
    // First insert the location, and then use the locationRowId to insert
    // the weather. Make sure to cover as many failure cases as you can.

    // Instead of rewriting all of the code we've already written in testLocationTable
    // we can move this code to insertLocation and then call insertLocation from both
    // tests. Why move it? We need the code to return the ID of the inserted location
    // and our testLocationTable can only return void because it's a test.

    // Step 1: Create the location //

    long locationRowId = insertLocation();

    // Make sure we have a valid row ID.
    assertFalse("Error: Location Not Inserted Correctly", locationRowId == -1L);

    // First step: Get reference to writable database
    WeatherDbHelper dbHelper = new WeatherDbHelper(mContext);
    SQLiteDatabase db = dbHelper.getWritableDatabase();

    // Create ContentValues of what you want to insert
    // (you can use the createWeatherValues TestUtilities function if you wish)

    // Step 2: Create content values with location id //

    // Second Step (Weather): Create weather values
    ContentValues weatherValues = TestUtilities.createWeatherValues(locationRowId);

    // Step 3: Insert into the table //

    // Third Step (Weather): Insert ContentValues into database and get a row ID back
    long weatherRowId = db.insert(WeatherContract.WeatherEntry.TABLE_NAME, null, weatherValues);

    assertTrue(weatherRowId != -1);

    // Step 4: Query the database and receive a Cursor back //

    // Fourth Step: Query the database and receive a Cursor back
    // A cursor is your primary interface to the query results.
    Cursor weatherCursor =
        db.query(
            WeatherContract.WeatherEntry.TABLE_NAME, // Table to Query
            null, // leaving "columns" null just returns all the columns.
            null, // cols for "where" clause
            null, // values for "where" clause
            null, // columns to group by
            null, // columns to filter by row groups
            null // sort order
            );

    // Move the cursor to a valid database row

    // Move the cursor to the first valid database row and check to see if we have any rows
    assertTrue("Error: No Records returned from location query", weatherCursor.moveToFirst());

    // Validate data in resulting Cursor with the original ContentValues
    // (you can use the validateCurrentRecord function in TestUtilities to validate the
    // query if you like)

    // Step 5: Validate against the original values //

    // Fifth Step: Validate the location Query
    TestUtilities.validateCurrentRecord(
        "testInsertReadDb weatherEntry failed to validate", weatherCursor, weatherValues);

    // Move the cursor to demonstrate that there is only one record in the database
    assertFalse(
        "Error: More than one record returned from weather query", weatherCursor.moveToNext());

    // Finally, close the cursor and database

    // Step 6: Close the Cursor and Database //

    // Sixth Step: Close cursor and db
    weatherCursor.close();
    dbHelper.close();
  }