/*
 * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
 *
 * The contents of this file are subject to the CCM Public
 * License (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.redhat.com/licenses/ccmpl.html.
 *
 * Software distributed under the License is distributed on an
 * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
 * or implied. See the License for the specific language
 * governing rights and limitations under the License.
 *
 */
package com.arsdigita.ui.login;

import com.arsdigita.bebop.BebopMapDispatcher;
import com.arsdigita.bebop.Component;
import com.arsdigita.bebop.ElementComponent;
import com.arsdigita.bebop.SimpleContainer;
import com.arsdigita.bebop.Label;
import com.arsdigita.bebop.HorizontalLine;
import com.arsdigita.bebop.Page;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.PageFactory;
import com.arsdigita.bebop.event.ActionListener;
import com.arsdigita.bebop.event.PrintListener;
import com.arsdigita.bebop.event.ActionEvent;
import com.arsdigita.bebop.event.PrintEvent;
import com.arsdigita.globalization.GlobalizedMessage;
import com.arsdigita.kernel.KernelHelper;
import com.arsdigita.kernel.security.Initializer;
import com.arsdigita.web.URL;
import com.arsdigita.web.ParameterMap;
import com.arsdigita.web.ReturnSignal;
import com.arsdigita.web.RedirectSignal;
import java.util.HashMap;
import java.util.Map;
import org.apache.log4j.Logger;
import com.arsdigita.dispatcher.Dispatcher;
import com.arsdigita.dispatcher.RequestContext;
import java.io.IOException;
import com.arsdigita.dispatcher.DispatcherHelper;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.ServletException;

/**
 * Dispatcher for the login package.  Manages user registration page, new user
 * page, user workspace, logout, and permissions admin pages.
 *
 * @author Sameer Ajmani
 **/
public class SubsiteDispatcher extends BebopMapDispatcher {
    public static final String versionId = "$Id: //core-platform/dev/src/com/arsdigita/ui/login/SubsiteDispatcher.java#15 $ by $Author: dennis $, $DateTime: 2004/04/07 16:07:11 $";

    public static final String APPLICATION_NAME = "login";

    private static final Logger s_log =
        Logger.getLogger(SubsiteDispatcher.class.getName());

    // define namespace URI
    final static String SUBSITE_NS_URI =
        "http://www.arsdigita.com/subsite/1.0";

    /**
     * Initializes dispatcher by registering URLs with bebop pages.
     **/
    public SubsiteDispatcher() {
        Map map = new HashMap();
        // special-case the empty URL
        String redirect = Initializer.getURL(Initializer.ROOT_PAGE_KEY);
        Dispatcher root = new RedirectDispatcher(redirect);
        map.put("", root);
        map.put("index", root);

        put(map, Initializer.EDIT_PAGE_KEY, buildSimplePage
            ("login.userEditPage.title", new UserEditForm()));
        put(map, Initializer.LOGIN_PAGE_KEY, buildSimplePage
            ("login.userRegistrationForm.title",
             new UserRegistrationForm(Initializer.getAutoRegistrationOn())));
        if (Initializer.getAutoRegistrationOn()) {
            put(map, Initializer.NEWUSER_PAGE_KEY, buildSimplePage
                ("login.userNewForm.title", new UserNewForm()));
        }
        put(map, Initializer.LOGOUT_PAGE_KEY, buildLogOutPage());
        put(map, Initializer.COOKIES_PAGE_KEY, buildSimplePage
            ("login.explainCookiesPage.title", new ElementComponent
             ("subsite:explainPersistentCookies", SUBSITE_NS_URI)));
        put(map, Initializer.CHANGE_PAGE_KEY, buildSimplePage
            ("login.changePasswordPage.title", new ChangePasswordForm()));
        put(map, Initializer.RECOVER_PAGE_KEY, buildSimplePage
            ("login.recoverPasswordPage.title", new RecoverPasswordPanel()));

        Page workspace = buildSimplePage
            ("login.workspacePage.title", new UserInfo());
        put(map, Initializer.WORKSPACE_PAGE_KEY, workspace);
        put(map, Initializer.EXPIRED_PAGE_KEY, buildExpiredPage());

        // special case to handle pvt/home
        String url = Initializer.getURL(Initializer.WORKSPACE_PAGE_KEY);
        if (url.equals("pvt/")) {
            map.put("pvt/home", workspace);
        }

        setMap(map);
    }

