/**
   * Retrieve credentials using the provided authorization code.
   *
   * <p>This function exchanges the authorization code for an access token and queries the UserInfo
   * API to retrieve the user's e-mail address. If a refresh token has been retrieved along with an
   * access token, it is stored in the application database using the user's e-mail address as key.
   * If no refresh token has been retrieved, the function checks in the application database for one
   * and returns it if found or throws a NoRefreshTokenException with the authorization URL to
   * redirect the user to.
   *
   * @return Credential containing an access and refresh token.
   * @throws NoRefreshTokenException No refresh token could be retrieved from the available sources.
   * @throws IOException
   */
  public Credential getActiveCredential() throws NoRefreshTokenException, IOException {
    String userId = (String) request.getSession().getAttribute(USER_ID_KEY);
    Credential credential = null;
    try {
      // Only bother looking for a Credential if the user has an existing
      // session with their email address stored.
      if (userId != null) {
        credential = getStoredCredential(userId);
      }

      // No Credential was stored for the current user or no refresh token is
      // available.
      // If an authorizationCode is present, upgrade it into an
      // access token and hopefully a refresh token.
      if ((credential == null || credential.getRefreshToken() == null)
          && request.getParameter("code") != null) {
        credential = exchangeCode(request.getParameter("code"));
        if (credential != null) {
          Userinfo userInfo = getUserInfo(credential);
          userId = userInfo.getId();
          request.getSession().setAttribute(USER_ID_KEY, userId);
          request.getSession().setAttribute(EMAIL_KEY, userInfo.getEmail());
          // Sometimes we won't get a refresh token after upgrading a code.
          // This won't work for our app, because the user can land directly
          // at our app without first visiting Google Drive. Therefore,
          // only bother to store the Credential if it has a refresh token.
          // If it doesn't, we'll get one below.
          if (credential.getRefreshToken() != null) {
            credentialStore.store(userId, credential);
          }
        }
      }

      if (credential == null || credential.getRefreshToken() == null) {
        // No refresh token has been retrieved.
        // Start a "fresh" OAuth 2.0 flow so that we can get a refresh token.
        String email = (String) request.getSession().getAttribute(EMAIL_KEY);
        String authorizationUrl = getAuthorizationUrl(email);
        throw new NoRefreshTokenException(authorizationUrl);
      }
    } catch (CodeExchangeException e) {
      // The code the user arrived here with was bad.  This pretty much never
      // happens. In a production application, we'd either redirect the user
      // somewhere like a home page, or show them a vague error mentioning
      // that they probably didn't arrive to our app from Google Drive.
      e.printStackTrace();
    } catch (NoUserIdException e) {
      // This is bad because it means the user either denied us access
      // to their email address, or we couldn't fetch it for some reason.
      // This is unrecoverable. In a production application, we'd show the
      // user a message saying that we need access to their email address
      // to work.
      e.printStackTrace();
    }
    return credential;
  }
  protected void updateCustomFields(
      User user, Userinfo userinfo, String accessToken, String refreshToken)
      throws PortalException, SystemException {

    ExpandoValueLocalServiceUtil.addValue(
        user.getCompanyId(),
        User.class.getName(),
        ExpandoTableConstants.DEFAULT_TABLE_NAME,
        GOOGLE_ACCESS_TOKEN,
        user.getUserId(),
        accessToken);

    ExpandoValueLocalServiceUtil.addValue(
        user.getCompanyId(),
        User.class.getName(),
        ExpandoTableConstants.DEFAULT_TABLE_NAME,
        GOOGLE_REFRESH_TOKEN,
        user.getUserId(),
        refreshToken);

    ExpandoValueLocalServiceUtil.addValue(
        user.getCompanyId(),
        User.class.getName(),
        ExpandoTableConstants.DEFAULT_TABLE_NAME,
        GOOGLE_USER_ID,
        user.getUserId(),
        userinfo.getId());
  }
  protected Userinfo getUserInfo(Credential credentials) throws NoSuchUserIdException {

    Oauth2.Builder builder =
        new Oauth2.Builder(new NetHttpTransport(), new JacksonFactory(), credentials);

    Oauth2 oauth2 = builder.build();

    Userinfo userInfo = null;

    try {
      userInfo = oauth2.userinfo().get().execute();
    } catch (IOException e) {
      System.err.println("An error occurred: " + e);
    }

    if ((userInfo != null) && (userInfo.getId() != null)) {
      return userInfo;
    } else {
      throw new NoSuchUserIdException();
    }
  }
  protected User setGoogleCredentials(HttpSession session, long companyId, Credential credential)
      throws Exception {

    Userinfo userinfo = getUserInfo(credential);

    if (userinfo == null) {
      return null;
    }

    User user = null;

    String emailAddress = userinfo.getEmail();

    if ((user == null) && Validator.isNotNull(emailAddress)) {
      user = UserLocalServiceUtil.fetchUserByEmailAddress(companyId, emailAddress);

      if ((user != null) && (user.getStatus() != WorkflowConstants.STATUS_INCOMPLETE)) {

        session.setAttribute("GOOGLE_USER_EMAIL_ADDRESS", emailAddress);
      }
    }

    if (user != null) {
      if (user.getStatus() == WorkflowConstants.STATUS_INCOMPLETE) {
        session.setAttribute("GOOGLE_INCOMPLETE_USER_ID", userinfo.getId());

        user.setEmailAddress(userinfo.getEmail());
        user.setFirstName(userinfo.getGivenName());
        user.setLastName(userinfo.getFamilyName());

        return user;
      }

      user = updateUser(user, userinfo);
    } else {
      user = addUser(session, companyId, userinfo);
    }

    if (DeployManagerUtil.isDeployed(_GOOGLE_DRIVE_CONTEXT)) {
      updateCustomFields(user, userinfo, credential.getAccessToken(), credential.getRefreshToken());
    }

    return user;
  }
  protected User updateUser(User user, Userinfo userinfo) throws Exception {
    String emailAddress = userinfo.getEmail();
    String firstName = userinfo.getGivenName();
    String lastName = userinfo.getFamilyName();
    boolean male = Validator.equals(userinfo.getGender(), "male");

    if (emailAddress.equals(user.getEmailAddress())
        && firstName.equals(user.getFirstName())
        && lastName.equals(user.getLastName())
        && (male == user.isMale())) {

      return user;
    }

    Contact contact = user.getContact();

    Calendar birthdayCal = CalendarFactoryUtil.getCalendar();

    birthdayCal.setTime(contact.getBirthday());

    int birthdayMonth = birthdayCal.get(Calendar.MONTH);
    int birthdayDay = birthdayCal.get(Calendar.DAY_OF_MONTH);
    int birthdayYear = birthdayCal.get(Calendar.YEAR);

    long[] groupIds = null;
    long[] organizationIds = null;
    long[] roleIds = null;
    List<UserGroupRole> userGroupRoles = null;
    long[] userGroupIds = null;

    ServiceContext serviceContext = new ServiceContext();

    if (!StringUtil.equalsIgnoreCase(emailAddress, user.getEmailAddress())) {

      UserLocalServiceUtil.updateEmailAddress(
          user.getUserId(), StringPool.BLANK, emailAddress, emailAddress);
    }

    UserLocalServiceUtil.updateEmailAddressVerified(user.getUserId(), true);

    return UserLocalServiceUtil.updateUser(
        user.getUserId(),
        StringPool.BLANK,
        StringPool.BLANK,
        StringPool.BLANK,
        false,
        user.getReminderQueryQuestion(),
        user.getReminderQueryAnswer(),
        user.getScreenName(),
        emailAddress,
        0,
        user.getOpenId(),
        user.getLanguageId(),
        user.getTimeZoneId(),
        user.getGreeting(),
        user.getComments(),
        firstName,
        user.getMiddleName(),
        lastName,
        contact.getPrefixId(),
        contact.getSuffixId(),
        male,
        birthdayMonth,
        birthdayDay,
        birthdayYear,
        contact.getSmsSn(),
        contact.getAimSn(),
        contact.getFacebookSn(),
        contact.getIcqSn(),
        contact.getJabberSn(),
        contact.getMsnSn(),
        contact.getMySpaceSn(),
        contact.getSkypeSn(),
        contact.getTwitterSn(),
        contact.getYmSn(),
        contact.getJobTitle(),
        groupIds,
        organizationIds,
        roleIds,
        userGroupRoles,
        userGroupIds,
        serviceContext);
  }
  protected User addUser(HttpSession session, long companyId, Userinfo userinfo) throws Exception {

    long creatorUserId = 0;
    boolean autoPassword = true;
    String password1 = StringPool.BLANK;
    String password2 = StringPool.BLANK;
    boolean autoScreenName = true;
    String screenName = StringPool.BLANK;
    String emailAddress = userinfo.getEmail();
    String openId = StringPool.BLANK;
    Locale locale = LocaleUtil.getDefault();
    String firstName = userinfo.getGivenName();
    String middleName = StringPool.BLANK;
    String lastName = userinfo.getFamilyName();
    int prefixId = 0;
    int suffixId = 0;
    boolean male = Validator.equals(userinfo.getGender(), "male");
    int birthdayMonth = Calendar.JANUARY;
    int birthdayDay = 1;
    int birthdayYear = 1970;
    String jobTitle = StringPool.BLANK;
    long[] groupIds = null;
    long[] organizationIds = null;
    long[] roleIds = null;
    long[] userGroupIds = null;
    boolean sendEmail = true;

    ServiceContext serviceContext = new ServiceContext();

    User user =
        UserLocalServiceUtil.addUser(
            creatorUserId,
            companyId,
            autoPassword,
            password1,
            password2,
            autoScreenName,
            screenName,
            emailAddress,
            0,
            openId,
            locale,
            firstName,
            middleName,
            lastName,
            prefixId,
            suffixId,
            male,
            birthdayMonth,
            birthdayDay,
            birthdayYear,
            jobTitle,
            groupIds,
            organizationIds,
            roleIds,
            userGroupIds,
            sendEmail,
            serviceContext);

    user = UserLocalServiceUtil.updateLastLogin(user.getUserId(), user.getLoginIP());

    user = UserLocalServiceUtil.updatePasswordReset(user.getUserId(), false);

    user = UserLocalServiceUtil.updateEmailAddressVerified(user.getUserId(), true);

    session.setAttribute("GOOGLE_USER_EMAIL_ADDRESS", emailAddress);

    return user;
  }