package jp.agentec.abook.abv.ui.home.helper;

import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences.Editor;
import android.content.res.Configuration;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
import androidx.core.content.FileProvider;
import android.webkit.MimeTypeMap;
import android.widget.Toast;

import org.json.adf.JSONException;
import org.json.adf.JSONObject;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Observable;
import java.util.Stack;

import jp.agentec.abook.abv.bl.acms.client.json.DownloadedContentInfoJSON;
import jp.agentec.abook.abv.bl.acms.client.json.content.ContentJSON;
import jp.agentec.abook.abv.bl.acms.type.DownloadStatusType;
import jp.agentec.abook.abv.bl.common.ABVEnvironment;
import jp.agentec.abook.abv.bl.common.constant.ABookKeys;
import jp.agentec.abook.abv.bl.common.exception.AcmsException;
import jp.agentec.abook.abv.bl.common.log.Logger;
import jp.agentec.abook.abv.bl.common.util.ContentFileUtil;
import jp.agentec.abook.abv.bl.common.util.JsonUtil;
import jp.agentec.abook.abv.bl.data.dao.AbstractDao;
import jp.agentec.abook.abv.bl.data.dao.ContentDao;
import jp.agentec.abook.abv.bl.download.ContentDownloadListener;
import jp.agentec.abook.abv.bl.download.ContentDownloader;
import jp.agentec.abook.abv.bl.download.ContentFileExtractor;
import jp.agentec.abook.abv.bl.download.ContentRefresher;
import jp.agentec.abook.abv.bl.download.ContentZipDownloadNotification;
import jp.agentec.abook.abv.bl.dto.ContentDto;
import jp.agentec.abook.abv.bl.dto.MeetingDto;
import jp.agentec.abook.abv.bl.logic.AbstractLogic;
import jp.agentec.abook.abv.bl.logic.ContentLogic;
import jp.agentec.abook.abv.bl.logic.ContentReadingLogLogic;
import jp.agentec.abook.abv.bl.logic.EnqueteLogic;
import jp.agentec.abook.abv.bl.logic.OperationLogic;
import jp.agentec.abook.abv.bl.observer.RemoteObserver;
import jp.agentec.abook.abv.bl.websocket.MeetingManager;
import jp.agentec.abook.abv.cl.util.ContentLogUtil;
import jp.agentec.abook.abv.cl.util.PreferenceUtil;
import jp.agentec.abook.abv.launcher.android.R;
import jp.agentec.abook.abv.ui.common.activity.ABVActivity;
import jp.agentec.abook.abv.ui.common.activity.ABVAuthenticatedActivity;
import jp.agentec.abook.abv.ui.common.activity.ABVContentViewActivity;
import jp.agentec.abook.abv.ui.common.activity.ABVUIActivity;
import jp.agentec.abook.abv.ui.common.appinfo.AppDefType;
import jp.agentec.abook.abv.ui.common.appinfo.AppDefType.DefPrefKey;
import jp.agentec.abook.abv.ui.common.appinfo.AppDefType.UserPrefKey;
import jp.agentec.abook.abv.ui.common.appinfo.AppNaviType;
import jp.agentec.abook.abv.ui.common.constant.NaviConsts;
import jp.agentec.abook.abv.ui.common.dialog.ABookAlertDialog;
import jp.agentec.abook.abv.ui.common.util.ABVToastUtil;
import jp.agentec.abook.abv.ui.common.util.AlertDialogUtil;
import jp.agentec.abook.abv.ui.home.activity.OperationListActivity;
import jp.agentec.abook.abv.ui.home.activity.OperationMeetingListActivity;
import jp.agentec.abook.abv.ui.home.activity.OperationRelatedContentActivity;
import jp.agentec.abook.abv.ui.viewer.activity.AudioPlayActivity;
import jp.agentec.abook.abv.ui.viewer.activity.ContentViewActivity;
import jp.agentec.abook.abv.ui.viewer.activity.EnqueteWebViewActivity;
import jp.agentec.abook.abv.ui.viewer.activity.HTMLWebViewActivity;
import jp.agentec.abook.abv.ui.viewer.activity.ImageViewActivity;
import jp.agentec.abook.abv.ui.viewer.activity.ParentWebViewActivity;
import jp.agentec.abook.abv.ui.viewer.activity.PreviewActivity;
import jp.agentec.abook.abv.ui.viewer.activity.VideoViewActivity;
import jp.agentec.adf.net.http.HttpDownloadSimpleNotification;
import jp.agentec.adf.util.DateTimeUtil;
import jp.agentec.adf.util.FileUtil;
import jp.agentec.adf.util.RuntimeUtil;
import jp.agentec.adf.util.StringUtil;

// TODO: synchronizedメソッドは、currentActivityStackによるブロックに変更
// TODO: リファクタリング ActivityStackとActivity起動とMeeting関係をクラス分離
public class ActivityHandlingHelper extends ABookHelper implements RemoteObserver, ContentDownloadListener {
    private static final String TAG = "ActivityHandlingHelper";
    protected static final String FILEPATH = ABVAuthenticatedActivity.FILEPATH;

    private static ActivityHandlingHelper remoteHandlingHelper = new ActivityHandlingHelper();
    private ContentLogic contentLogic = AbstractLogic.getLogic(ContentLogic.class);
    private ContentDownloader contentDownloader = ContentDownloader.getInstance();
    private ContentDao contentDao = AbstractDao.getDao(ContentDao.class);

    private Context mContext;
    private OperationMeetingListActivity operationMeetingListActivity;
    private Handler handler;

    private Stack<ABVAuthenticatedActivity> currentActivityStack = new Stack<>();
    private volatile ABVContentViewActivity contentViewActivity;
    private volatile ABVContentViewActivity objectViewActivity;
    private MeetingManager meetingManager;
    private ABookAlertDialog downloadConfirmDialog;
    private ABookAlertDialog updateConfirmDialog;
    private boolean requireHomeReload;
    private ABookAlertDialog promotionRequestAlertDialog;
    private long lastDisconnect;
    private static Dialog meetingAlertDialog;

    protected ContentRefresher contentRefresher = ContentRefresher.getInstance();

    // 設定画面の前に表示していたActivity
    private ABVUIActivity previousOfSettingActivity;
    // Chat
    private ParentWebViewActivity previousOfSettingActivity2;

    private ActivityHandlingHelper() {
    }

    public static ActivityHandlingHelper getInstance() {
        return remoteHandlingHelper;
    }

    public void init(Context context) {
        if (mContext == null) {
            this.mContext = context;
            handler = new Handler();
            meetingManager = MeetingManager.getInstance();
            meetingManager.addObserver(this);
        }
    }

    public void destroy() {
        MeetingManager.getInstance().deleteObserver(this);
    }

    public void startContentActivity(Long contentId, Integer page) {
        boolean isLinkedContent = false;
        Long operationId = null;
        int pageNo = 0;
        ABVAuthenticatedActivity activity = getCurrentActivity();
        if (activity instanceof ABVContentViewActivity) {
            operationId = ((ABVContentViewActivity) activity).mOperationId;
            isLinkedContent = ((ABVContentViewActivity) activity).isLinkedContent;
            pageNo = ((ABVContentViewActivity) activity).pageNo;
        }


        if (isLinkedContent) {
            startContentActivityForLinkedConent(operationId, contentId, pageNo);
        } else {
            startContentActivity(contentId, page, new Intent());
        }
    }

    public void checkContentActivity(Long contentId, Integer page, Intent intent) {
        startContentActivity(contentId, page, intent);
    }

    public void startContentActivity(final Long contentId, final Integer page, final Intent intent) {
        handler.post(new Runnable() {
            @Override
            public void run() {
                try {
                    intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
                    if (page != null) {
                        intent.putExtra(ABVActivity.PAGE, page);
                    }
                    startContentActivity(mContext, intent, null, Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK, contentId);
                } catch (Exception e) {
                    Logger.e(TAG, "startContentActivity contentId=" + contentId, e);
                    showToast(mContext.getString(R.string.E113));
                }
            }
        });
    }

