/**
   * Computes the java String object hash code (32 bit) as the disaster ID of the message TODO: For
   * security reasons (to prevent intentional hash collisions), this should be a cryptographic hash
   * function instead of the string hash.
   *
   * @param cv
   * @return
   */
  private int getDisasterID(ContentValues cv) {
    String text = cv.getAsString(DirectMessages.COL_TEXT);

    String senderId;
    if (!cv.containsKey(DirectMessages.COL_SENDER)
        || (cv.getAsString(DirectMessages.COL_SENDER) == null)) {
      senderId = LoginActivity.getTwitterId(getContext()).toString();
    } else {
      senderId = cv.getAsString(DirectMessages.COL_SENDER);
    }

    return (new String(text + senderId)).hashCode();
  }
  /** Insert a direct message into the DB */
  @Override
  public synchronized Uri insert(Uri uri, ContentValues values) {
    int disasterId;
    Cursor c = null;
    Uri insertUri = null; // the return value;

    switch (dmUriMatcher.match(uri)) {
      case LIST_NORMAL:
        Log.d(TAG, "Insert LIST_NORMAL");
        /*
         * First, we check if we already have a direct messages with the
         * same disaster ID. If yes, two cases are possible 1 If the
         * existing message is a message of our own which was flagged to
         * insert, the insert operation may have been successful but the
         * success was not registered locally. In this case we update the
         * new message with the new information 2 It may be a hash function
         * collision (two different messages have the same hash code)
         * Probability of this should be small.
         */
        disasterId = getDisasterID(values);

        c =
            database.query(
                DBOpenHelper.TABLE_DMS,
                null,
                DirectMessages.COL_DISASTERID + "=" + disasterId,
                null,
                null,
                null,
                null);
        if (c.getCount() > 0) {

          c.moveToFirst();
          while (!c.isAfterLast()) {
            boolean isOurs =
                Long.toString(c.getLong(c.getColumnIndex(DirectMessages.COL_SENDER)))
                    .equals(LoginActivity.getTwitterId(getContext()));
            boolean isForUs =
                Long.toString(c.getLong(c.getColumnIndex(DirectMessages.COL_RECEIVER)))
                    .equals(LoginActivity.getTwitterId(getContext()));

            if (isOurs || isForUs) {

              // clear the to insert flag
              int flags = c.getInt(c.getColumnIndex(DirectMessages.COL_FLAGS));
              values.put(DirectMessages.COL_FLAGS, flags & (~DirectMessages.FLAG_TO_INSERT));

              Uri updateUri =
                  Uri.parse(
                      "content://"
                          + DirectMessages.DM_AUTHORITY
                          + "/"
                          + DirectMessages.DMS
                          + "/"
                          + Integer.toString(c.getInt(c.getColumnIndex("_id"))));
              update(updateUri, values, null, null);
              return updateUri;
            }
            c.moveToNext();
          }
        }
        c.close();
        // if none of the before was true, this is a proper new tweet which
        // we now insert
        insertUri = insertDM(values);
        // delete everything that now falls out of the buffer
        purgeDMs(values);

        break;

      case LIST_DISASTER:
        Log.d(TAG, "Insert LIST_DISASTER");
        // in disaster mode, we set the is disaster flag, encrypt and sign
        // the message
        // and sign the tweet (if we have a certificate for our key pair)
        values.put(DirectMessages.COL_ISDISASTER, 1);

        // if we already have a disaster tweet with the same disaster ID,
        // we discard the new one
        disasterId = getDisasterID(values);
        c =
            database.query(
                DBOpenHelper.TABLE_DMS,
                null,
                DirectMessages.COL_DISASTERID
                    + "="
                    + disasterId
                    + " AND "
                    + DirectMessages.COL_ISDISASTER
                    + ">0",
                null,
                null,
                null,
                null);
        if (c.getCount() > 0) {
          c.moveToFirst();
          Uri oldUri =
              Uri.parse(
                  "content://"
                      + DirectMessages.DM_AUTHORITY
                      + "/"
                      + DirectMessages.DMS
                      + "/"
                      + Long.toString(c.getLong(c.getColumnIndex("_id"))));
          c.close();
          return oldUri;
        }

        CertificateManager cm = new CertificateManager(getContext());
        KeyManager km = new KeyManager(getContext().getApplicationContext());

        // verify whether I was the author or not
        if (LoginActivity.getTwitterId(getContext())
            .equals(values.getAsInteger(DirectMessages.COL_SENDER).toString())) {

          if (cm.hasCertificate()) {

            // we put the signature
            String text = values.getAsString(DirectMessages.COL_TEXT);
            String userId = LoginActivity.getTwitterId(getContext()).toString();

            String signature = km.getSignature(new String(text + userId));
            values.put(DirectMessages.COL_SIGNATURE, signature);
            // and the certificate
            values.put(DirectMessages.COL_CERTIFICATE, cm.getCertificate());
            // and set the is_verified flag to show that the tweet is
            // signed
            values.put(DirectMessages.COL_ISVERIFIED, 1);

            // Long twitterId =
            // getIdFromScreenName(values.getAsString(DirectMessages.COL_RECEIVER_SCREENNAME));

            // TODO: obtain peers public keys and encrypt
            values.put(DirectMessages.COL_CRYPTEXT, text);
            /*
             * if (twitterId != null) { String cipherText =
             * km.encrypt(text,twitterId ); Log.i(TAG, "ciphertext: " +
             * cipherText ); if (cipherText != null) {
             * values.put(DirectMessages.COL_CRYPTEXT,cipherText );
             *
             * } }
             */

          } else values.put(DirectMessages.COL_ISVERIFIED, 0);

        } else {
          // Is it for me?
          if (values
              .getAsLong(DirectMessages.COL_RECEIVER)
              .toString()
              .equals(LoginActivity.getTwitterId(getContext()))) {

            values.put(
                DirectMessages.COL_BUFFER,
                DirectMessages.BUFFER_DISASTER_ME | DirectMessages.BUFFER_MESSAGES);
            // TODO: DECRYPT THE MESSAGE
            // String plainText =
            // km.decrypt(values.getAsString(DirectMessages.COL_CRYPTEXT));
            String plainText = values.getAsString(DirectMessages.COL_CRYPTEXT);
            // values.remove(DirectMessages.COL_CRYPTEXT);
            values.put(DirectMessages.COL_TEXT, plainText);

            // check signature
            String signature = values.getAsString(DirectMessages.COL_SIGNATURE);
            String certificate = values.getAsString(DirectMessages.COL_CERTIFICATE);

            String textForSignatureCheck =
                plainText + values.getAsString(DirectMessages.COL_SENDER);

            if (km.checkSignature(cm.parsePem(certificate), signature, textForSignatureCheck)) {
              values.put(DirectMessages.COL_ISVERIFIED, 1);
            } else values.put(DirectMessages.COL_ISVERIFIED, 0);

          } else values.put(DirectMessages.COL_BUFFER, DirectMessages.BUFFER_DISASTER_OTHERS);
        }
        c.close();
        insertUri = insertDM(values);
        // purgeTweets(values);

        break;
      default:
        throw new IllegalArgumentException("Unsupported URI: " + uri);
    }

    return insertUri;
  }
  /** Query the direct messages table TODO: Create the queries more elegantly.. */
  @Override
  public synchronized Cursor query(
      Uri uri, String[] projection, String where, String[] whereArgs, String sortOrder) {

    if (TextUtils.isEmpty(sortOrder)) sortOrder = Tweets.DEFAULT_SORT_ORDER;

    Cursor c = null;
    String sql = null;
    Intent i = null;
    switch (dmUriMatcher.match(uri)) {
      case DMS:
        Log.d(TAG, "Query DMS");
        c =
            database.query(
                DBOpenHelper.TABLE_DMS, projection, where, whereArgs, null, null, sortOrder);
        c.setNotificationUri(getContext().getContentResolver(), DirectMessages.CONTENT_URI);
        break;

      case DM_ID:
        Log.d(TAG, "Query DM_ID");
        sql =
            "SELECT  * "
                + "FROM "
                + DBOpenHelper.TABLE_DMS
                + " "
                + "WHERE "
                + DBOpenHelper.TABLE_DMS
                + "._id="
                + uri.getLastPathSegment()
                + ";";
        c = database.rawQuery(sql, null);
        c.setNotificationUri(getContext().getContentResolver(), uri);
        break;

      case USER:
        Log.d(TAG, "Query USER");
        // get the twitter user id
        sql =
            "SELECT "
                + DBOpenHelper.TABLE_USERS
                + "."
                + TwitterUsers.COL_TWITTER_USER_ID
                + " "
                + "FROM "
                + DBOpenHelper.TABLE_USERS
                + " "
                + "WHERE "
                + TwitterUsers.COL_ROW_ID
                + "="
                + uri.getLastPathSegment()
                + ";";
        c = database.rawQuery(sql, null);

        if (c.getCount() == 0) return null; // this should not happen
        c.moveToFirst();
        long twitterUserId = c.getLong(c.getColumnIndex(TwitterUsers.COL_TWITTER_USER_ID));
        c.close();

        // get the direct messages
        sql =
            "SELECT "
                + DBOpenHelper.TABLE_DMS
                + "."
                + DirectMessages.COL_ROW_ID
                + ", "
                + DBOpenHelper.TABLE_DMS
                + "."
                + DirectMessages.COL_TEXT
                + ", "
                + DBOpenHelper.TABLE_DMS
                + "."
                + DirectMessages.COL_SENDER
                + ", "
                + DBOpenHelper.TABLE_DMS
                + "."
                + DirectMessages.COL_CREATED
                + ", "
                + DBOpenHelper.TABLE_DMS
                + "."
                + DirectMessages.COL_ISDISASTER
                + ", "
                + DBOpenHelper.TABLE_DMS
                + "."
                + DirectMessages.COL_FLAGS
                + ", "
                + DBOpenHelper.TABLE_DMS
                + "."
                + DirectMessages.COL_DMID
                + ", "
                + DBOpenHelper.TABLE_USERS
                + "."
                + TwitterUsers.COL_ROW_ID
                + " AS "
                + COL_USER_ROW_ID
                + ", "
                + DBOpenHelper.TABLE_USERS
                + "."
                + TwitterUsers.COL_SCREEN_NAME
                + ", "
                + DBOpenHelper.TABLE_USERS
                + "."
                + TwitterUsers.COL_NAME
                + ", "
                + DBOpenHelper.TABLE_USERS
                + "."
                + TwitterUsers.COL_PROFILE_IMAGE_URI
                + " FROM "
                + DBOpenHelper.TABLE_DMS
                + " "
                + "JOIN "
                + DBOpenHelper.TABLE_USERS
                + " "
                + "ON "
                + DBOpenHelper.TABLE_DMS
                + "."
                + DirectMessages.COL_SENDER
                + "="
                + DBOpenHelper.TABLE_USERS
                + "."
                + TwitterUsers.COL_TWITTER_USER_ID
                + " "
                + "WHERE "
                + DBOpenHelper.TABLE_DMS
                + "."
                + DirectMessages.COL_RECEIVER
                + "="
                + twitterUserId
                + " "
                + "OR "
                + DBOpenHelper.TABLE_DMS
                + "."
                + DirectMessages.COL_SENDER
                + "="
                + twitterUserId
                + " "
                + "ORDER BY "
                + DBOpenHelper.TABLE_DMS
                + "."
                + DirectMessages.COL_CREATED
                + " DESC "
                + "LIMIT 100";

        c = database.rawQuery(sql, null);
        // TODO: Correct notification URI
        c.setNotificationUri(getContext().getContentResolver(), DirectMessages.CONTENT_URI);

        break;
      case USERS:
        Log.d(TAG, "Query USERS");
        // selects the last DM of which the given user is either a sender or
        // recepient
        String subQuery1 =
            "SELECT "
                + DirectMessages.COL_TEXT
                + " "
                + "FROM "
                + DBOpenHelper.TABLE_DMS
                + " "
                + "WHERE "
                + DBOpenHelper.TABLE_DMS
                + "."
                + DirectMessages.COL_RECEIVER
                + "="
                + DBOpenHelper.TABLE_USERS
                + "."
                + TwitterUsers.COL_TWITTER_USER_ID
                + " "
                + "OR "
                + DBOpenHelper.TABLE_DMS
                + "."
                + DirectMessages.COL_SENDER
                + "="
                + DBOpenHelper.TABLE_USERS
                + "."
                + TwitterUsers.COL_TWITTER_USER_ID
                + " "
                + "ORDER BY "
                + DBOpenHelper.TABLE_DMS
                + "."
                + DirectMessages.COL_CREATED
                + " DESC "
                + "LIMIT 1";
        // selects the timestamp of the last DM of which the given user is
        // either a sender or recepient
        String subQuery2 =
            "SELECT "
                + DirectMessages.COL_CREATED
                + " "
                + "FROM "
                + DBOpenHelper.TABLE_DMS
                + " "
                + "WHERE "
                + DBOpenHelper.TABLE_DMS
                + "."
                + DirectMessages.COL_RECEIVER
                + "="
                + DBOpenHelper.TABLE_USERS
                + "."
                + TwitterUsers.COL_TWITTER_USER_ID
                + " "
                + "OR "
                + DBOpenHelper.TABLE_DMS
                + "."
                + DirectMessages.COL_SENDER
                + "="
                + DBOpenHelper.TABLE_USERS
                + "."
                + TwitterUsers.COL_TWITTER_USER_ID
                + " "
                + "ORDER BY "
                + DBOpenHelper.TABLE_DMS
                + "."
                + DirectMessages.COL_CREATED
                + " DESC "
                + "LIMIT 1";

        // selects all users who have sent or received at least one DM
        sql =
            "select "
                + DBOpenHelper.TABLE_USERS
                + "."
                + TwitterUsers.COL_ROW_ID
                + ", "
                + DBOpenHelper.TABLE_USERS
                + "."
                + TwitterUsers.COL_TWITTER_USER_ID
                + ", "
                + DBOpenHelper.TABLE_USERS
                + "."
                + TwitterUsers.COL_SCREEN_NAME
                + ", "
                + DBOpenHelper.TABLE_USERS
                + "."
                + TwitterUsers.COL_NAME
                + ", "
                + DBOpenHelper.TABLE_USERS
                + "."
                + TwitterUsers.COL_PROFILE_IMAGE_URI
                + ", "
                + "("
                + subQuery1
                + ") AS text, "
                + "("
                + subQuery2
                + ") AS created "
                + "FROM "
                + DBOpenHelper.TABLE_USERS
                + " "
                + "LEFT JOIN "
                + DBOpenHelper.TABLE_DMS
                + " AS sent ON "
                + DBOpenHelper.TABLE_USERS
                + "."
                + TwitterUsers.COL_TWITTER_USER_ID
                + "=sent."
                + DirectMessages.COL_SENDER
                + " "
                + "LEFT JOIN "
                + DBOpenHelper.TABLE_DMS
                + " AS received ON "
                + DBOpenHelper.TABLE_USERS
                + "."
                + TwitterUsers.COL_TWITTER_USER_ID
                + "=received."
                + DirectMessages.COL_RECEIVER
                + " "
                + "WHERE "
                + "(sent."
                + DirectMessages.COL_TEXT
                + " IS NOT NULL OR "
                + "received."
                + DirectMessages.COL_TEXT
                + " IS NOT NULL) "
                + "AND "
                + DBOpenHelper.TABLE_USERS
                + "."
                + TwitterUsers.COL_TWITTER_USER_ID
                + "<>"
                + LoginActivity.getTwitterId(getContext())
                + " "
                + "GROUP BY "
                + DBOpenHelper.TABLE_USERS
                + "."
                + TwitterUsers.COL_TWITTER_USER_ID
                + " "
                + "ORDER BY created DESC LIMIT 100;";

        Log.e(TAG, sql);

        c = database.rawQuery(sql, null);
        // TODO: Correct notification URI
        c.setNotificationUri(getContext().getContentResolver(), DirectMessages.CONTENT_URI);

        // start synch service with a synch DMs request
        i = new Intent(getContext(), TwitterSyncService.class);
        i.putExtra(
            TwitterSyncService.EXTRA_KEY_ACTION, TwitterSyncService.EXTRA_ACTION_SYNC_MESSAGES);
        getContext().startService(i);
        break;
      case LIST_ALL:
        // TODO
        break;

      case LIST_DISASTER:
        Log.i(TAG, "Query DMS Disaster");
        c =
            database.query(
                DBOpenHelper.TABLE_DMS,
                projection,
                DirectMessages.COL_BUFFER
                    + "&"
                    + DirectMessages.BUFFER_MYDISASTER
                    + "!=0"
                    + " OR "
                    + DirectMessages.COL_BUFFER
                    + "&"
                    + DirectMessages.BUFFER_DISASTER_OTHERS
                    + "!=0",
                whereArgs,
                null,
                null,
                sortOrder);
        c.setNotificationUri(getContext().getContentResolver(), DirectMessages.CONTENT_URI);
        break;

      case LIST_NORMAL:
        // TODO
        break;

      case INCOMING_RECEIVED_AFTER:
        Log.d(TAG, "Query INCOMING_RECEIVED_AFTER");

        sql =
            "SELECT "
                + DBOpenHelper.TABLE_DMS
                + "._id, "
                + DBOpenHelper.TABLE_DMS
                + "."
                + DirectMessages.COL_TEXT
                + ", "
                + DBOpenHelper.TABLE_DMS
                + "."
                + DirectMessages.COL_SENDER
                + ", "
                + DBOpenHelper.TABLE_DMS
                + "."
                + DirectMessages.COL_CREATED
                + ", "
                + DBOpenHelper.TABLE_DMS
                + "."
                + DirectMessages.COL_ISDISASTER
                + ", "
                + DBOpenHelper.TABLE_DMS
                + "."
                + DirectMessages.COL_FLAGS
                + ", "
                + DBOpenHelper.TABLE_DMS
                + "."
                + DirectMessages.COL_DMID
                + ", "
                + DBOpenHelper.TABLE_USERS
                + "._id AS "
                + COL_USER_ROW_ID
                + ", "
                + DBOpenHelper.TABLE_USERS
                + "."
                + TwitterUsers.COL_SCREEN_NAME
                + ", "
                + DBOpenHelper.TABLE_USERS
                + "."
                + TwitterUsers.COL_NAME
                + ", "
                + DBOpenHelper.TABLE_USERS
                + "."
                + TwitterUsers.COL_PROFILE_IMAGE_URI
                + " "
                + "FROM "
                + DBOpenHelper.TABLE_DMS
                + " "
                + "JOIN "
                + DBOpenHelper.TABLE_USERS
                + " "
                + "ON "
                + DBOpenHelper.TABLE_DMS
                + "."
                + DirectMessages.COL_SENDER
                + "="
                + DBOpenHelper.TABLE_USERS
                + "."
                + TwitterUsers.COL_TWITTER_USER_ID
                + " "
                + "WHERE "
                + DBOpenHelper.TABLE_DMS
                + "."
                + DirectMessages.COL_RECEIVER
                + "=="
                + LoginActivity.getTwitterId(getContext())
                + " AND "
                + DBOpenHelper.TABLE_DMS
                + "."
                + DirectMessages.COL_RECEIVED
                + ">"
                + uri.getLastPathSegment()
                + " "
                + "ORDER BY "
                + DBOpenHelper.TABLE_DMS
                + "."
                + DirectMessages.COL_CREATED
                + " DESC "
                + "LIMIT 100";

        c = database.rawQuery(sql, null);
        // TODO: Correct notification URI
        c.setNotificationUri(getContext().getContentResolver(), DirectMessages.CONTENT_URI);

        break;
      default:
        throw new IllegalArgumentException("Unsupported URI: " + uri);
    }

    return c;
  }