/*
 * Aipo is a groupware program developed by Aimluck,Inc.
 * Copyright (C) 2004-2011 Aimluck,Inc.
 * http://www.aipo.com
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.aimluck.eip.modules.actions;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;

import javax.servlet.http.Cookie;

import org.apache.jetspeed.om.security.JetspeedUser;
import org.apache.jetspeed.services.JetspeedSecurity;
import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
import org.apache.jetspeed.services.logging.JetspeedLogger;
import org.apache.jetspeed.services.resources.JetspeedResources;
import org.apache.jetspeed.services.rundata.JetspeedRunData;
import org.apache.jetspeed.services.security.AccountExpiredException;
import org.apache.jetspeed.services.security.CredentialExpiredException;
import org.apache.jetspeed.services.security.FailedLoginException;
import org.apache.jetspeed.services.security.LoginException;
import org.apache.jetspeed.services.security.nosecurity.FakeJetspeedUser;
import org.apache.jetspeed.util.template.JetspeedLink;
import org.apache.jetspeed.util.template.JetspeedLinkFactory;
import org.apache.turbine.modules.ActionEvent;
import org.apache.turbine.services.localization.Localization;
import org.apache.turbine.services.template.TurbineTemplate;
import org.apache.turbine.util.RunData;

import com.aimluck.commons.field.ALStringField;
import com.aimluck.eip.common.ALEipConstants;
import com.aimluck.eip.common.ALEipUser;
import com.aimluck.eip.services.eventlog.ALEventlogFactoryService;
import com.aimluck.eip.util.ALCellularUtils;
import com.aimluck.eip.util.ALEipUtils;

/**
 * ログイン処理用のクラスです。 <br />
 * 
 */
public class ALJLoginUser extends ActionEvent {

  private static final JetspeedLogger logger = JetspeedLogFactoryService
    .getLogger(ALJLoginUser.class.getName());

  public static String KEY_MYGROUP = "mygroup";