    public void startContentActivity(Context context, Intent intent, NaviConsts aBVNavi, Integer flags, long contentId) throws Exception {
        Logger.i(TAG, "startContentActivity contentId=" + contentId + " intent=" + intent);

        String path = ContentFileExtractor.getInstance().getContentCacheDirWithExtract(contentId);
        if (path == null) {
            Logger.e(TAG, "startContentActivity: JSON Data is Null.mContentDir=" + null);
            throw new FileNotFoundException(null);
        }
        ContentJSON contentJSON = contentLogic.getContentInfoJson(path, contentId);
        if (contentJSON == null) {
            Logger.e(TAG, "startContentActivity: JSON Data is Null.mContentDir=" + path);
            throw new FileNotFoundException(path);
        }
        if (ABVEnvironment.getInstance().isContentProtected) {
            // cacheフォルダのパーミッションの修正
            RuntimeUtil.exec("chmod 751 " + path);
        }

        String contentType = contentJSON.getContentType();

        if (contentJSON.isPdf()) {
            contentType = ContentJSON.KEY_PDF_TYPE;
        }

        if (contentType.equals(ContentJSON.KEY_LINK_TYPE)) {
            path = contentJSON.getFileName();
        } else if (!contentJSON.isPdf() && !contentType.equals(ContentJSON.KEY_NONE_TYPE)) {
            if (StringUtil.equalsAny(contentType, ContentJSON.KEY_HTML_TYPE, ContentJSON.KEY_PANO_MOVIE_TYPE, ContentJSON.KEY_PANO_IMAGE_TYPE, ContentJSON.KEY_OBJECTVR_TYPE,
                ContentJSON.KEY_ENQUETE_TYPE, ContentJSON.KEY_EXAM_TYPE)) { // HTML, ENQUETE, EXAM, PANO,ObjectVRファイル

                String dir = path + "/" + FileUtil.getFilenameWithoutExt(contentJSON.getFileName()) + "/";
                path = dir + "index.html";
                if (!FileUtil.exists(path)) {
                    path = dir + "index.htm";
                }
            } else if (contentType.equals(ContentJSON.KEY_OTHER_TYPE)) { // その他ファイル
                // セキュリティのため（ディレクトリが対象アプリで見えてしまう）、ファイルを一段階下に移動させる。
                String newPath = path + "/0/" + contentJSON.getFileName();
                if (!FileUtil.exists(newPath)) {
                    FileUtil.createParentDirectory(newPath);
                    RuntimeUtil.exec("chmod 755 " + path + "/0/");
                    FileUtil.move(path + "/" + contentJSON.getFileName(), newPath, true);
                    RuntimeUtil.exec("chmod 755 " + newPath);
                }
                path = newPath;
            } else {
                path = path + "/" + contentJSON.getFileName(); // PDF以外はjsonファイルパスを指定
            }
            if (!FileUtil.exists(path)) {
                Logger.e(TAG, "startContentActivity: File not found. filepath=" + path);
                throw new FileNotFoundException();
            }
        }
        if (StringUtil.equalsAny(contentType, ContentJSON.KEY_PANO_MOVIE_TYPE, ContentJSON.KEY_PANO_IMAGE_TYPE, ContentJSON.KEY_OBJECTVR_TYPE)) { // PANO,ObjectVRファイル
            path += "?app=android";
            if (contentType.equals(ContentJSON.KEY_PANO_IMAGE_TYPE)) {
                // ページの場合、0から始まるのでシーン設定は+1する
                path += "&startscene=scene" + (intent.getIntExtra(ABVActivity.PAGE, 1) + 1);
            }
            // 管理者モードで開く場合、パラメータ追加
            path += "&isManagementMode=true";
        }

        // 音声ファイルの場合、マイク権限チェック
        if (contentType.equals(ContentJSON.KEY_MUSIC_TYPE)) {
            ABVAuthenticatedActivity activity = getCurrentActivity();
            if (!((ABVAuthenticatedActivity) activity).checkMicPermission()) {
                return;
            }
        }

        //プッシュ―メッセージを経由してコンテンツダウンロード場合：開く対象のコンテンツは現在開いているコンテンツと同じ場合画面遷移しない
        if (contentViewActivity == null || contentViewActivity.getContentId() != contentId) {
            startActivity(context, intent, aBVNavi, flags, contentId, contentType, path);
        }
    }

    public void startContentActivityForLinkedConent(final Long operationId, final Long contentId, final Integer page) {
        handler.post(new Runnable() {
            @Override
            public void run() {
                try {
                    Intent intent = new Intent();
                    if (page != null) {
                        intent.putExtra(ABVActivity.PAGE, page);
                    }
                    intent.putExtra("isLinkedContent", true);

                    if (operationId != null) {
                        intent.putExtra(ABookKeys.OPERATION_ID, operationId);
                    }
                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    startContentActivity(mContext, intent, null, null, contentId);
                } catch (Exception e) {
                    Logger.e(TAG, "startContentActivity contentId=" + contentId, e);
                    showToast(mContext.getString(R.string.E113));
                }
            }
        });
    }

    private void startActivity(Context context, Intent intent, NaviConsts ABVNavi, Integer flags, long contentId, String contentType, String path) throws Exception {
        contentRefresher.stopRefresh(); // 新着更新を停止する
        if (intent == null) {
            intent = new Intent();
        }
        intent.putExtra(ABookKeys.CONTENT_ID, contentId);
        intent.putExtra(FILEPATH, path);
        intent.putExtra(ABookKeys.CONTENT_TYPE, contentType);
        intent.putExtra(ABookKeys.CONTENT_NAME, contentDao.getContent(contentId).contentName);
        if (flags != null) {
            intent.setFlags(flags);
        }

        if (contentType.equals(ContentJSON.KEY_PDF_TYPE) || contentType.equals(ContentJSON.KEY_NONE_TYPE)) {
            intent.setClass(context, ContentViewActivity.class);
            if (ABVNavi != null) {
                transitionNavi((Activity) context, ABVNavi);
            }
        } else if (contentType.equals(ContentJSON.KEY_IMAGE_TYPE)) { // 画像コンテンツ
            intent.setClass(context, ImageViewActivity.class);
        } else if (contentType.equals(ContentJSON.KEY_MOVIE_TYPE)) { // 動画ファイル
            intent.setClass(context, VideoViewActivity.class);
        } else if (contentType.equals(ContentJSON.KEY_MUSIC_TYPE)) { // 音声ファイル
            intent.setClass(context, AudioPlayActivity.class);
        } else if (contentType.equals(ContentJSON.KEY_HTML_TYPE)) { // HTMLファイル
            startHTMLWebActivity(context, intent, "file://" + path, contentId, -1, -1, -1, -1, -1);
        } else if (StringUtil.equalsAny(contentType, ContentJSON.KEY_PANO_MOVIE_TYPE, ContentJSON.KEY_PANO_IMAGE_TYPE, ContentJSON.KEY_OBJECTVR_TYPE)) { // HTML/360動画/バーチャルツアー/オブジェクトVR
            startHTMLWebActivity(context, intent, "file://" + path, contentId, -1, -1, -1, -1, -1);
        } else if (contentType.equals(ContentJSON.KEY_ENQUETE_TYPE)
                || contentType.equals(ContentJSON.KEY_EXAM_TYPE)) { // ENQUETE, EXAMファイル
            //会議室連動はしない
            if (!checkOwner(context)) { // 会議室司会者は不可
                return;
            }
            // 一回だけ
            startEnqueteWebActivity(context, intent, "file://" + path, contentId, -1, -1, -1, -1, false);
        } else if (contentType.equals(ContentJSON.KEY_LINK_TYPE)) {
            if (path.startsWith("http:") || path.startsWith("https:")) { // httpまたはhttpsの場合内部ブラウザで表示
                if (!checkOwner(context)) { // 会議室司会者は不可
                    return;
                }
                // 内部ブラウザ
                DownloadedContentInfoJSON json = ContentFileUtil.getDownloadedContentInfoJSON(contentId);
                if (json.browserType == 0) {
                    startHTMLWebActivity(context, intent, path, contentId, -1, -1, -1, -1, -1);
                    // 外部ブラウザ
                } else {
                    Uri uri = Uri.parse(path);
                    intent.setAction(Intent.ACTION_VIEW);
                    intent.setData(uri);
                    recordContentReadLog(context, contentId);
                    context.startActivity(intent);
                }
            } else if (path.startsWith(context.getString(R.string.scheme_url) + "://")) {
                // 自身を起動するUrlは無効とする
                showToast(context.getString(R.string.E130));
            } else {
                // 他のスキーマはintent渡しする
                Uri uri = Uri.parse(path);
                intent.setAction(Intent.ACTION_VIEW);
                intent.setData(uri);
                recordContentReadLog(context, contentId);
                context.startActivity(intent);
            }
        } else if (contentType.equals(ContentJSON.KEY_OTHER_TYPE)) { // その他ファイル
            if (!checkOwner(context)) { // 会議室司会者は不可
                return;
            }
            intent.setAction(Intent.ACTION_VIEW);
            String extention = MimeTypeMap.getFileExtensionFromUrl(path);
            String mimetype = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extention);
            if (mimetype == null) {
                mimetype = "*/*";
            }

            // Android 7.0以上の場合
            if (Build.VERSION.SDK_INT >= 24) {
                File file = new File(path);
                if (!FileUtil.exists(path)) {
                    Logger.e(TAG, "CONTENT_TYPE[OTHER_TYPE]: File not found. filepath=" + path);
                    throw new FileNotFoundException();
                }
                Uri uri = FileProvider.getUriForFile(context, context.getPackageName() + ".provider", file);
                intent.setDataAndType(uri, mimetype);
                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            } else {
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                intent.setDataAndType(Uri.parse("file://" + path), mimetype);
            }

            recordContentReadLog(context, contentId);
        }