    protected void preprocessRequest(HttpServletRequest req,
                                     HttpServletResponse resp,
                                     RequestContext ctx,
                                     String url) {
        // Allow world caching for pages without authentication,
        // ie, /register, /register/explain-persistent-cookies,
        // /register/login-expired, /register/recover-password
        // NB, although you'd think /register is cachable, it
        // stores a timestamp in the login form :(
        if (url.equals(Initializer.getURL(Initializer.COOKIES_PAGE_KEY)) ||
            url.equals(Initializer.getURL(Initializer.EXPIRED_PAGE_KEY)) ||
            url.equals(Initializer.getURL(Initializer.RECOVER_PAGE_KEY))) {
            DispatcherHelper.cacheForWorld(resp);
        } else {
            DispatcherHelper.cacheDisable(resp);
        }
    }

    /**
     * Adds <url, page> to the given map, where URL is looked up from the
     * page map using the given key.  If the URL represents a directory
     * (ends with "/"), URL+"index" is also added to the map and URL-"/" is
     * redirected to URL.
     **/
    private void put(Map map, String key, Page page) {
        String url = Initializer.getURL(key);
        map.put(url, page);
        if (url.endsWith("/")) {
            map.put(url+"index", page);
            requireTrailingSlash(url.substring(0, url.length()-1));
        }
    }

    /**
     * Creates a Page with the given title and body component.
     *
     * @return the new Page
     **/
    private static Page buildSimplePage(String title, Component body) {
        Page page = PageFactory.buildPage(
            APPLICATION_NAME,
            new Label(LoginHelper.getMessage(title)));
        page.add(body);
        page.lock();
        return page;
    }

    private static Page buildExpiredPage() {
        Page page = PageFactory.buildPage(
            APPLICATION_NAME,
            new Label(LoginHelper.getMessage("login.loginExpiredPage.title")));
        page.add(new SimpleContainer() {
             { // constructor
                 add(new Label(LoginHelper.getMessage
                               ("login.loginExpiredPage.before")));
                 add(new DynamicLink("login.loginExpiredPage.link",
                                     Initializer.LOGIN_PAGE_KEY));
                 add(new Label(LoginHelper.getMessage
                               ("login.loginExpiredPage.after")));
                 add(new ElementComponent("subsite:explainLoginExpired",
                                          SUBSITE_NS_URI));
             }
            });
        page.lock();
        return page;
    }

    private static Page buildLogOutPage() {
        Page page = PageFactory.buildPage(
            APPLICATION_NAME,
            new Label(LoginHelper.getMessage("Logout")));
        page.addActionListener(new UserLogoutListener());
        page.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent event) {
                    final PageState state = event.getPageState();

                    final HttpServletRequest req = state.getRequest();

                    final String path = Initializer.getFullURL
                        (Initializer.ROOT_PAGE_KEY, req);

                    throw new ReturnSignal(req, URL.there(req, path));
                }
            });

        page.lock();
        return page;
    }

    private class RedirectDispatcher implements Dispatcher {
        private String m_path;

        public RedirectDispatcher(String path) {
            m_path = path;
        }

        public void dispatch(final HttpServletRequest req,
                             final HttpServletResponse resp,
                             final RequestContext actx)
                throws IOException, ServletException {
            // URL requires that its path argument start with a /,
            // while the old dispatcher stuff assumes paths do not
            // start with a slash.  We translate.

            final URL url = URL.there(req,
                                      "/" + m_path,
                                      new ParameterMap(req));

            throw new RedirectSignal(url, false);
        }
    }
}