  @Override
  @SuppressWarnings("deprecation")
  public void doPerform(RunData rundata) throws Exception {
    try {
      JetspeedRunData data = (JetspeedRunData) rundata;

      String username = data.getParameters().getString("username", "");
      String password = data.getParameters().getString("password", "");

      boolean newUserApproval =
        JetspeedResources.getBoolean("newuser.approval.enable", false);
      String secretkey = data.getParameters().getString("secretkey", null);
      if (secretkey != null) {
        // its the first logon - we are verifying the secretkey

        // handle the buttons on the ConfirmRegistration page
        String button1 = data.getParameters().getString("submit1", null);
        if (button1 != null && button1.equalsIgnoreCase("Cancel")) {
          data.setScreenTemplate(TurbineTemplate.getDefaultScreen());
          return;
        }

        // check to make sure the user entered the right confirmation key
        // if not, then send them to the ConfirmRegistration screen
        JetspeedUser user = JetspeedSecurity.getUser(username);

        if (user == null) {
          logger.warn("JLogin User: Unexpected condition : user is NULL");
          return;
        }
        String confirm_value = user.getConfirmed();
        if (!secretkey.equals(confirm_value)
          && !confirm_value.equals(JetspeedResources.CONFIRM_VALUE)) {
          if (newUserApproval) {
            data.setMessage(Localization.getString(
              rundata,
              "JLOGINUSER_KEYNOTVALID"));
            // data.setScreenTemplate("NewUserAwaitingAcceptance");
            return;
          } else {
            if (user.getConfirmed().equals(
              JetspeedResources.CONFIRM_VALUE_REJECTED)) {
              data.setMessage(Localization.getString(
                rundata,
                "JLOGINUSER_KEYNOTVALID"));
              // data.setScreenTemplate("NewUserRejected");
              return;
            } else {
              data.setMessage(Localization.getString(
                rundata,
                "JLOGINUSER_KEYNOTVALID"));
              // data.setScreenTemplate("ConfirmRegistration");
              return;
            }
          }
        }
        user.setConfirmed(JetspeedResources.CONFIRM_VALUE);
        data.setMessage(Localization.getString(rundata, "JLOGINUSER_WELCOME"));
        JetspeedSecurity.saveUser(user);
      }

      JetspeedUser user = null;
      try {
        if (ALCellularUtils.isCellularPhone(data)) {
          String key = data.getParameters().getString("key", "").trim();
          if (key != null && key.length() > 0 && key.contains("_")) {
            username = key.substring(0, key.lastIndexOf("_"));
            String base64value = key.substring(key.lastIndexOf("_") + 1);

            // 入力されたユーザ名を検証する．
            ALStringField tmpname = new ALStringField();
            tmpname.setTrim(true);
            tmpname.setNotNull(true);
            tmpname.setCharacterType(ALStringField.TYPE_ASCII);
            tmpname.limitMaxLength(16);
            tmpname.setValue(username);
            boolean valid = tmpname.validate(new ArrayList<String>());

            int length = username.length();
            for (int i1 = 0; i1 < length; i1++) {
              if (isSymbol(username.charAt(i1))) {
                // 使用されているのが妥当な記号であるかの確認
                if (!(username.charAt(i1) == "_".charAt(0)
                  || username.charAt(i1) == "-".charAt(0) || username
                  .charAt(i1) == ".".charAt(0))) {
                  valid = false;
                  break;
                }
              }
            }

            if (valid) {
              ALEipUser eipuser = ALEipUtils.getALEipUser(username);
              if (eipuser != null) {
                if (!(ALCellularUtils.getCheckValueForCellLogin(
                  username,
                  eipuser.getUserId().toString())).equals(base64value)) {
                  username = "";
                }
              } else {
                username = "";
              }
            } else {
              username = "";
            }
          }
          String celluid = ALCellularUtils.getCellularUid(rundata);
          password = ALEipConstants.KEY_CELLULAR_UID + celluid;
        }

        user = JetspeedSecurity.login(username, password);
        JetspeedSecurity.saveUser(user);

        int loginUserId = Integer.parseInt(user.getUserId());
        ALEventlogFactoryService.getInstance().getEventlogHandler().logLogin(
          loginUserId);

      } catch (LoginException e) {
        /*
         * data.setScreenTemplate(
         * JetspeedResources.getString(TurbineConstants.TEMPLATE_LOGIN));
         */
        String message = e.getMessage() != null ? e.getMessage() : e.toString();

        data.setMessage(message);
        data.setUser(JetspeedSecurity.getAnonymousUser());
        data.getUser().setHasLoggedIn(Boolean.valueOf(false));

        if (e instanceof FailedLoginException) {
          if (!disableCheck(data)) {
            logger.info("JLoginUser: Credential Failure on login for user: "
              + username);
            data.setMessage(Localization.getString(
              rundata,
              "PASSWORDFORM_FAILED_MSG"));
          }
        } else if (e instanceof AccountExpiredException) {
          logger.info("JLoginUser: Account Expired for user " + username);
        } else if (e instanceof CredentialExpiredException) {
          logger.info("JLoginUser: Credentials expired for user: " + username);
          /*
           * data.setScreenTemplate( JetspeedResources.getString(
           * JetspeedResources.CHANGE_PASSWORD_TEMPLATE, "ChangePassword"));
           */
          data.setMessage(Localization.getString(
            rundata,
            "PASSWORDFORM_EXPIRED_MSG"));
          data.getParameters().setString("username", username);
        }

        return;
      } catch (Throwable other) {
        // data.setScreenTemplate(
        // JetspeedResources.getString(TurbineConstants.TEMPLATE_ERROR));
        String message =
          other.getMessage() != null ? other.getMessage() : other.toString();
        data.setMessage(message);
        data.setStackTrace(org.apache.turbine.util.StringUtils
          .stackTrace(other), other);
        JetspeedUser juser =
          new FakeJetspeedUser(JetspeedSecurity.getAnonymousUserName(), false);
        data.setUser(juser);
        return;
      }
      if ("T".equals(user.getDisabled())) {
        // 理由等 ：ブラウザの戻るボタンを押した場合に，
        // ログイン無効ユーザに対してログイン画面を表示していた．
        // 対処方法：ログイン無効のユーザーを匿名ユーザーとして取り扱い処理する．
        data.setUser(JetspeedSecurity.getAnonymousUser());
        data.setMessage(Localization.getString(
          rundata,
          "JLOGINUSER_ACCOUNT_DISABLED"));
        // data.setScreenTemplate(JetspeedResources.getString("logon.disabled.form"));
        data.getUser().setHasLoggedIn(Boolean.valueOf(false));

        return;
      } else if ("N".equals(user.getDisabled())) {
        // 理由等 ：ブラウザの戻るボタンを押した場合に，
        // ログイン無効ユーザに対してログイン画面を表示していた．
        // 対処方法：ログイン無効のユーザーを匿名ユーザーとして取り扱い処理する．
        data.setUser(JetspeedSecurity.getAnonymousUser());
        data.setMessage("このユーザーは現在無効化されています。担当者様にご確認ください。");
        // data.setScreenTemplate(JetspeedResources.getString("logon.disabled.form"));
        data.getUser().setHasLoggedIn(Boolean.valueOf(false));
        return;
      }

      // check for being confirmed before allowing someone to finish logging in
      if (data.getUser().hasLoggedIn()) {
        if (JetspeedSecurity.isDisableAccountCheckEnabled()) {
          // dst: this needs some refactoring. I don't believe this api is
          // necessary
          JetspeedSecurity.resetDisableAccountCheck(data
            .getParameters()
            .getString("username", ""));
        }

        String confirmed = data.getUser().getConfirmed();
        if (confirmed == null
          || !confirmed.equals(JetspeedResources.CONFIRM_VALUE)) {
          if (confirmed != null
            && confirmed.equals(JetspeedResources.CONFIRM_VALUE_REJECTED)) {
            data.setMessage(Localization.getString(
              rundata,
              "JLOGINUSER_KEYNOTVALID"));
            // data.setScreenTemplate("NewUserRejected");
            data.getUser().setHasLoggedIn(Boolean.valueOf(false));
            return;
          } else {

            data.setMessage(Localization.getString(
              rundata,
              "JLOGINUSER_CONFIRMFIRST"));

            // data.setScreenTemplate("ConfirmRegistration");

            data.getUser().setHasLoggedIn(Boolean.valueOf(false));
            return;
          }
        }

        // user has logged in successfully at this point

        boolean automaticLogonEnabled =
          JetspeedResources.getBoolean("automatic.logon.enable", false);
        if (automaticLogonEnabled) {
          // Does the user want to use this facility?
          boolean userRequestsRememberMe =
            data.getParameters().getBoolean("rememberme", false);
          if (userRequestsRememberMe) {
            // save cookies on the users machine.
            int maxage =
              JetspeedResources.getInt("automatic.logon.cookie.maxage", -1);
            String comment =
              JetspeedResources.getString("automatic.logon.cookie.comment", "");
            String domain =
              JetspeedResources.getString("automatic.logon.cookie.domain");
            String path =
              JetspeedResources.getString("automatic.logon.cookie.path", "/");

            if (domain == null) {
              String server = data.getServerName();
              domain = "." + server;
            }

            String loginCookieValue = null;

            if (JetspeedResources.getString(
              "automatic.logon.cookie.generation",
              "everylogon").equals("everylogon")) {
              loginCookieValue = "" + Math.random();
              data.getUser().setPerm("logincookie", loginCookieValue);
              JetspeedSecurity.saveUser(data.getJetspeedUser());
            } else {
              loginCookieValue = (String) data.getUser().getPerm("logincookie");
              if (loginCookieValue == null || loginCookieValue.length() == 0) {
                loginCookieValue = "" + Math.random();
                data.getUser().setPerm("logincookie", loginCookieValue);
                JetspeedSecurity.saveUser(data.getJetspeedUser());
              }
            }

            Cookie userName =
              new Cookie("username", data.getUser().getUserName());
            Cookie loginCookie = new Cookie("logincookie", loginCookieValue);

            userName.setMaxAge(maxage);
            userName.setComment(comment);
            userName.setDomain(domain);
            userName.setPath(path);

            loginCookie.setMaxAge(maxage);
            loginCookie.setComment(comment);
            loginCookie.setDomain(domain);
            loginCookie.setPath(path);

            data.getResponse().addCookie(userName);
            data.getResponse().addCookie(loginCookie);

          }

        }

        String redirectUrl = data.getParameters().getString("redirect", "");

        if (redirectUrl != null && !"".equals(redirectUrl)) {
          JetspeedLink jsLink = JetspeedLinkFactory.getInstance(data);
          data.setRedirectURI(redirectUrl);
          data.getResponse().sendRedirect(redirectUrl);
          JetspeedLinkFactory.putInstance(jsLink);
          jsLink = null;
        }

        if (ALCellularUtils.isCellularPhone(data)) {
          JetspeedLink jsLink = JetspeedLinkFactory.getInstance(rundata);
          rundata.setRedirectURI(jsLink.getPortletById("").addQueryData(
            JetspeedResources.PATH_ACTION_KEY,
            "controls.Restore").toString());
          rundata.getResponse().sendRedirect(rundata.getRedirectURI());
          JetspeedLinkFactory.putInstance(jsLink);
          jsLink = null;
        }

      } else {
        disableCheck(data);
      }

    } catch (Exception e) {
      logger.error("[ALJLoginUser]", e);
    }

  }

  /**
   * 
   * 指定したchar型文字が記号であるかを判断します。
   * 
   * @param ch
   * @return
   */
  protected boolean isSymbol(char ch) {
    byte[] chars;

    try {
      chars = (Character.valueOf(ch).toString()).getBytes("shift_jis");
    } catch (UnsupportedEncodingException ex) {
      return false;
    }

    if (chars == null
      || chars.length == 2
      || Character.isDigit(ch)
      || Character.isLetter(ch)) {
      return false;
    } else {
      return true;
    }

  }

  @SuppressWarnings("deprecation")
  private boolean disableCheck(JetspeedRunData data) {
    boolean disabled = false;
    // disable user after a configurable number of strikes
    if (JetspeedSecurity.isDisableAccountCheckEnabled()) {
      disabled =
        JetspeedSecurity.checkDisableAccount(data.getParameters().getString(
          "username",
          ""));

      if (disabled) {
        data.setMessage(Localization.getString(
          data,
          "JLOGINUSER_ACCOUNT_DISABLED"));
        data.setScreenTemplate(JetspeedResources
          .getString("logon.disabled.form"));
        data.getUser().setHasLoggedIn(Boolean.valueOf(false));
      }
    }
    return disabled;
  }
}