        if (!StringUtil.equalsAny(contentType,
                ContentJSON.KEY_HTML_TYPE, ContentJSON.KEY_LINK_TYPE, ContentJSON.KEY_ENQUETE_TYPE, ContentJSON.KEY_EXAM_TYPE,
                ContentJSON.KEY_PANO_MOVIE_TYPE, ContentJSON.KEY_PANO_IMAGE_TYPE, ContentJSON.KEY_OBJECTVR_TYPE)) {
            context.startActivity(intent);
        }
    }

    private void recordContentReadLog(final Context context, final long contentId) {
        if (!ABVEnvironment.getInstance().disableLogSend) {
            // 閲覧ログ開始
            handler.post(new Runnable() {
                @Override
                public void run() {
                    ContentReadingLogLogic contentReadingLogic = AbstractLogic.getLogic(ContentReadingLogLogic.class);
                    ContentLogUtil contentLogUtil = ContentLogUtil.getInstance();
                    contentLogUtil.startContentReadLog(context, contentId, PreferenceUtil.getUserPref(context, DefPrefKey.PERMISSION_ACCESS_LOCATION, false));
                    // 閲覧履歴保存
                    contentDao.updateContentReadingDate(DateTimeUtil.getCurrentTimestamp(), contentId);
                    // 閲覧ログ終了
                    contentReadingLogic.endContentReadLog(contentId); // 終了のタイミングつかめないのですぐにRead終了とする。
                }
            });
        }
    }

    public static void transitionNavi(Activity act, NaviConsts ABVNavi) {
        AppNaviType.setAfter(ABVNavi);
        if (AppNaviType.getAfter().equals(NaviConsts.Down)) {
            act.overridePendingTransition(R.anim.viewin_down, R.anim.viewout_down);
        } else if (AppNaviType.getAfter().equals(NaviConsts.Up)) {
            act.overridePendingTransition(R.anim.viewin_up, R.anim.viewout_up);
        } else if (AppNaviType.getAfter().equals(NaviConsts.Right)) {
            act.overridePendingTransition(R.anim.viewin_right_to_left, R.anim.viewout_right_to_left);
        } else if (AppNaviType.getAfter().equals(NaviConsts.Left)) {
            act.overridePendingTransition(R.anim.viewin_left_to_right, R.anim.viewout_left_to_right);
        } else if (AppNaviType.getAfter().equals(NaviConsts.Alpha)) {
            act.overridePendingTransition(R.anim.alpha_in, R.anim.alpha_out);
        } else {
            act.overridePendingTransition(R.anim.alpha_up_in, R.anim.alpha_up_out);
        }
    }


    /**
     * WebViewを開く
     *
     * @param context
     * @param intent
     * @param path
     * @param contentId
     * @param requestCode
     * @param pageNumber        呼び出し元のページ番号
     * @param objectId
     */
    public void startHTMLWebActivity(Context context, Intent intent, String path, long contentId, int requestCode, int pageNumber, long objectId, int objectLogId, int readingLogId) {
        if (path != null && path.startsWith("http") && !ABVEnvironment.getInstance().networkAdapter.isNetworkConnected()) {
            ABVToastUtil.showMakeText(context, R.string.NETWORK, Toast.LENGTH_LONG);
            return;
        }

        if (intent == null) {
            intent = new Intent();
        }
        intent.setClass(context, HTMLWebViewActivity.class);
        intent.putExtra("LINKURL", path);
        intent.putExtra(ABookKeys.CONTENT_ID, contentId);
        intent.putExtra("pageNumber", pageNumber);
        intent.putExtra("objectId", objectId);
        intent.putExtra("objectLogId", objectLogId);
        intent.putExtra("readingLogId", readingLogId);
        if (requestCode == -1) {
            context.startActivity(intent);
        } else {
            ((Activity) context).startActivityForResult(intent, requestCode);
        }
    }

    /**
     * WebViewを開く
     *
     * @param context
     * @param intent
     * @param path
     * @param contentId
     * @param requestCode
     * @param pageNumber        呼び出し元のページ番号
     * @param objectLogId
     * @param isInteractiveMode
     * @throws IOException
     * @throws AcmsException
     */
    public void startEnqueteWebActivity(Context context, Intent intent, String path, long contentId, int requestCode, int pageNumber, long abObjectId, int objectLogId, boolean isInteractiveMode) throws AcmsException, IOException {
        if (path != null && path.startsWith("http") && !ABVEnvironment.getInstance().networkAdapter.isNetworkConnected()) {
            ABVToastUtil.showMakeText(context, R.string.NETWORK, Toast.LENGTH_LONG);
            return;
        }
        // contentDownloadForAnd.zip/json.txt
        DownloadedContentInfoJSON json = ContentFileUtil.getDownloadedContentInfoJSON(contentId);
        // 回答制限あり
        if (isAnsweredEnquete(json)) {
            return;
        }

        if (intent == null) {
            intent = new Intent();
        }

        intent.setClass(context, EnqueteWebViewActivity.class);
        intent.putExtra("LINKURL", path);
        intent.putExtra(ABookKeys.CONTENT_ID, contentId);
        intent.putExtra(ABookKeys.CONTENT_TYPE, json.contentType);

        intent.putExtra("replyLimit", json.replyLimit);
        intent.putExtra("showResult", json.showResult);
        intent.putExtra("sendResult", json.sendResult);

        intent.putExtra("pageNumber", pageNumber);
        intent.putExtra("abEnqueteId", json.enqueteId);
        intent.putExtra("abObjectId", abObjectId);
        intent.putExtra("objectLogId", objectLogId);
        if (requestCode == -1) {
            context.startActivity(intent);
        } else {
            ((Activity) context).startActivityForResult(intent, requestCode);
        }
    }

    public boolean isAnsweredEnquete(DownloadedContentInfoJSON json) {
        EnqueteLogic es = AbstractLogic.getLogic(EnqueteLogic.class);

        if (json.replyLimit == 1 && es.getLimitEnquete(json.contentId, 0)) {
            //回答済みの場合：アラートを出すのでタイトルと内容はアンケート、試験、クイズによって変えるため
            String enquete_strType_over = null;
            if (json.contentType.equals(ContentJSON.KEY_ENQUETE_TYPE)) {
                enquete_strType_over = mContext.getResources().getString(R.string.enquete_over);
            } else if (json.contentType.equals(ContentJSON.KEY_EXAM_TYPE)) {
                enquete_strType_over = mContext.getResources().getString(R.string.exam_over);
            }
            showToast(enquete_strType_over);

            return true;
        }

        return false;
    }

    public boolean isExistRelatedContent(long contentId, Long operationId) {
        Logger.i(TAG, "[isExistRelatedContent]contentId=" + contentId + ", operationId=" + operationId);
        if (operationId == null) {
            return false;
        }

        OperationLogic mOperationLogic = AbstractLogic.getLogic(OperationLogic.class);

        return mOperationLogic.isOperationRelatedContent(contentId, operationId);
    }

    public boolean isExistCommonContent(long contentId) {
        Logger.i(TAG, "[isExistCommonContent]contentId=" + contentId);
        OperationLogic mOperationLogic = AbstractLogic.getLogic(OperationLogic.class);

        return mOperationLogic.isCommonContent(contentId);
    }

    public void unloadOperationMeetingListActivity() {
        if (operationMeetingListActivity != null) {
            operationMeetingListActivity.finish();
        }
    }

    public void setOperationMeetingListActivity(OperationMeetingListActivity operationMeetingListActivity) {
        this.operationMeetingListActivity = operationMeetingListActivity;
    }

    public ABVContentViewActivity getContentViewActivity() {
        return contentViewActivity;
    }

    public synchronized void setContentViewActivity(ABVContentViewActivity contentViewActivity) {
        this.contentViewActivity = contentViewActivity;
    }

    public ABVContentViewActivity getObjectViewActivity() {
        return objectViewActivity;
    }

    public synchronized void setObjectViewActivity(ABVContentViewActivity objectViewActivity) {
        this.objectViewActivity = objectViewActivity;
    }

    public synchronized ABVAuthenticatedActivity getCurrentActivity() {
        if (currentActivityStack.isEmpty()) {
            return null;
        }
        return currentActivityStack.peek();
    }

    public synchronized OperationListActivity getPreviousOperationListActivity() {
        if (currentActivityStack.isEmpty()) {
            return null;
        }

        int size = currentActivityStack.size();

        if (size > 0) {
            for(int i = size-1; i >= 0; i--) {
                ABVAuthenticatedActivity activity = currentActivityStack.elementAt(i);
                if (activity instanceof OperationListActivity) {
                    return (OperationListActivity) activity;
                }
            }
            return null;
        } else {
            return null;
        }
    }

    public synchronized void setCurrentActivity(ABVAuthenticatedActivity currentActivity) {
        currentActivityStack.push(currentActivity);
        Logger.i(TAG, "Activity Stack: " + currentActivityStack);
    }

    public synchronized void removeCurrentActivity(ABVAuthenticatedActivity currentActivity) {
        try {
            if (currentActivityStack.contains(currentActivity)) {
                currentActivityStack.remove(currentActivity);
                if (!currentActivityStack.isEmpty()) {
                    final ABVAuthenticatedActivity activity = currentActivityStack.peek();
                }
            }
        } catch (Exception e) {
            Logger.e(TAG, "removeCurrentActivity failed.", e); // ignore
        }
    }

    /**
     * currentActivityStackに引数に指定したActivityクラスが含まれるか
     *
     * @param classes
     * @return
     */
    @SuppressWarnings("rawtypes")
    public boolean contains(Class... classes) {
        for (Iterator iterator = currentActivityStack.iterator(); iterator.hasNext(); ) {
            ABVAuthenticatedActivity act = (ABVAuthenticatedActivity) iterator.next();
            for (Class clazz : classes) {
                if (act.getClass().getName().equals(clazz.getName())) {
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * スタックの中から引数に指定したActivityクラスのインスタンスを返す
     *
     * @param clazz
     * @return
     */
    public <T extends ABVAuthenticatedActivity> T getActivity(Class<T> clazz) {
        for (Iterator<ABVAuthenticatedActivity> iterator = currentActivityStack.iterator(); iterator.hasNext(); ) {
            @SuppressWarnings("unchecked")
            T act = (T) iterator.next();
            if (act.getClass().getName().equals(clazz.getName())) {
                return act;
            }
        }

        return null;
    }

    public synchronized void removeContentViewActivity(ABVContentViewActivity contentViewActivity) {
        sendToBookShelf();
        if (this.contentViewActivity != null && this.contentViewActivity.equals(contentViewActivity)) {
            setContentViewActivity(null);
        }
    }

    public synchronized void removeObjectViewActivity(ABVContentViewActivity objectViewActivity) {
        if (this.objectViewActivity != null && this.objectViewActivity.equals(objectViewActivity)) {
            setObjectViewActivity(null);
        }
    }

    /**
     * コンテンツのActivityをすべて終了させる（特定のActivityをStackから削除する方法がないため）
     */
    public synchronized void finishAllContentViewActivity() {
        for (ABVAuthenticatedActivity activity : currentActivityStack) {
            if (activity instanceof ABVContentViewActivity) {
                activity.finish();
            }
        }
        //戻る用のコンテンツビュー情報リストをリセット
        if (contentViewActivity != null) {
            contentViewActivity.resetReturnContentIdList();
        }
    }

    /**
     * リンクコンテンツのActivityのみをすべて終了させる（特定のActivityをStackから削除する方法がないため）
     */
    public synchronized void finishAllLinkContentViewActivity() {
        int activitySize = currentActivityStack.size();
        for (int i = 1; i < activitySize - 1; i++) {
            ABVAuthenticatedActivity activity = currentActivityStack.get(currentActivityStack.size() - i);
            if (activity instanceof ABVContentViewActivity) {
                activity.finish();
            }
        }

        //戻る用のコンテンツビュー情報リストをリセット
        if (contentViewActivity != null) {
            contentViewActivity.resetReturnContentIdList();
        }
    }

    /**
     * 引数に指定したActivity以外すべて終了させる
     *
     * @param except
     */
    public synchronized void finishAllContentViewActivityExcept(ABVContentViewActivity except) {
        for (ABVAuthenticatedActivity activity : currentActivityStack) {
            if (activity instanceof ABVContentViewActivity && !activity.equals(except)) {
                activity.finish();
            }
        }
    }

    private synchronized boolean hasOperationListActivity() {
        if (!currentActivityStack.isEmpty()) {
            for (ABVAuthenticatedActivity activity : currentActivityStack) {
                if ((activity instanceof OperationListActivity) || (activity instanceof OperationRelatedContentActivity)) {
                    return true;
                }
            }
        }
        return false;
    }

    private synchronized boolean hasParentWebViewActivity() {
        if (!currentActivityStack.isEmpty()) {
            for (ABVAuthenticatedActivity activity : currentActivityStack) {
                if ((activity instanceof ParentWebViewActivity)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 履歴で直前に360コンテンツであったかを確認
     * @param contentId
     * @return boolean
     */
    public boolean hasPreviousPanoContentId(long contentId) {
        if (!currentActivityStack.isEmpty() && currentActivityStack.size() > 1) {
            // 直前のコンテンツを取り出す
            ABVAuthenticatedActivity activity = currentActivityStack.get(currentActivityStack.size() - 2);
            if (!(activity instanceof HTMLWebViewActivity)) {
                return false;
            }

            if (activity instanceof HTMLWebViewActivity) {
                HTMLWebViewActivity htmlWebViewActivity = (HTMLWebViewActivity) activity;
                if (htmlWebViewActivity.getContentId() == contentId) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 履歴から該当の360コンテンツを削除する
     * @param contentId long
     */
    public void deleteExistPanoContentId(long contentId) {
        if (!currentActivityStack.isEmpty()) {
            for (ABVAuthenticatedActivity activity : currentActivityStack) {
                if (activity instanceof HTMLWebViewActivity) {
                    if (((HTMLWebViewActivity) activity).getContentId() == contentId) {
                        activity.finish();
                        ((HTMLWebViewActivity) activity).finishWebView();
                        currentActivityStack.remove(activity);
                        break;
                    }
                }
            }
        }
    }

    public void setRequireHomeReload(boolean requireHomeReload) {
        this.requireHomeReload = requireHomeReload;
    }

    /**
     * 遠隔連動メッセージ受信処理
     * MeetingMangerからObserver経由で呼び出される
     */
    @Override
    public void update(Observable observable, final Object data) {
        Logger.v(TAG, "[update] %s contentViewActivity=%s objectViewActivity=%s", data, contentViewActivity, objectViewActivity);
        if (data instanceof JSONObject) {
            handleUpdateJson((JSONObject) data);
        } else if (data instanceof String) {
            handleUpdateString((String) data);
        }
    }

    private void handleUpdateJson(final JSONObject json) {
        try {
            final String cmd = json.getString(MeetingManager.CMD);
            final long contentId = JsonUtil.getLong(json, MeetingManager.CONTENTID);
            final int pageNumber = JsonUtil.getInt(json, MeetingManager.PAGE_NUMBER);

            if (cmd.equals(MeetingManager.CMD_MEETINGINFO)) { // 入室結果
                showToast(mContext.getString(meetingManager.isOwner() ? R.string.msg_enter_as_publisher : R.string.msg_enter_as_subscriber));
                return;
            }

            if (meetingManager.isOwner()) { // Publisherの場合
                if (cmd.equals(MeetingManager.CMD_PRESENTERREQUEST)) { // 昇格依頼受信
                    handlePresenterRequest(json);
                } else if (cmd.equals(MeetingManager.CMD_MOVEPAGE)) { // コンテンツを開く(会議室を再開した場合)
                    if (checkContent(contentId, pageNumber)) {
                        startContentActivity(contentId, pageNumber);
                    }
                    return;
                }
            } else { // Subscriberの場合
                if (!meetingManager.isOwner() && cmd.equals(MeetingManager.CMD_APPROVALSTATUS)) { // 昇格依頼結果受信
                    handleApprovalStatus(json);
                    return;
                }

                if (!ABVActivity.isVisible()) { // バックグラウンドなら何もしない
                    Logger.w(TAG, "Activity is not visible.");
                    return;
                }

                if (cmd.equals(MeetingManager.CMD_TOBOOKSHELF)) { // トップに戻る(コメントアウト：参加者はTOPに戻らない)
//						finishContentObjectActivity();
                    return;
                }

                if (!checkContent(contentId, pageNumber)) {
                    return;
                }

                if (cmd.equals(MeetingManager.CMD_OPEN) || contentViewActivity == null || contentViewActivity.getContentId() != contentId) { // 現在開いているコンテンツと異なる場合、そのコンテンツを開く
                    if (contentViewActivity != null && contentViewActivity.getContentId() != contentId) {
                        finishContentObjectActivity();
                    }
                    startContentActivity(contentId, json.getInt(MeetingManager.PAGE_NUMBER));

                    if (cmd.equals(MeetingManager.CMD_OPEN) || cmd.equals(MeetingManager.CMD_MOVEPAGE)) {
                        return;
                    }
                }

                int retry = 0;
                while (contentViewActivity == null) { // contentViewActivityが設定されるまで待つ
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                    }
                    retry++;
                    if (retry > 5) {
                        return;
                    }
                }

                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        // ページが異なる場合、そのページに移動する
                        if (contentViewActivity instanceof ContentViewActivity) {
                            if (pageNumber != -1 && contentViewActivity.getCurrentPageNumber() != pageNumber) {
                                ((ContentViewActivity) contentViewActivity).jumpToPage(pageNumber);
                            }
                        }

                        if (cmd.equals(MeetingManager.CMD_CLOSEPOPUP) && objectViewActivity != null
                                && (objectViewActivity.getObjectId() == JsonUtil.getLong(json, MeetingManager.OBJECTID, 0)
                                || objectViewActivity.getObjectId() == -1)) {
                            // ActivityとしてのPopupを閉じる（ViewのPopupはperformRemoteEvent()内で） objectId=-1のときは必ず閉じる
                            objectViewActivity.finish();
                            objectViewActivity = null;
                        } else if (cmd.equals(MeetingManager.CMD_IMAGEPREVIEWACTION)) {
                            if (objectViewActivity instanceof PreviewActivity) {
                                // イメージプレビュー
                                int imageIndex = JsonUtil.getInt(json, MeetingManager.IMAGE_INDEX);
                                if (imageIndex < 0 || imageIndex >= ((PreviewActivity) objectViewActivity).getMaxImg()) {
                                    Logger.w(TAG, "invalid imageIndex " + imageIndex);
                                } else {
                                    ((PreviewActivity) objectViewActivity).goIndex(imageIndex);
                                }
                            }
                        } else {
                            if (contentViewActivity != null) {
                                // PDF/NONE、動画、音声それぞれのコンテンツに応じてイベント実行
                                contentViewActivity.performRemoteEvent(json);
                            }
                        }
                    }
                });
            }
        } catch (JSONException e) {
            Logger.e(TAG, "[update]" + json, e); // JSONエラーはUIには通知しない
        } catch (Exception e) {
            Logger.e(TAG, "[update]" + json, e);
            showToast(mContext.getString(R.string.ERROR));
        }
    }

    private void handleUpdateString(String data) {
        if (data.startsWith("onClose:")) { // 親がCloseしたのにまだビューワにいる場合
            boolean reflectContentView = true;

            if (data.startsWith("onClose:1000")) {
                saveMeetingInfo(null, null, null, false);
            } else if (contentViewActivity == null && data.endsWith(";" + MeetingManager.STATUS_PEND)) { // 初期接続の失敗では再接続アラートダイアログは出さない
                showEnterFailedAlert();
            } else {
                reflectContentView = false;
                lastDisconnect = System.currentTimeMillis();
                if ((contentViewActivity != null) && ABVActivity.isVisible()) { // Wifi以外の理由で接続が突然切れた場合
                    handler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            if (ABVEnvironment.getInstance().networkAdapter.isNetworkConnected()) {
                                if (!meetingManager.isOwner()) {
                                    try {
                                        String retSkey = meetingManager.refreshSkeyIfInvalid(); // セッションキーをリフレッシュする(司会者の場合リフレッシュすると親ではなくなってしまう)
                                        if (retSkey != null) {
                                            saveMeetingInfo(retSkey, null, null, null);
                                        }
                                    } catch (Exception e) {
                                        Logger.e(TAG, "refreshSkeyIfInvalid failed. ", e); // ignore
                                    }
                                }
                                if (meetingManager.getSkey() != null) {
                                    reconnectMeeting();
                                } else { // なぜかskeyがnullになるときがある。
                                    Logger.w(TAG, "skey is null.");
                                    try {
                                        reconnectMeetingAfterShutdown(R.string.msg_disconnected_reconnect);
                                    } catch (Exception e) {
                                        Logger.w(TAG, "reconnectMeetingAfterShutdown failed.", e);
                                        showToast(mContext.getString(R.string.msg_disconnected));
                                    }
                                }
                            }
                        }
                    }, 3000L); // 3秒後に自動再接続
                }
            }
            if (reflectContentView) {
                reflectContentView(data);
            }
        } else if (data.startsWith("onOpen:")) {
            String password = meetingManager.getJoinedMeetingPassword();
            saveMeetingInfo(meetingManager.getSkey(), meetingManager.getJoinedMeetingId(), (password != null ? password : ""), true);
        }

        if (operationMeetingListActivity != null) { // 会議室一覧画面への反映
            operationMeetingListActivity.update(data);
        }
    }

    private void showEnterFailedAlert() {
        handler.post(new Runnable() {
            @Override
            public void run() {
                ABookAlertDialog alertDialog = AlertDialogUtil.createAlertDialog(getCurrentActivity(), mContext.getString(R.string.error), mContext.getString(R.string.E125));
                alertDialog.setPositiveButton(R.string.ok, null);
                alertDialog.show();
            }
        });
    }

    protected void reflectContentView(String data) {
        if (meetingManager.isOwner()) {
            if (contentViewActivity != null) {
                contentViewActivity.switchMeetingExitButton();
            }
        } else {
            finishContentObjectActivity();
        }
    }

    private void handleUpdateDownload(final ContentZipDownloadNotification data) {
        if (data.getDownloadStatus() == DownloadStatusType.Succeeded) {
            if (!hasOperationListActivity()) { // OperationListActivityがStackにない場合無視
                Logger.w(TAG, "No OperationListActivity. Ignore download notification.");
                return;
            }

            showToast(mContext.getString(R.string.download_success));

            handler.postDelayed(new Runnable() { // DLのステータスがDBに反映されれるよりも先に通知が来るため１秒delayさせる。
                @Override
                public void run() {
                    if (meetingManager.isConnected()) { // 会議室参加の場合
                        meetingManager.setPaused(false);
                    }
                    contentDownloader.removeContentDownloadListener(ActivityHandlingHelper.this);
                }
            }, 1000);
        }
    }

    public boolean isDownloadEnable(ContentDto contentDto) {
        return !contentDto.downloadedFlg;
    }

    public boolean isUpdateEnable(ContentDto contentDto) {
        return contentDto.updatedFlg;
    }

    public void downloadUnAuthorizedContentInfo(long contentId) {
        //通話中の場合権限のないコンテンツの情報をダウンロードしてからコンテンツダウンロード確認ダイアログ表示
        try {
            contentDownloader.downloadUnAuthorizedContentInfo(contentId);
            contentDao.updateUnAuthorizedFlg(contentId, true);
        } catch (MalformedURLException e) {
            Logger.e(TAG, "getContent failed. contentId=" + contentId, e);
        }
    }

    /**
     * コンテンツのチェック　（未DLの場合はDLする）
     *
     * @param contentId
     * @param page
     * @return true:開いてOK、false:開くのはNG/すぐには開かない
     */
    public boolean checkContent(final long contentId, int page) {
        try {
            final ContentDto contentDto = contentDao.getContent(contentId);
            if (contentDto == null) {
                Logger.e(TAG, "Content not found. contentId=" + contentId);
                showToast(mContext.getString(R.string.no_content_need_refresh));
                return false;
            }

            if (contentDto.downloadedFlg && !contentDto.updatedFlg) { // DL && Update済みの場合はOK
                return true;
            }

            if (meetingManager.isSubscribed() // 会議室参加者の場合: ストリーミング優先、リンクコンテンツ、その他タイプのとき不可Ha
                    && (contentDto.isLinkType() || contentDto.isOtherType())) {
                showToast(mContext.getString(R.string.msg_content_not_allowed_at_meeting));
                return false;
            } else {
                handleDownload(contentId, contentDto); // DLを行ったのち開く
                return false;
            }
        } catch (Exception e) {
            Logger.e(TAG, "getContent failed. contentId=" + contentId, e);
            return false;
        }
    }

    /**
     * コンテンツダウンロード
     *
     * @param contentId
     * @param contentDto
     */
    private void handleDownload(final long contentId, final ContentDto contentDto) {
        meetingManager.setPaused(true);
        if (contentDto.downloadingFlg) {
            showToast(mContext.getString(R.string.link_download_waiting));
            if (contentDto.isDownloadPaused()) {
                try {
                    contentDownloader.resume(contentId);
                    contentDownloader.addContentDownloadListener(ActivityHandlingHelper.this);
                } catch (Exception e) {
                    Logger.e(TAG, "downloadContent failed. contentId=" + contentId, e);
                    showToast(mContext.getString(R.string.DOWNLOAD_ERROR));
                }
            }
        } else {
            if (contentDto.downloadedFlg && contentDto.updatedFlg) {
                // 更新処理
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        showUpdateConfirm(contentId, contentDto.contentName);
                    }
                });
            } else {
                // ダウンロード処理
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        showDownloadConfirm(contentId, contentDto.contentName);
                    }
                });
            }
        }
    }

    /**
     * 昇格依頼結果受信
     *
     * @param json
     */
    private void handleApprovalStatus(final JSONObject json) {
        final Boolean approved = JsonUtil.getBoolean(json, MeetingManager.APPROVED);
        if (approved == null) {
            return;
        }
        Logger.v(TAG, "CMD_APPROVALSTATUS %s", approved);
        handler.post(new Runnable() {
            @Override
            public void run() {
                int msgId;
                if (approved) { // 承認された場合
                    meetingManager.setOwner(true);
                    meetingManager.setPaused(false);
                    if (contentViewActivity != null) {
                        if (contentViewActivity instanceof ContentViewActivity) {
                            ((ContentViewActivity) contentViewActivity).setBarVisible(false);
                            ((ContentViewActivity) contentViewActivity).setMarkingReadOnly(false);
                        }
                        contentViewActivity.configureRemote();
                    }

                    if (operationMeetingListActivity != null) { // 会議室一覧は閉じておく
                        operationMeetingListActivity.finish();
                    }
                    msgId = R.string.msg_promotion_approved;
                } else { // 却下された場合
                    msgId = R.string.msg_promotion_denied;
                }
                showToast(mContext.getString(msgId));
            }
        });
    }

    /**
     * 昇格依頼受信
     *
     * @param json
     */
    private void handlePresenterRequest(final JSONObject json) {
        final String requesterId = json.getString(MeetingManager.LOGIN_ID);
        final String requesterSkey = json.getString(MeetingManager.ID);
        handler.post(new Runnable() {
            @Override
            public void run() {
                showPromotionRequest(requesterId, requesterSkey);
            }
        });
    }

    public void downloadContent(long contentId) {
        try {
            int checkStatus = getCurrentActivity().contentValidCheck(contentId);
            if (checkStatus == ABVAuthenticatedActivity.ContentCheckResultType.SUCCESS) {
                contentDownloader.download(contentId); // DL実行
                ContentDownloader downloader = ContentDownloader.getInstance();
                downloader.addContentDownloadListener(ActivityHandlingHelper.this);
            } else {
                showToast(mContext.getString(R.string.M002));
            }
        } catch (Exception e) {
            Logger.e(TAG, "downloadContent failed. contentId=" + contentId, e);
            showToast(mContext.getString(R.string.DOWNLOAD_ERROR));
        }
    }

    private void createDownloadConfirm(final long contentId, final String contentName) {
        if (downloadConfirmDialog != null && downloadConfirmDialog.isShowing()) { // すでにダイアログがある場合は閉じる
            downloadConfirmDialog.dismiss();
        }
        String unAuthorizedContentDownloadMsg = getCurrentActivity().getString(R.string.request_download_un_authorized_content);
        final boolean isNoAuthorizedContentDownloadRequest = contentName.equals(unAuthorizedContentDownloadMsg);

        downloadConfirmDialog = AlertDialogUtil.createAlertDialog(getCurrentActivity(), R.string.confirm);
        downloadConfirmDialog.setCancelable(false);
        if (isNoAuthorizedContentDownloadRequest) {
            downloadConfirmDialog.setMessage(unAuthorizedContentDownloadMsg);
        } else {
            downloadConfirmDialog.setMessage(String.format(mContext.getString(R.string.no_content2), contentName));
        }
        downloadConfirmDialog.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int whichButton) {
                downloadConfirmDialog.dismiss();
                //権限の無いコンテンツの場合：コンテンツ情報を先にダウンロード
                if (isNoAuthorizedContentDownloadRequest) {
                    downloadUnAuthorizedContentInfo(contentId);
                }
                downloadContent(contentId);
                downloadConfirmDialog = null;
            }
        });
        downloadConfirmDialog.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int whichButton) {
                downloadConfirmDialog.dismiss();
                if (meetingManager.isConnected()) {
                    meetingManager.setPaused(false);
                }
                downloadConfirmDialog = null;
            }
        });
    }

    /**
     * 資料の更新ダイアログ生成処理
     * @param contentId
     */
    private void createUpdateConfirm(final long contentId, final String contentName) {
        if (updateConfirmDialog != null && updateConfirmDialog.isShowing()) { // すでにダイアログがある場合は閉じる
            updateConfirmDialog.dismiss();
        }

        updateConfirmDialog = AlertDialogUtil.createAlertDialog(getCurrentActivity(), R.string.confirm);
        updateConfirmDialog.setCancelable(false);

        updateConfirmDialog.setMessage(String.format(mContext.getString(R.string.content_link_update), contentName));

        updateConfirmDialog.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int whichButton) {
                updateConfirmDialog.dismiss();
                downloadContent(contentId);
                updateConfirmDialog = null;
            }
        });
        updateConfirmDialog.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int whichButton) {
                updateConfirmDialog.dismiss();
                startContentActivity(contentId, 0);
                updateConfirmDialog = null;
            }
        });
    }

    /**
     * DL確認ダイアローグ表示
     *
     * @param contentId
     * @param contentName
     */
    private void showDownloadConfirm(final long contentId, String contentName) {
        createDownloadConfirm(contentId, contentName);
        downloadConfirmDialog.show();
    }

    // 資料更新画面表示
    private void showUpdateConfirm(final long contentId, final String contentName) {
        if (!ABVEnvironment.getInstance().networkAdapter.isNetworkConnected()) {
            // インターネットが繋がってない場合は、更新前の関連資料を開く
            startContentActivity(contentId, 0);
        } else {
            createUpdateConfirm(contentId, contentName);
            updateConfirmDialog.show();
        }
    }

    public void finishContentObjectActivity() {
        if (objectViewActivity != null) {
            objectViewActivity.finish();
            removeObjectViewActivity(objectViewActivity);
        }
        if (contentViewActivity != null) {
            contentViewActivity.finish();
            removeContentViewActivity(objectViewActivity);
        }
    }

    private void showToast(final String msg) {
        handler.post(new Runnable() {
            @Override
            public void run() {
                ABVToastUtil.showMakeText(mContext, msg, Toast.LENGTH_SHORT);
            }
        });
    }

    /**
     * 昇格依頼受信表示
     *
     * @param requesterId
     * @param requesterSkey
     */
    private void showPromotionRequest(String requesterId, final String requesterSkey) {
        if (promotionRequestAlertDialog != null && promotionRequestAlertDialog.getOwnerActivity() != null && !promotionRequestAlertDialog.getOwnerActivity().isFinishing() && promotionRequestAlertDialog.isShowing()) {
            Logger.w(TAG, "promotionRequestAlertDialog is showing. ignore request. requesterId=" + requesterId);
            return;
        }
        promotionRequestAlertDialog = AlertDialogUtil.createAlertDialog(getCurrentActivity(), R.string.confirm);
        promotionRequestAlertDialog.setMessage(String.format(mContext.getString(R.string.msg_approve_promotion), requesterId));
        promotionRequestAlertDialog.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int whichButton) { // 許可する場合
                try {
                    // 承認する前にマーキングモード終了メッセージを送信
                    if (contentViewActivity instanceof ContentViewActivity && ((ContentViewActivity)contentViewActivity).isMarkingStatus()) {
                        JSONObject jsonMarkingInvisible = new JSONObject();
                        jsonMarkingInvisible.put(MeetingManager.MARKING_ACTION, MeetingManager.MARKING_ACTION_END);
                        meetingManager.sendWs(MeetingManager.CMD_MARKING, contentViewActivity.getContentId(), contentViewActivity.getCurrentPageNumber(), null, jsonMarkingInvisible);
                    }

                    JSONObject json = new JSONObject();
                    json.put(MeetingManager.ID, requesterSkey);
                    json.put(MeetingManager.APPROVED, true);
                    meetingManager.sendWs(MeetingManager.CMD_APPROVALSTATUS, null, null, null, json);
                    meetingManager.setOwner(false); // 司会者ではなくなる
                    if (contentViewActivity != null) {
                        if (contentViewActivity instanceof ContentViewActivity) {
                            ((ContentViewActivity) contentViewActivity).setBarVisible(false);
                            ((ContentViewActivity) contentViewActivity).setMarkingReadOnly(true);
                        }
                        contentViewActivity.configureRemote();
                    } else {
                        startMeetingActivity();
                    }
                } catch (Exception e) {
                    Logger.e(TAG, "showPromotionRequest ok failed", e);
                    showToast("Promotion request failed.");
                }
                dialog.dismiss();
            }
        });
        promotionRequestAlertDialog.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int whichButton) { // 却下する場合
                JSONObject json = new JSONObject();
                json.put(MeetingManager.ID, requesterSkey);
                json.put(MeetingManager.APPROVED, false);
                meetingManager.sendWs(MeetingManager.CMD_APPROVALSTATUS, null, null, null, json);
                dialog.dismiss();
            }
        });
        promotionRequestAlertDialog.show();
    }

    /**
     * トップページに戻るメッセージを送信
     * （コンテンツリンクのときは送らないようにする）
     */
    private void sendToBookShelf() {
        if (meetingManager.isSendable()) {
            ABVAuthenticatedActivity activity = currentActivityStack.peek();
            if (!(activity instanceof ABVContentViewActivity)) {
                meetingManager.sendWs(MeetingManager.CMD_TOBOOKSHELF, null, null, null, null);
            }
        }
    }

    public void refreshMeetingListActivity() {
        if (operationMeetingListActivity != null) {
            operationMeetingListActivity.reloadMeetingList();
        }
    }

    // TODO: later meeting関係のメソッドは新しいクラスを作って移す
    public void saveMeetingInfo(String skey, Integer meetingId, String meetingPassword, Boolean meetingEnteredFlg) {
        Logger.v(TAG, "saveMeetingInfo skey=%s meetingId=%s meetingPassword=%s meetingEnteredFlg=%s", skey, meetingId, meetingPassword, meetingEnteredFlg);
        Editor editor = PreferenceUtil.getUserEditor(mContext);
        if (skey != null) {
            editor.putString(UserPrefKey.SKEY, skey);
        }
        if (meetingId != null) {
            editor.putInt(UserPrefKey.MEETING_ID, meetingId);
        }
        if (meetingPassword != null) {
            if (meetingPassword.isEmpty()) {
                editor.remove(UserPrefKey.MEETING_PASSWORD);
            } else {
                editor.putString(UserPrefKey.MEETING_PASSWORD, meetingPassword);
            }
        }
        if (meetingEnteredFlg != null) {
            editor.putBoolean(UserPrefKey.MEETING_ENTERED_FLG, meetingEnteredFlg);
            editor.putLong(UserPrefKey.MEETING_ENTERED_TIME, System.currentTimeMillis());
        }
        editor.commit();
    }

    /**
     * 前回会議室参加の際、強制終了となった場合起動時に再接続を促す
     *
     * @throws Exception
     */
    public void reconnectMeetingAfterShutdown(int resId) throws Exception {
        Logger.d(TAG, "reconnectMeeting isConnected=" + meetingManager.isConnected());
        if (!meetingManager.isConnected() && meetingAlertDialog == null) { // 接続が維持されている場合、一度表示したことがある場合は何もしない
            String skey = PreferenceUtil.getUserPref(mContext, UserPrefKey.SKEY, null);
            Integer meetingId = PreferenceUtil.getUserPref(mContext, UserPrefKey.MEETING_ID, -1);
            boolean enteredFlg = PreferenceUtil.getUserPref(mContext, UserPrefKey.MEETING_ENTERED_FLG, false); // 入室フラグ（正常退室した場合はfalse）
            boolean isExpired = (System.currentTimeMillis() - PreferenceUtil.getUserPref(mContext, UserPrefKey.MEETING_ENTERED_TIME, 0L) > mContext.getResources().getInteger(R.integer.meeting_reenter_alert) * 60 * 1000);// 前回入室日時（SystemTimeInMil）から指定時間(分)経過しているか
            Logger.d(TAG, "reconnectMeeting skey=" + skey + " meetingId=" + meetingId + " enteredFlg=" + enteredFlg + " isExpired=" + isExpired);
            if (skey != null && meetingId != -1 && enteredFlg && !isExpired) {
                meetingManager.setJoinedMeetingId(meetingId);
                List<MeetingDto> meetingDtoList = meetingManager.getMeetingList(skey);
                final MeetingDto meetingDto = meetingManager.getJoinedMeetingDto(meetingDtoList);
                if (meetingDto != null) { // まだ会議室が存在している場合
                    showEnterMeetingAlertDialog(resId, skey, meetingId, PreferenceUtil.getUserPref(mContext, UserPrefKey.MEETING_PASSWORD, null), skey.equals(meetingDto.presenterskey), true);
                }
            }
        }
    }

    /**
     * 会議室に再入室する
     */
    public void reconnectMeeting() {
        Logger.v(TAG, "reconnectMeeting lastDisconnect: %s", new Date(lastDisconnect));
        if (lastDisconnect != 0L && !meetingManager.isConnected() && meetingManager.getJoinedMeetingId() != MeetingManager.NO_MEETING_ID) {
            if (System.currentTimeMillis() - lastDisconnect > 3 * 60 * 1000) { // 3分以上経過の場合はアラート表示
                showEnterMeetingAlertDialog(R.string.msg_disconnected_reconnect, meetingManager.getSkey(), meetingManager.getJoinedMeetingId(), meetingManager.getJoinedMeetingPassword(), meetingManager.isOwner(), contentViewActivity == null);
            } else { // 自動的に接続
                reJoinMeeting(meetingManager.getSkey(), meetingManager.getJoinedMeetingId(), meetingManager.getJoinedMeetingPassword(), meetingManager.isOwner(), contentViewActivity == null);
            }
            lastDisconnect = 0L;
        } else if (meetingManager.isConnected() && meetingManager.isSubscribed()) { // 会議参加中の場合は最新の状態を適用
            meetingManager.applyLastMessage();
        }
    }

    public void showEnterMeetingAlertDialog(int resId, final String skey, final Integer meetingId, final String meetingPassword, final boolean isOwner, final boolean isHome) {
        //AlertDialogを表示
        Activity activity = getCurrentActivity();
        if (activity == null) {
            Logger.w(TAG, "getCurrentActivity is null");
            return;
        }

        ABookAlertDialog alert = AlertDialogUtil.createAlertDialog(activity, R.string.confirm);
        alert.setMessage(resId);
        alert.setCancelable(false);
        alert.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                contentRefresher.stopRefresh();
                meetingAlertDialog.dismiss();
                int i = 0;
                while (contentRefresher.isRefreshing() && i < 10) { // 確実に止まるまで待つ
                    try {
                        Thread.sleep(1000);
                        i++;
                    } catch (InterruptedException e) {
                    }
                }
                reJoinMeeting(skey, meetingId, meetingPassword, isOwner, isHome);
            }
        });
        alert.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                meetingAlertDialog.dismiss();
                disableMeetingEnteredFlg();
                if (isOwner) {
                    try {
                        meetingManager.deleteMeeting(meetingId, skey);
                    } catch (Exception e) { // ignore
                        Logger.e(TAG, "deleteMeeting failed.", e);
                    }
                }
                if (!isHome) {
                    finishContentObjectActivity();
                }
            }
        });

        meetingAlertDialog = alert;
        meetingAlertDialog.show();
    }

    public void startMeetingActivity() {
        String className = OperationMeetingListActivity.class.getName();
        boolean isNormalSize = (mContext.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_NORMAL;
        if (!isNormalSize) {
            className += "Dialog";
        }
        Intent intent = new Intent();
        intent.setClassName(mContext.getPackageName(), className);
        Activity activity = getCurrentActivity();
        if (activity != null) {
            activity.startActivity(intent);
        }
        if (isNormalSize) {
            if (activity != null) {
                activity.overridePendingTransition(R.anim.view_up, 0);
            }
        }
    }

    private void disableMeetingEnteredFlg() {
        PreferenceUtil.putUserPref(mContext, UserPrefKey.MEETING_ENTERED_FLG, false); // フラグをオフにする
    }

    /**
     * 会議に再度参加する
     *
     * @param skey
     * @param meetingId
     * @param meetingPassword
     * @param isOwner
     * @param isHome
     */
    public void reJoinMeeting(String skey, Integer meetingId, String meetingPassword, boolean isOwner, boolean isHome) {
        try {
            meetingManager.join(meetingId, skey, meetingPassword, isOwner);
            if (!isOwner && isHome) {
                startMeetingActivity();
            }
        } catch (Exception e) {
            Logger.e(TAG, "meeting reconnect error.", e);
            showToast(mContext.getString(R.string.E125));
        }
    }


    public boolean isMeetingConnected() {
        return meetingManager.isConnected();
    }

    @Override
    public void onDownloadingContentZip(ContentZipDownloadNotification notification) {
        handleUpdateDownload(notification);
    }

    @Override
    public void onRefreshedContent(boolean result, long contentId, Exception e) {
    } // ignore : not come here

    @Override
    public void onDownloadedContentDetail(HttpDownloadSimpleNotification notification) {
    } // ignore : not come here

    @Override
    public void onAuthenticationFailed() {
    } // ignore : not come here

    // 上位のClassからHTML側のコールを行うための処理
    public void callOzdHtmlScript(String url) {
        if (!currentActivityStack.isEmpty()) {
            for (final ABVAuthenticatedActivity activity : currentActivityStack) {
                final String scriptUrl = url;
                if (activity instanceof ParentWebViewActivity) {
                    ((ParentWebViewActivity) activity).callViewLoadUrl(scriptUrl);
                } else if (activity instanceof ContentViewActivity) {
                    ((ContentViewActivity) activity).callOzWebViewLoadUrl(scriptUrl);
                }
            }
        }
    }

    // ActivityであるClassからCheckOZDViewActivityを確認する処理
    public boolean searchOzdActivityStack() {
        return false;
    }

    // ActivityであるClassからCheckOZDViewActivityを確認して画面を閉じる処理
    public void selectedOzdActivityClose() {
    }

    // ActivityであるClassからCheckOZDViewActivityを確認してContextの値を変更する。
    public Context selectedOzdAtivityContext() {
        return null;
    }

    /**
     * 設定画面から戻る用
     * @return 設定画面へ遷移前の画面
     */
    public ABVUIActivity getPreviousOfSettingActivity() {
        return previousOfSettingActivity;
    }

    /**
     * 設定画面遷移前に設定
     * @param activity
     */
    public void setPreviousOfSettingActivity(ABVUIActivity activity) {
        this.previousOfSettingActivity2 = null;
        this.previousOfSettingActivity = activity;
    }

    /**
     * 設定画面から戻る用
     * @return 設定画面へ遷移前の画面
     */
    public ParentWebViewActivity getPreviousForChatOfSettingActivity() {
        return previousOfSettingActivity2;
    }

    /**
     * 設定画面遷移前に設定
     * @param activity
     */
    public void setPreviousOfSettingActivity(ParentWebViewActivity activity) {
        this.previousOfSettingActivity = null;
        this.previousOfSettingActivity2 = activity;
    }
}
