/*
 * Copyright 2013 Google Inc. All Rights Reserved.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.appengine.tck.login;

import java.lang.reflect.Method;
import java.net.URI;
import java.net.URLEncoder;
import java.util.List;
import java.util.Set;

import com.google.appengine.tck.base.TestBase;
import com.google.appengine.tck.driver.DefaultLoginHandler;
import com.google.appengine.tck.driver.LoginHandler;
import org.jboss.arquillian.container.spi.client.protocol.ProtocolDescription;
import org.jboss.arquillian.container.spi.client.protocol.metadata.HTTPContext;
import org.jboss.arquillian.container.spi.client.protocol.metadata.ProtocolMetaData;
import org.jboss.arquillian.container.spi.event.container.AfterDeploy;
import org.jboss.arquillian.container.test.impl.domain.ProtocolDefinition;
import org.jboss.arquillian.container.test.impl.domain.ProtocolRegistry;
import org.jboss.arquillian.core.api.Instance;
import org.jboss.arquillian.core.api.annotation.Inject;
import org.jboss.arquillian.core.api.annotation.Observes;
import org.jboss.arquillian.core.spi.EventContext;
import org.jboss.arquillian.protocol.modules.ModulesApi;
import org.jboss.arquillian.protocol.modules.ModulesProtocolConfiguration;
import org.jboss.arquillian.test.spi.event.suite.Before;
import org.openqa.selenium.By;
import org.openqa.selenium.Cookie;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;

/**
 * @author Julien Deray
 * @author Ales Justin
 */
public class UserLogin {
    static final String USER_LOGIN_SERVLET_PATH = "user-login-builtin";

    @Inject
    private Instance<ProtocolRegistry> registry;

    private ProtocolMetaData protocolMetaData;

    public void prepare(@Observes AfterDeploy event, ProtocolMetaData data) {
        this.protocolMetaData = data;
    }

    protected URI getBaseURI(Method method) throws Exception {
        ProtocolDefinition definition = registry.get().getProtocol(ProtocolDescription.DEFAULT);
        ModulesProtocolConfiguration configuration = (ModulesProtocolConfiguration) definition.createProtocolConfiguration();
        HTTPContext context = ModulesApi.findHTTPContext(configuration, protocolMetaData, method);
        return context.getServlets().get(0).getBaseURI();
    }

    public void login(@Observes EventContext<Before> event) throws Exception {
        Before before = event.getEvent();

        UserIsLoggedIn userIsLoggedIn = null;
        if (before.getTestMethod().isAnnotationPresent(UserIsLoggedIn.class)) {
            userIsLoggedIn = before.getTestMethod().getAnnotation(UserIsLoggedIn.class);
        } else if (before.getTestClass().isAnnotationPresent(UserIsLoggedIn.class)) {
            userIsLoggedIn = before.getTestClass().getAnnotation(UserIsLoggedIn.class);
        }

        if (userIsLoggedIn != null) {
            final URI baseUri = getBaseURI(before.getTestMethod());
            final WebDriver driver = createWebDriver();
            try {
                driver.manage().deleteAllCookies();

                driver.navigate().to(baseUri + USER_LOGIN_SERVLET_PATH + "?location=" + URLEncoder.encode(userIsLoggedIn.location(), "UTF-8"));

                // did we navigate to this requested page, or did we get redirected/forwarded to login already
                List<WebElement> loginUrlElts = driver.findElements(By.id("login-url"));
                if (loginUrlElts.size() > 0) {
                    String loginURL = loginUrlElts.get(0).getText();

                    // check
                    if (isInternalLink(loginURL)) {
                        loginURL = baseUri + loginURL;
                    }

                    // go-to login page
                    driver.navigate().to(loginURL);
                }

                // find custom login handler, if exists
                LoginHandler loginHandler = TestBase.instance(getClass(), LoginHandler.class);
                if (loginHandler == null) {
                    loginHandler = new DefaultLoginHandler();
                }
                loginHandler.login(driver, new UserLoginContext(userIsLoggedIn));
                // copy cookies
                Set<Cookie> cookies = driver.manage().getCookies();
                for (Cookie cookie : cookies) {
                    ModulesApi.addCookie(cookie.getName(), cookie.getValue());
                }
            } finally {
                driver.close();
            }
        }

        event.proceed();
    }

    protected WebDriver createWebDriver() {
        return new HtmlUnitDriver();
    }

    protected boolean isInternalLink(String link) {
        return !(link.startsWith("http://") || link.startsWith("https://"));
    }
}

@@ -772,16 +772,49 @@
 til.Set;
+%0Aimport java.util.logging.Logger;
 %0A%0Aimport
@@ -910,24 +910,77 @@
 ginHandler;%0A
+import com.google.appengine.tck.driver.LoginContext;%0A
 import com.g
@@ -2156,24 +2156,99 @@
 UserLogin %7B%0A
+    static final Logger log = Logger.getLogger(UserLogin.class.getName());%0A
     static f
@@ -3543,32 +3543,231 @@
 edIn != null) %7B%0A
+            final LoginContext context = new UserLoginContext(userIsLoggedIn);%0A%0A            log.info(String.format(%22Found @UserIsLoggedIn: %25s %5B%25s%5D%22, context.getEmail(), userIsLoggedIn.location()));%0A%0A
             fina
@@ -4999,43 +4999,76 @@
 er, 
-new UserLoginContext(userIsLoggedIn
+context);%0A                log.info(%22Logged-in: %22 + context.getEmail(
 ));%0A

Add some info to login.