/*
   * This method is called by the application when the user clicks on 'Sign In
   * with Intuit' button from the Login Page to get the OpenId.
   */
  @RequestMapping(value = "/initialize.htm", method = RequestMethod.GET)
  public void initialize(final HttpServletRequest request, final HttpServletResponse response)
      throws IOException {

    LOG.info("### OpenIdController -> initialize() - started ###");

    final List<DiscoveryInformation> discoveries = new ArrayList<DiscoveryInformation>();
    final ConsumerManager manager = new ConsumerManager();

    manager.setAssociations(new InMemoryConsumerAssociationStore());
    manager.setNonceVerifier(new InMemoryNonceVerifier(5000));
    manager.setMinAssocSessEnc(AssociationSessionType.DH_SHA256);

    DiscoveryInformation discovered = null;

    try {
      LOG.info("OpenID Provider URL = " + WebUtils.OPENID_PROVIDER_URL);
      discovered = new DiscoveryInformation(new URL(WebUtils.OPENID_PROVIDER_URL));
    } catch (DiscoveryException e) {
      LOG.error(e.getLocalizedMessage());
    } catch (MalformedURLException me) {
      LOG.error(me.getLocalizedMessage());
    }

    discoveries.add(discovered);

    final DiscoveryInformation discoveryInfo = manager.associate(discoveries);
    request.getSession().setAttribute("openid-disc", discoveryInfo);

    final FetchRequest fetch = FetchRequest.createFetchRequest();

    try {
      fetch.addAttribute("FirstName", "http://axschema.org/namePerson/first", true);
      fetch.addAttribute("LastName", "http://axschema.org/namePerson/last", true);
      fetch.addAttribute("Email", "http://axschema.org/contact/email", true);
      fetch.addAttribute("RealmId", "http://axschema.org/intuit/realmId", true);
    } catch (MessageException e) {
      LOG.error(e.getLocalizedMessage());
    }

    fetch.setCount("Email", 3);

    AuthRequest authReq = null;
    LOG.info("openIdReturnUrl = " + WebUtils.OPENID_RETURN_URL);
    try {
      authReq = manager.authenticate(discoveryInfo, WebUtils.OPENID_RETURN_URL);
      authReq.addExtension(fetch);
    } catch (MessageException e) {
      LOG.error(e.getLocalizedMessage());
    } catch (ConsumerException e) {
      LOG.error(e.getLocalizedMessage());
    }

    final HttpSession session = request.getSession();
    LOG.info("Session Id : " + session.getId());
    session.setAttribute("consumerManager", manager);
    LOG.info("authReq.getDestinationUrl: " + authReq.getDestinationUrl(true));
    LOG.info("### OpenIdController -> initialize() - completed ###");

    response.sendRedirect(authReq.getDestinationUrl(true));
  }
  // authentication request
  public String authRequest(
      String userSuppliedString, HttpServletRequest httpReq, HttpServletResponse httpResp)
      throws IOException, ServletException {

    if (OpenIDRealm.instance == null) {
      ServletOutputStream out = httpResp.getOutputStream();
      httpResp.setContentType("text/html; charset=\"UTF-8\"");
      httpResp.addHeader("pragma", "no-cache");
      httpResp.addHeader("Cache-Control", "no-cache");

      httpResp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);

      out.print("<html><head>");
      out.print("<title>OpenIDServlet Error</title>");
      out.print("<link rel=\"stylesheet\" type=\"text/css\" href=\"error.css\"></link></head>");
      out.print("<body><div id=\"container\"><h1>Error found</h1>");

      out.print("<h2>Message:");
      out.print("OpenID realm wasn't initialized.");
      out.print("</h2>");

      // out.print(HTTPUtils.printStackTraceHTML(t));

      out.print("</div></body></html>");
      return null;
    }
    try {
      String returnAfterAuthentication = httpReq.getParameter("return_to");

      // configure the return_to URL where your application will receive
      // the authentication responses from the OpenID provider
      String returnToUrl =
          httpReq.getRequestURL().toString()
              + "?is_return=true&exist_return="
              + returnAfterAuthentication;

      // perform discovery on the user-supplied identifier
      List<?> discoveries = manager.discover(userSuppliedString);

      // attempt to associate with the OpenID provider
      // and retrieve one service endpoint for authentication
      DiscoveryInformation discovered = manager.associate(discoveries);

      // store the discovery information in the user's session
      httpReq.getSession().setAttribute("openid-disc", discovered);

      // obtain a AuthRequest message to be sent to the OpenID provider
      AuthRequest authReq = manager.authenticate(discovered, returnToUrl);

      if (authReq.getOPEndpoint().indexOf("myopenid.com") > 0) {
        SRegRequest sregReq = SRegRequest.createFetchRequest();

        sregReq.addAttribute(AXSchemaType.FULLNAME.name().toLowerCase(), true);
        sregReq.addAttribute(AXSchemaType.EMAIL.name().toLowerCase(), true);
        sregReq.addAttribute(AXSchemaType.COUNTRY.name().toLowerCase(), true);
        sregReq.addAttribute(AXSchemaType.LANGUAGE.name().toLowerCase(), true);

        authReq.addExtension(sregReq);
      } else {

        FetchRequest fetch = FetchRequest.createFetchRequest();

        fetch.addAttribute(
            AXSchemaType.FIRSTNAME.getAlias(), AXSchemaType.FIRSTNAME.getNamespace(), true);
        fetch.addAttribute(
            AXSchemaType.LASTNAME.getAlias(), AXSchemaType.LASTNAME.getNamespace(), true);
        fetch.addAttribute(AXSchemaType.EMAIL.getAlias(), AXSchemaType.EMAIL.getNamespace(), true);
        fetch.addAttribute(
            AXSchemaType.COUNTRY.getAlias(), AXSchemaType.COUNTRY.getNamespace(), true);
        fetch.addAttribute(
            AXSchemaType.LANGUAGE.getAlias(), AXSchemaType.LANGUAGE.getNamespace(), true);

        // wants up to three email addresses
        fetch.setCount(AXSchemaType.EMAIL.getAlias(), 3);

        authReq.addExtension(fetch);
      }

      if (!discovered.isVersion2()) {
        // Option 1: GET HTTP-redirect to the OpenID Provider endpoint
        // The only method supported in OpenID 1.x
        // redirect-URL usually limited ~2048 bytes
        httpResp.sendRedirect(authReq.getDestinationUrl(true));
        return null;

      } else {
        // Option 2: HTML FORM Redirection (Allows payloads >2048 bytes)

        Object OPEndpoint = authReq.getDestinationUrl(false);

        ServletOutputStream out = httpResp.getOutputStream();

        httpResp.setContentType("text/html; charset=UTF-8");
        httpResp.addHeader("pragma", "no-cache");
        httpResp.addHeader("Cache-Control", "no-cache");

        out.println("<html xmlns=\"http://www.w3.org/1999/xhtml\">");
        out.println("<head>");
        out.println("    <title>OpenID HTML FORM Redirection</title>");
        out.println("</head>");
        out.println("<body onload=\"document.forms['openid-form-redirection'].submit();\">");
        out.println(
            "    <form name=\"openid-form-redirection\" action=\""
                + OPEndpoint
                + "\" method=\"post\" accept-charset=\"utf-8\">");

        Map<String, String> parameterMap = authReq.getParameterMap();
        for (Entry<String, String> entry : parameterMap.entrySet()) {
          out.println(
              "	<input type=\"hidden\" name=\""
                  + entry.getKey()
                  + "\" value=\""
                  + entry.getValue()
                  + "\"/>");
        }

        out.println("        <button type=\"submit\">Continue...</button>");
        out.println("    </form>");
        out.println("</body>");
        out.println("</html>");

        out.flush();
      }
    } catch (OpenIDException e) {
      // present error to the user
      LOG.debug("OpenIDException", e);

      ServletOutputStream out = httpResp.getOutputStream();
      httpResp.setContentType("text/html; charset=\"UTF-8\"");
      httpResp.addHeader("pragma", "no-cache");
      httpResp.addHeader("Cache-Control", "no-cache");

      httpResp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);

      out.print("<html><head>");
      out.print("<title>OpenIDServlet Error</title>");
      out.print("<link rel=\"stylesheet\" type=\"text/css\" href=\"error.css\"></link></head>");
      out.print("<body><div id=\"container\"><h1>Error found</h1>");

      out.print("<h2>Message:");
      out.print(e.getMessage());
      out.print("</h2>");

      Throwable t = e.getCause();
      if (t != null) {
        // t can be null
        out.print(HTTPUtils.printStackTraceHTML(t));
      }

      out.print("</div></body></html>");
    }

    return null;
  }