package jp.co.y_net.amm.page;

import jp.co.y_net.amm.AppSession;
import jp.co.y_net.amm.AppSession.LoginUser;
import jp.co.y_net.amm.common.AppStringUtils;
import jp.co.y_net.amm.common.AppUtils;
import jp.co.y_net.amm.common.CalcHash;
import jp.co.y_net.amm.dao.AppDef;
import jp.co.y_net.amm.dao.Org;
import jp.co.y_net.amm.dao.Usr;

import org.apache.commons.lang.StringUtils;
import org.apache.wicket.RestartResponseException;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Button;
import org.apache.wicket.markup.html.form.CheckBox;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.PasswordTextField;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.request.mapper.parameter.PageParameters;


/**
 * @author k_inaba
 */
public class MemberDetailPage extends CommonFrameA {
    private static final long serialVersionUID = 1L;
    
    /*
     * 画面入力値
     */
    public String nameValue;
    public String mailValue;
    public String mail2Value;
    public String passwordValue;
    public String password2Value;
//    public String fromdateValue;
//    public String todateValue;
    public boolean stoploginValue;
    
    /*
     * 画面の状態
     */
    private boolean completeMod = false;
    private boolean completePwreset = false;
    private boolean completeDel = false;
    
    /**
     * ログインチェック定義
     * @see jp.co.y_net.amm.page.AppPage#validateLogin()
     */
    @Override
    public boolean validateLogin() {
        if(AppSession.get().isLogin()) {
            if(AppSession.get().getLoginUser().getKind().equals(Usr.KIND_運営管理者)) {
                return true;
            }
            if(AppSession.get().getLoginUser().getKind().equals(Usr.KIND_機関管理者)) {
                return true;
            }
            if(AppSession.get().getLoginUser().getKind().equals(Usr.KIND_機関会員)) {
                return true;
            }
        }
        return false;
    }
    
    
    public MemberDetailPage(PageParameters pageParams) {
	    
        /* 共通戻るリンクの設置 */
        createCommonBackLinks();

        /* 画面固有の戻るボタンの設置 */
        createBackLink(MemberListPage.class, "会員管理");
        
        /* フィードバックパネルの設置 */
        createFeedbackPanel();

        
        /* 入力フォーム */
        final Form<Void> form  = new Form<Void>("form");
        form.setOutputMarkupId(true);
        add(form);
        
        /* 初期表示エラーチェック ----------------------------------------------------------------------------------- */
        form.setVisible(false); // Formはエラーチェックが完了するまで非表示とする。
        
        String paramUsrid = pageParams.get("usrid").toString("");
        final Integer targetUserid;
        if(StringUtils.isEmpty(paramUsrid)) {
            /* パラメータが指定されていなければ、ログインユーザの情報を対象とする */
            if (isMember() || isOrgAdmin() || isSystemAdmin()) {
                targetUserid = AppSession.get().getLoginUser().getUsrid();
            } else {
                error("パラメータ usrid がありません。");
                return; // ----------中断
            }
        } else {
            targetUserid = AppUtils.toInteger(paramUsrid);
        }
        final Usr targetUsr = usrDao.getByUsrid(targetUserid);
        if(targetUsr == null) {
            error("該当する利用者情報がありません。");
            return; // ----------中断
            
        }
        if(isSystemAdmin()) {
            /* 機関管理者が他機関の情報にアクセスしてはいけない */
            LoginUser loginUser = AppSession.get().getLoginUser();
            if(AppUtils.equals(loginUser.getOrgid(), targetUsr.getOrgid()) == false && isSystemAdmin() == false) {
                error("該当する情報を扱う権限がありません。");
                return; // ----------中断
            }
        }
        
        final LoginUser loginUser  = AppSession.get().getLoginUser();
        if(loginUser == null) {
            error("ログイン情報が取得できません。");
            return;
        }
        final Integer loginUserId = loginUser.getUsrid();
        
        
        /* 組織の管理者は 登録情報編集画面を使用するため、会員詳細ページへリンクさせない */
        if(Usr.ROLE_管理者 == targetUsr.getOrgrole()) {
            throw new RestartResponseException(OrgDetailPage.class);
        }
        
        
        
        if(hasInputError()) return; // ----------エラーがあれば中止
        form.setVisible(true);


        
        /* Form内の設定 ----------------------------------------------------------------------------------------------*/
        
        /* 完了メッセージ */
        Model<String> resultMessageModel = new Model<String>() {
            @Override
            public String getObject() {
                if(completeMod) {
                    return "会員情報を変更しました。";
                }
                if(completePwreset) {
                    return "パスワード登録用のメールを送りました。";
                }
                if(completeDel) {
                    return "会員情報を削除しました。";
                }
                return "";
            }
        };
        final Label resutlMessage = new Label("resutlMessage", resultMessageModel);
        form.add(resutlMessage);
        
        /* 入力コンポーネントの設定 ----------------------------------------------------------------------------------*/
        
        nameValue = targetUsr.getName();
        mailValue = targetUsr.getLoginid();
        stoploginValue = AppUtils.toBoolean(targetUsr.getStoplogin());
        
        /* 名前 */
        TextField<String> name = new TextField<String>("name", new PropertyModel<String>(this, "nameValue"));
        form.add(name);
        /* メールアドレス */
        TextField<String> mail = new TextField<String>("mail", new PropertyModel<String>(this, "mailValue"));
        form.add(mail);
        /* メールアドレス確認用 */
        TextField<String> mail2 = new TextField<String>("mail2", new PropertyModel<String>(this, "mail2Value"));
        form.add(mail2);
        
        /* パスワード */
        final PasswordTextField password = new PasswordTextField("password", new PropertyModel<String>(this, "passwordValue")){
            @Override
            public boolean isVisible() {
                /* ログインユーザ自身の情報でなければ画面から変更できない */
                return isLoginUser(targetUsr);
            }
        };
        password.setRequired(false);
        form.add(password);
        
        /* パスワード確認用 */
        PasswordTextField password2 = new PasswordTextField("password2", new PropertyModel<String>(this, "password2Value")){
            @Override
            public boolean isVisible() {
                /* ログインユーザ自身の情報でなければ画面から変更できない */
                return isLoginUser(targetUsr);
            }
        };
        password2.setRequired(false);
        form.add(password2);
        
        /* 利用可能期間FROM～TO */
        Org 所属する組織 = orgDao.getByOrgid(targetUsr.getOrgid());
        String fromtodateStr = 所属する組織.getFromTodate_Disp();

        Label fromtodate = new Label("fromtodate", Model.of(fromtodateStr)){
            @Override
            public boolean isVisible() {
                return StringUtils.isEmpty(getDefaultModelObjectAsString()) == false;
            }
            
        };
        form.add(fromtodate);

        /* ログイン停止 */
        final Model<Boolean> stoploginModel = Model.of(stoploginValue);
        CheckBox stoplogin = new CheckBox("stoplogin", stoploginModel){
            @Override
            public boolean isVisible() {
                /* 一般会員変更不可 */
                return isSystemAdmin() || isOrgAdmin();
            }
        };
        form.add(stoplogin);

        /* 表示コンポーネントの設定 ----------------------------------------------------------------------------------*/
        
        /* 所属機関 */
        final Org org = orgDao.getByOrgid(targetUsr.getOrgid());
        form.add(new Label("orgname", org.getName()){
            @Override
            public boolean isVisible() {
                if(org.isPersonalOrg()) { // 個人の場合は非表示
                    return false;
                }
                return true;
            }
        });
        
        /* 最終ログイン日時 */
        form.add(new Label("lastlogin" , targetUsr.getLastlogindate_Disp()));
        
        /* 状態 */
        form.add(new Label("status", targetUsr.getStatus_Disp()));
        
        
        /* 上位者によるメールアドレス変更のメッセージ */
        form.add(new Label("msgpwreset", "※ メールアドレスを変更するとパスワードがリセットされます。") {
            @Override
            public boolean isVisible() {
                /* パスワード欄から変更できない場合はパスワードリセット */
                return password.isVisible() == false;
            }
        });
        
        
        /* パスワード情報 */
        PasswordInfoPanel passwordInfoPanel = new PasswordInfoPanel("PasswordInfoPanel", 
                targetUsr,
                isSystemAdmin());
        form.add(passwordInfoPanel);
        
        /* 処理ボタン定義 --------------------------------------------------------------------------------------------*/
        
        /*
         * 【会員情報変更】
         */
        Button btnSubmitMod = new ConfirmAjaxButton("btnSubmitMod") {
            @Override
            String getConfirmMessage() {
                return "更新します。";
            }
            @Override
            boolean executeBefore() {
                /* 入力値変換 */
                nameValue = AppStringUtils.trim(nameValue);
                mailValue = AppStringUtils.trimHalf(mailValue);
                mail2Value = AppStringUtils.trimHalf(mail2Value);
                passwordValue = AppStringUtils.trimHalf(passwordValue);
                password2Value = AppStringUtils.trimHalf(password2Value);
                if(isSystemAdmin() || isOrgAdmin()) {
                    stoploginValue = stoploginModel.getObject();
                }
                boolean isメールアドレスが変更されている = (mailValue.equals(targetUsr.getLoginid()) == false);
                boolean isパスワード欄が入力されている = (StringUtils.isEmpty(passwordValue) == false);
                
                /* 入力値検査 */
                validItem(nameValue, "氏名", 1, 512);
                
                if(isメールアドレスが変更されている){
                    validItemMail(mailValue, "メールアドレス");
                    validItemMail(mail2Value, "メールアドレス確認用");
                }
                if (isパスワード欄が入力されている) {
                    validItemAscii(passwordValue, "パスワード", 8, 16);
                    validItemAscii(password2Value, "パスワード確認用", 8, 16);
                }

                if(hasInputError()) return false; // ここまででエラーチェック

                if(isメールアドレスが変更されている){
                    if(mailValue.equals(mail2Value) == false) {
                        error("メールアドレスが一致しません。");
                    }
                    
                    if(mailAddressCheck.exist(mailValue)) {
                        error("このメールアドレスは既に使用されています。");
                    }
                }
                if(isパスワード欄が入力されている) {
                    if(passwordValue.equals(password2Value) == false) {
                        error("パスワードが一致しません。");
                    }
                }
                if(hasInputError()) return false; // ここまででエラーチェック
                
                /*
                 * パスワードの変更について
                 *  メールアドレスが変更されている場合は、パスワードの変更が必須である。
                 *  パスワード欄が入力できるのは変更対象の情報が、ログインユーザ本人であるときのみ。
                 *  パスワード欄が入力できない場合（代表者や運営管理者による変更）は、パスワードリセットを実施する。
                 */
//                boolean パスワードリセットが必要 = false;
                if(isメールアドレスが変更されている) {
                    if(isLoginUser(targetUsr) ) {
                        /* 変更対象の情報が、ログインユーザ本人 */
                        if(isパスワード欄が入力されている) {
                            // 正しい
                        } else {
                            error("メールアドレスを変更する場合は、パスワードも設定してください。");
                        }
                        
                    } else if(isSystemAdmin() || isOrgAdmin()) {
                        /* パスワード欄が入力できない場合（代表者や運営管理者による変更） */
//                        パスワードリセットが必要 = true;
                    } else {
                        /* 通常想定されない条件 */
                        error("メールアドレスを変更することはできません。");
                    }
                }
                
                if(hasInputError()) return false; // ここまででエラーチェック
                
                return true;
            }
            
            @Override
            void executeAfter(AjaxRequestTarget target) {
                /* データアクセス 代表者による会員情報変更  */
                
                boolean isメールアドレスが変更されている = (mailValue.equals(targetUsr.getLoginid()) == false);
                boolean isパスワード欄が入力されている = (StringUtils.isEmpty(passwordValue) == false);
                
                if(isメールアドレスが変更されている){
                    targetUsr.setLoginid(mailValue);
                }
                if(isパスワード欄が入力されている) {
                    String pwhash = CalcHash.passowrdHash(passwordValue, targetUsr.getLoginid());
                    targetUsr.setPwhash(pwhash);
                    targetUsr.setModpwdate(AppUtils.createNowLong()); // パスワード変更日時
                }
                
                if(isメールアドレスが変更されている 
                        && isパスワード欄が入力されている == false) {
                    /* 代表者や運営管理者によるメールアドレスだけの変更 */
                    targetUsr.setPwhash("");
                    targetUsr.setModpwdate(AppUtils.createNowLong()); // パスワード変更日時
                }
                
                targetUsr.setName(nameValue);
                if(stoploginValue) {
                    targetUsr.setStoplogin(AppDef.TRUE);
                } else {
                    targetUsr.setStoplogin(AppDef.FLASE);
                }
                
                usrDao.update(targetUsr, loginUserId); // 【更新処理】
                
                
                /* 本人以外がメールアドレスを変更していたらパスワードリセット */
                boolean パスワードリセットが必要 = false;
                if(isメールアドレスが変更されている) {
                    if(isSystemAdmin() || isOrgAdmin()) {
                        /* パスワード欄が入力できない場合（代表者や運営管理者による変更） */
                        パスワードリセットが必要 = true;
                    }
                }
                if(パスワードリセットが必要) {
                    doパスワードリセット(targetUserid, passwordTicketManager, mailValue);
                }
                
                /*
                 * 状態遷移
                 */
                completeMod = true;
                
                
                /* TODO ログインユーザのメールアドレスかパスワードが変更されたら、自動ログアウトさせる */
                if(isパスワード欄が入力されている && isLoginUser(targetUsr)) {
                    /* APIログアウト相当の実施 */
                    logout.execute(AppSession.get().getLoginUser().getLoginid());
                    
                    /* セッション無効化 */
                    AppSession session = (AppSession) getSession();
                    session.invalidateNow();
                    
                    // TODO 次のメッセージを出すことができない。
                    error("パスワードが変更されたためログアウトしました。新たらしいパスワードでログインしてください。");
                    
                    setResponsePage(LoginPage.class);
                }
                
                /* 画面コンポーネントを更新する */
                target.add(form);
                
            }
            @Override
            public boolean isVisible() {
                /* 完了後の状態ならボタンを表示しない */
                return completeMod == false && completePwreset == false && completeDel == false;
            }
        };
        form.add(btnSubmitMod);
        
        /*
         * 【パスワードリセット】
         */
        Button btnSubmitPwreset = new ConfirmAjaxButton("btnSubmitPwreset") {
            @Override
            String getConfirmMessage() {
                return "パスワードリセットします。";
            }
            @Override
            void executeAfter(AjaxRequestTarget target) {
                
                doパスワードリセット(targetUserid, passwordTicketManager, mailValue);
                
                
                /* 完了状態へ遷移 */
                completePwreset = true;
                
                /* 画面コンポーネントを更新する */
                target.add(form);
            }

            @Override
            public boolean isVisible() {
                /* パスワード変更欄が表示されていれば、パスワードリセットボタンは表示しない */
                if(password.isVisible()) {
                    return false;
                }
                
                /* 完了後の状態ならボタンを表示しない */
                return completeMod == false && completePwreset == false && completeDel == false;
            }
        };
        form.add(btnSubmitPwreset);
        
        /*
         * 【会員情報削除】
         */
        Button btnSubmitDel = new ConfirmAjaxButton("btnSubmitDel") {
            @Override
            String getConfirmMessage() {
                return "削除します。";
            }
            @Override
            String getConfirmMessageStrong() {
                return "本当によろしいですか？";
            }
            @Override
            void executeAfter(AjaxRequestTarget target) {
                
                /* データアクセス 機関管理者による会員情報削除 */
                targetUsr.退会処理();
                usrDao.update(targetUsr, loginUserId); // 【更新処理】
                
                /* 外部APIに退会者のログインIDを通知 */
                AppUtils.callDeleteNotice(targetUsr);
                
                /* 完了状態へ遷移 */
                completeDel = true;
                
                /* 画面コンポーネントを更新する */
                target.add(form);
            }
            @Override
            public boolean isVisible() {
                /* 運営管理者、代表者以外には表示しない */
                if(isSystemAdmin() == false && isOrgAdmin() == false) {
                    return false;
                }
                /* 自分自身の情報は削除できない */
                if(isLoginUser(targetUsr)) {
                    return false;
                }
                
                /* 完了後の状態ならボタンを表示しない */
                return completeMod == false && completePwreset == false && completeDel == false;
            }
        };
        form.add(btnSubmitDel);
    }







}
