@Override
  protected void onPostExecute(Connection.Response response) {
    if (response != null && response.statusCode() == 200) {
      try {
        Log.v(TAG, "Response to JSON request: " + response.body());
        JSONObject root = new JSONObject(response.body());

        boolean success = "success".equals(root.getString("type"));
        int points = root.getInt("points");

        IHasEnterableGiveaways fragment = getFragment();
        fragment.onEnterLeaveResult(giveawayId, getWhat(), success, true);

        // Update the points we have.
        SteamGiftsUserData.getCurrent().setPoints(points);

        if (fragment instanceof Fragment
            && "error".equals(root.getString("type"))
            && "Sync Required".equals(root.getString("msg"))) {
          ((Fragment) fragment)
              .getActivity()
              .startActivity(new Intent(((Fragment) fragment).getContext(), SyncActivity.class));
        }

        return;
      } catch (JSONException e) {
        Log.e(TAG, "Failed to parse JSON object", e);
      }
    }

    getFragment().onEnterLeaveResult(giveawayId, getWhat(), null, false);
  }
  @Override
  protected List<GiveawayGroup> doInBackground(Void... params) {
    Log.d(TAG, "Fetching giveaways for page " + page);

    try {
      // Fetch the Giveaway page

      Connection jsoup =
          Jsoup.connect("http://www.steamgifts.com/giveaway/" + path + "/groups/search")
              .userAgent(Constants.JSOUP_USER_AGENT)
              .timeout(Constants.JSOUP_TIMEOUT);
      jsoup.data("page", Integer.toString(page));

      if (SteamGiftsUserData.getCurrent(fragment.getContext()).isLoggedIn())
        jsoup.cookie(
            "PHPSESSID", SteamGiftsUserData.getCurrent(fragment.getContext()).getSessionId());
      Document document = jsoup.get();

      SteamGiftsUserData.extract(fragment.getContext(), document);

      // Parse all rows of groups
      Elements groups = document.select(".table__row-inner-wrap");
      Log.d(TAG, "Found inner " + groups.size() + " elements");

      List<GiveawayGroup> groupList = new ArrayList<>();
      for (Element element : groups) {
        Element link = element.select(".table__column__heading").first();

        // Basic information
        String title = link.text();
        String id = link.attr("href").substring(7, 12);

        String avatar = null;
        Element avatarNode = element.select(".global__image-inner-wrap").first();
        if (avatarNode != null) avatar = Utils.extractAvatar(avatarNode.attr("style"));

        GiveawayGroup group = new GiveawayGroup(id, title, avatar);
        groupList.add(group);
      }

      return groupList;
    } catch (IOException e) {
      Log.e(TAG, "Error fetching URL", e);
      return null;
    }
  }
 @Override
 public boolean onOptionsItemSelected(MenuItem item) {
   int itemId = item.getItemId();
   if (itemId == R.id.user) {
     showProfile(SteamGiftsUserData.getCurrent().getName());
     return true;
   } else if (itemId == R.id.mark_read) {
     new MarkMessagesReadTask(this, adapter.getXsrfToken()).execute();
     return true;
   } else {
     return super.onOptionsItemSelected(item);
   }
 }
  @Override
  public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
    if (SteamGiftsUserData.getCurrent().isLoggedIn()) {
      menu.setHeaderTitle(R.string.actions);

      if (writeCommentListener != null) {
        menu.add(0, 1, 0, R.string.add_comment)
            .setOnMenuItemClickListener(
                new MenuItem.OnMenuItemClickListener() {
                  @Override
                  public boolean onMenuItemClick(MenuItem item) {
                    if (writeCommentListener != null) writeCommentListener.onClick(itemView);
                    return true;
                  }
                });
      }
    }
  }
  public void onMarkedMessagesRead() {
    for (int i = 0, size = adapter.getItemCount(); i < size; ++i) {
      IEndlessAdaptable element = adapter.getItem(i);
      if (!(element instanceof Comment)) continue;

      Comment comment = (Comment) element;

      if (comment.isHighlighted()) {
        comment.setHighlighted(false);
        adapter.notifyItemChanged(i);
      }
    }

    adapter.setXsrfToken(null);
    getActivity().supportInvalidateOptionsMenu();

    // We no longer have any notifications
    SteamGiftsUserData.getCurrent().setMessageNotification(0);
  }
    @Override
    public void addItems(
        List<? extends IEndlessAdaptable> items, boolean clearExistingItems, String xsrfToken) {
      if (items == null || items.size() == 0) {
        Log.d(TAG, "got no won games -at all-");
        return;
      }

      SharedPreferences sharedPreferences =
          context.getSharedPreferences(PREFS_NOTIFICATIONS_SERVICE, Context.MODE_PRIVATE);

      // Interestingly enough, the question with re-rolls etc is most likely that we can't reliably
      // tell these giveaways will arrive in order.
      Set<String> knownWonGames =
          sharedPreferences.getStringSet(PREF_KEY_LAST_DISMISSED_WON_GAMES, new HashSet<String>());

      List<Giveaway> mostRecentWonGames = new ArrayList<>(MAX_DISPLAYED_GIVEAWAYS);
      for (IEndlessAdaptable item : items) {
        if (item instanceof Giveaway) {
          Giveaway giveaway = (Giveaway) item;

          // If we marked this giveaway as received yet, we don't want to show it.
          if (!giveaway.isEntered()) continue;

          if (knownWonGames.contains(giveaway.getGiveawayId())) continue;

          mostRecentWonGames.add(giveaway);
          if (knownWonGames.size() == MAX_DISPLAYED_NOTIFICATIONS) break;
        }
      }

      if (mostRecentWonGames.isEmpty()) {
        Log.v(TAG, "Got no new won games, or we've dismissed the last giveaways we could see");
      } else {
        String lastShownId = sharedPreferences.getString(PREF_KEY_LAST_SHOWN_WON_GAME, null);

        // While this same comment may appear in a later notification, we're establishing that it
        // may not be the first comment again.

        // This is simply so you're not being notified about the same message(s) over and over
        // again, and if it's still unread when a new
        // message is pushed, we may show it again.

        // Contrary, dismissing a message will never show it to you again. "Ignoring" a message here
        // will simply show it stacked
        // with other new messages in the future.
        Giveaway firstGiveaway = mostRecentWonGames.get(0);
        if (lastShownId != null && lastShownId.equals(firstGiveaway.getGiveawayId())) {
          // We've shown a notification for the very same comment before, so do nothing...
          Log.d(TAG, "Most recent won game has the same id as the last shown won game");
          return;
        }

        lastGiveawayIds = new ArrayList<>();
        for (IEndlessAdaptable item : items) {
          if (item instanceof Giveaway) lastGiveawayIds.add(((Giveaway) item).getGiveawayId());
        }

        // Save the last comment id
        sharedPreferences
            .edit()
            .putString(PREF_KEY_LAST_SHOWN_WON_GAME, firstGiveaway.getGiveawayId())
            .apply();

        // Do we show a single (expanded) content or a bunch of comments?
        if (mostRecentWonGames.size() == 1) {
          showNotification(
              context,
              NOTIFICATION_ID,
              R.drawable.ic_gift,
              String.format(
                  context.getString(R.string.notification_won_game),
                  mostRecentWonGames.get(0).getTitle()),
              mostRecentWonGames.get(0).getRelativeEndTime(context),
              getViewIntent(),
              getDeleteIntent());
        } else {
          List<CharSequence> texts = new ArrayList<>(mostRecentWonGames.size());
          for (Giveaway giveaway : mostRecentWonGames) texts.add(giveaway.getTitle());

          showNotification(
              context,
              NOTIFICATION_ID,
              R.drawable.ic_gift,
              String.format(
                  context.getString(R.string.notification_won_games),
                  SteamGiftsUserData.getCurrent(context).getWonNotification()),
              texts,
              getViewIntent(),
              getDeleteIntent());
        }

        Log.d(TAG, "Shown " + mostRecentWonGames.size() + " won games as notification");
      }
    }