package jp.agentec.abook.abv.ui.common.activity;

import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.net.ConnectivityManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.text.InputType;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CheckedTextView;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;

//import com.google.firebase.iid.FirebaseInstanceId;
import androidx.annotation.NonNull;

import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.messaging.FirebaseMessaging;
import com.google.zxing.WriterException;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

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.DeliveryType;
import jp.agentec.abook.abv.bl.acms.type.DownloadStatusType;
import jp.agentec.abook.abv.bl.acms.type.LoginMode;
import jp.agentec.abook.abv.bl.acms.type.UpdateSelect;
import jp.agentec.abook.abv.bl.common.ABVEnvironment;
import jp.agentec.abook.abv.bl.common.Callback;
import jp.agentec.abook.abv.bl.common.CommonExecutor;
import jp.agentec.abook.abv.bl.common.Constant;
import jp.agentec.abook.abv.bl.common.Constant.AlertMessageLevel;
import jp.agentec.abook.abv.bl.common.constant.ABookKeys;
import jp.agentec.abook.abv.bl.common.exception.ABVException;
import jp.agentec.abook.abv.bl.common.exception.ABVExceptionCode;
import jp.agentec.abook.abv.bl.common.exception.ABVRuntimeException;
import jp.agentec.abook.abv.bl.common.exception.AcmsException;
import jp.agentec.abook.abv.bl.common.exception.NetworkDisconnectedException;
import jp.agentec.abook.abv.bl.common.log.Logger;
import jp.agentec.abook.abv.bl.common.util.ContentFileUtil;
import jp.agentec.abook.abv.bl.data.ABVDataCache;
import jp.agentec.abook.abv.bl.data.dao.AbstractDao;
import jp.agentec.abook.abv.bl.data.dao.ContentDao;
import jp.agentec.abook.abv.bl.data.dao.MemberInfoDao;
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.logic.AbstractLogic;
import jp.agentec.abook.abv.bl.logic.BookmarkLogic;
import jp.agentec.abook.abv.bl.logic.CategoryLogic;
import jp.agentec.abook.abv.bl.logic.ContentLogic;
import jp.agentec.abook.abv.bl.logic.ContractLogic;
import jp.agentec.abook.abv.bl.logic.GroupLogic;
import jp.agentec.abook.abv.bl.logic.MemoLogic;
import jp.agentec.abook.abv.bl.logic.UserAuthenticateLogic;
import jp.agentec.abook.abv.cl.billing.Purchase;
import jp.agentec.abook.abv.cl.helper.ABVUncaughtExceptionHandler;
import jp.agentec.abook.abv.cl.push.FcmManager;
import jp.agentec.abook.abv.cl.util.AndroidStringUtil;
import jp.agentec.abook.abv.cl.util.BitmapUtil;
import jp.agentec.abook.abv.cl.util.PreferenceUtil;
import jp.agentec.abook.abv.cl.util.RawResourceUtil;
import jp.agentec.abook.abv.cl.util.StorageUtil;
import jp.agentec.abook.abv.launcher.android.ABVApplication;
import jp.agentec.abook.abv.launcher.android.R;
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.constant.ErrorCode;
import jp.agentec.abook.abv.ui.common.constant.ErrorMessage;
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.common.util.DisplayUtil;
import jp.agentec.abook.abv.ui.common.util.Initializer;
import jp.agentec.abook.abv.ui.common.view.ABVBatchSyncView;
import jp.agentec.abook.abv.ui.common.vo.Size;
import jp.agentec.abook.abv.ui.home.activity.HelpActivity;
import jp.agentec.abook.abv.ui.home.activity.LoginActivity;
import jp.agentec.abook.abv.ui.home.activity.SplashScreenActivity;
import jp.agentec.abook.abv.ui.home.helper.ActivityHandlingHelper;
import jp.agentec.abook.abv.ui.home.helper.ContentViewHelper;
import jp.agentec.abook.abv.ui.viewer.foxitPdf.PdfImageProvider;
import jp.agentec.adf.net.http.HttpDownloadSimpleNotification;
import jp.agentec.adf.util.StringUtil;

public abstract class ABVAuthenticatedActivity extends ABVActivity implements ContentDownloadListener {
	private final static String TAG = "ABVAuthenticatedActivity";

	public static final String FILEPATH = "FILEPATH";

	protected ContentDao contentDao = AbstractDao.getDao(ContentDao.class);

	protected MemoLogic memoLogic = AbstractLogic.getLogic(MemoLogic.class);
	protected BookmarkLogic bookmarkLogic = AbstractLogic.getLogic(BookmarkLogic.class);
	protected ContentDownloader contentDownloader = ContentDownloader.getInstance();
	protected ContentRefresher contentRefresher = ContentRefresher.getInstance();

	private ExecutorService initilizeExecutor = Executors.newFixedThreadPool(2); // DL後の初期化専用

	protected ImageButton btnDownload;
	protected ActivityHandlingHelper activityHandlingHelper;
	protected Size mDisplaySize;
	// 一括同期ビュー（コントロール）
	protected ABVBatchSyncView batchSyncView;
	/**
	 * メッセージ表示タイプ
	 */
	public interface MessageType {
		int TYPE_SHOW_NONE = 0;
		int TYPE_SHOW_TOAST = 1;
		int TYPE_SHOW_ALERT = 2;
	}
	
	public interface ContentCheckResultType {
		int NETWORK_ERROR = -2;
		int ERROR = -1;
		int SUCCESS = 0;
		int NO_AUTH_DELETE = 1;
		int CHANGED_META_INFO = 2;
		int PAYMENT = 3;
	}

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
        sendRegistrationIdToCMS();
		activityHandlingHelper = ActivityHandlingHelper.getInstance();
		activityHandlingHelper.setCurrentActivity(this);
	}

	private void sendRegistrationIdToCMS() {
        // Tokenが更新されたか確認
        if (!PreferenceUtil.getUserPref(this, UserPrefKey.NEED_SEND_TOKEN, false)){
            // 更新されてない
            return;
        }
		final Callback resultCallback = new Callback() {
			@Override
			public Object callback(Object ret) {
				String fcmToken = (String)ret;
				needSendDeviceToken(fcmToken);
				return null;
			}
		};
		FcmManager.getFcmToken(this, resultCallback);
	}

	private void needSendDeviceToken(String fcmToken) {
		boolean isSendSuccess = false;
		// CMSに送信
		if (getRInteger(R.integer.push_message) == 1 && fcmToken != null) {
			try {
				// 既にMacAddress使用に同意している場合はMacAddressを使う
				// 認証なしの場合はUUIDを使用する
				if (ABVEnvironment.getInstance().deviceIdType != Constant.DeviceIdType.MAC_ADDRESS) {
					AbstractLogic.getLogic(UserAuthenticateLogic.class).updateDeviceTokenByUUID(fcmToken);
				} else {
					AbstractLogic.getLogic(UserAuthenticateLogic.class).updateDeviceTokenByMacAdress(fcmToken);
				}
				isSendSuccess = true;
			} catch (NetworkDisconnectedException e) {
				Logger.w(TAG, "[sendRegistrationIdToCMS] NetworkDisconnectedException");
			} catch (Exception e) {
				Logger.e(TAG, "[sendRegistrationIdToCMS]", e);
			}
		}
		// CMSへ更新した結果をセットする
		PreferenceUtil.putUserPref(this, UserPrefKey.NEED_SEND_TOKEN, !isSendSuccess);
	}


	@Override
	protected void onStart() {
		super.onStart();
		// 前回起動時にアプリが強制終了した場合、オプションで送信オンになっている場合は例外トレース情報を送信する（設定によりメールかCMSへ送信）
		ABVUncaughtExceptionHandler.getInstancer().sendBugReport(this);
	}

	@Override
	protected void onResume() {
		super.onResume();
		if (!ABVEnvironment.getInstance().isInitialized()) {
			Initializer.getInstance().init(getABVApplication());
		}
		validateLoginStatus();
		
		if (ABVEnvironment.getInstance().acmsAddress == null) {
			loadAddressIfSaasGeneral();
		}

		contentDownloader.addContentDownloadListener(this);
	}

	@Override
	protected void onPause() {
		super.onPause();
		contentDownloader.removeContentDownloadListener(this);
	}

	@Override
	protected void onDestroy() {
		super.onDestroy();
		activityHandlingHelper.removeCurrentActivity(this);
	}

	@Override
	protected void onApplicationBroughtFromBackground() {
		new Handler().post(new Runnable() {
			@Override
			public void run() {
				if (checkForceOfflineLogout()) {
					finish();
				} else {
					if (checkValidAuthTime()) {
						finish();
					} else {
						checkRequiredChangePassword(null);
					}
				}
			}
		});
	}

	@Override
	protected void onPasswordChanged() {
	}

	private void validateLoginStatus() {
		boolean isLoggedIn = true;

		try {
			isLoggedIn = (ABVDataCache.getInstance().getMemberInfo() != null);
		} catch (ABVRuntimeException e) {
			Logger.e("onResume failed", e);

			if (e.getCode() == ABVExceptionCode.C_E_SECURITY_1004) {
				isLoggedIn = false;
			}
		} catch (Exception e) {
			Logger.e("onResume failed", e);
		}

		if (!isLoggedIn) {
			ErrorMessage.showErrorMessageToast(this, ErrorCode.C_E_SECURITY_1004);

			Intent intent = new Intent();
			intent.setClassName(getApplicationContext().getPackageName(), LoginActivity.class.getName()).setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
			startActivity(intent);
			finish();
		}
	}

	/**
	 * Viewを開始します。
	 */
	public void startContentViewActivity(Intent intent, long contentId) {
        // 該当コンテンツが360コンテンツ＆直前にある場合、startActivityで移動せず、履歴で残っているActivityをそのまま表示する。
        if (checkPanoContent(contentId) && ActivityHandlingHelper.getInstance().hasPreviousPanoContentId(contentId)) {
            finish();
            return;
        }

        // 直前のActivityにはないが、同じ360コンテンツが存在している場合、それをfinishさせる。
        ActivityHandlingHelper.getInstance().deleteExistPanoContentId(contentId);

		// コンテンツアラートのサービスオプションがYの時はアラートを表示
		if (AbstractLogic.getLogic(ContractLogic.class).getContentAlert()) {
			contentViewActivityMoveWithContentAlert(intent, contentId, NaviConsts.Right);
		} else {
			contentViewActivityMoveWithAccessLocationAlert(intent, contentId, NaviConsts.Right);
		}
	}

    /**
     * 360コンテンツ使用可能かのチェック
     * バーチャルツアー：OS4.4以上
     * 360動画：OS5.0以上
     * @param contentId
     * @return
     */
    private boolean checkPanoContent(long contentId) {
        int ret = ContentViewHelper.getInstance().check360Content(contentId);
        return ret == 0 ? false : true;
    }

	private void contentViewActivityMoveWithContentAlert(final Intent intent, final long contentId, final NaviConsts ABVNavi) {
		ContentDto contentDto = contentDao.getContent(contentId);
		// コンテンツ表示制限チェック
		switch (contentDto.alertMessageLevel) {
			case AlertMessageLevel.NONE :
				contentViewActivityMoveWithAccessLocationAlert(intent, contentId, ABVNavi);
				break;
			case AlertMessageLevel.MESSAGE :
				showContentMessageDialog(intent, contentId, contentDto.alertMessage, ABVNavi);
				break;
			case AlertMessageLevel.PASSWORD :
				showPasswordCheckDialog(intent, contentId, null, ABVNavi);
				break;
		}
	}

	private void contentViewActivityMoveWithAccessLocationAlert(final Intent intent, final long contentId, final NaviConsts ABVNavi) {
		contentViewActivityMove(intent, contentId, ABVNavi);
		//位置情報のアプリ内の許可しないように修正
//		if (!getABVUIDataCache().isShowedPermissionAccessLocationAlert() && ( AbstractLogic.getLogic(ContractLogic.class).getUsableReadinglogGps())) {
//			// 位置情報取得許可アラートを一度も表示していない場合表示する
//			putUserPref(UserPrefKey.SHOWED_PERMISSION_ACCESS_LOCATION_ALERT, true);
//			showPermissionAccessLocationAlert(intent, contentId, ABVNavi);
//		} else {
//			contentViewActivityMove(intent, contentId, ABVNavi);
//		}
	}

	private void showPermissionAccessLocationAlert(final Intent intent, final long contentId, final NaviConsts ABVNavi) {
		ABookAlertDialog dialog = AlertDialogUtil.createAlertDialog(this, R.string.app_name);
		dialog.setMessage(String.format(getString(R.string.access_location_message), getString(R.string.app_name)));
		dialog.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				putUserPref(DefPrefKey.PERMISSION_ACCESS_LOCATION, true);
				contentViewActivityMove(intent, contentId, ABVNavi);
			}
		});
		dialog.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				putUserPref(DefPrefKey.PERMISSION_ACCESS_LOCATION, false);
				contentViewActivityMove(intent, contentId, ABVNavi);
			}
		});
		showAlertDialog(dialog);
	}

	private void contentViewActivityMove(final Intent intent, final long contentId, final NaviConsts ABVNavi) {
		Logger.v(TAG, "contentViewActivityMove. contentId=%s", contentId);
		final Context context = this;
		if (isRotatable()) {
			setFixedOrientation(true);
		}
		showProgressPopup();
		CommonExecutor.execute(new Runnable() {
			@Override
			public void run() {
				try {
					Thread.sleep(500);
					activityHandlingHelper.startContentActivity(context, intent, ABVNavi, null, contentId);
				} catch (FileNotFoundException e) {
					Logger.e(TAG, "startContentActivity " + contentId, e);
					handleErrorMessageToast(ErrorCode.E105);
				} catch (ActivityNotFoundException e) {
					Logger.e(TAG, "startContentActivity " + contentId, e);
					handleErrorMessageToast(ErrorCode.E112);
				} catch (Exception e) {
					Logger.e(TAG, "startContentActivity " + contentId, e);
					handleErrorMessageToast(ErrorCode.E107);
				} finally {
					closeProgressPopup();
					if (ABVAuthenticatedActivity.this instanceof ShowPushMessageDailogActivity) {
						if (getABVApplication().isAutoOpenAfterDownloadContent()) {
							//コンテンツダウンロードして自動的にコンテンツを開く場合：自動的に開くフラグ更新
							((ABVApplication)getApplication()).setAutoOpenAfterDownloadContent(false);
						} else {
							//ダウンロード済みコンテンツを開く場合：プッシュ―アクティビティを終了
							finish();
						}
					}
					if (isRotatable()) {
						setFixedOrientation(false);
					}
					finish();
				}
			}
		});
	}

	public void showContentMessageDialog(final Intent intent, final long contentId, String message, final NaviConsts ABVNavi) {
		ABookAlertDialog dialog = AlertDialogUtil.createAlertDialog(this, R.string.app_name);
		dialog.setMessage(message);
		dialog.setPositiveButton(R.string.confirm, new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				contentViewActivityMoveWithAccessLocationAlert(intent, contentId, ABVNavi);
			}
		});
		dialog.setNegativeButton(R.string.cancel, null);
		showAlertDialog(dialog);
	}

	public void showPasswordCheckDialog(final Intent intent, final long contentId, String additionalMessage, final NaviConsts ABVNavi) {
		ABookAlertDialog dialog = AlertDialogUtil.createAlertDialog(this, R.string.app_name);

		LinearLayout layout = new LinearLayout(this);
		layout.setOrientation(LinearLayout.VERTICAL);
		layout.setPadding(10, 0, 10, 0);

		TextView messageView = new TextView(this);
		messageView.setText(getString(R.string.L123));
		layout.addView(messageView);
		final EditText edtPassword = new EditText(this);
		edtPassword.setSingleLine(true);
		edtPassword.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
		layout.addView(edtPassword);

		if (additionalMessage != null) {
			TextView additionalMessageView = new TextView(this);
			additionalMessageView.setText(additionalMessage);
			additionalMessageView.setTextColor(Color.RED);
			layout.addView(additionalMessageView);
		}

		edtPassword.setOnEditorActionListener(new TextView.OnEditorActionListener() {
			@Override
			public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
				passwordCheck(intent, contentId, ABVNavi, edtPassword.getText().toString());
				return true;
			}
		});
		dialog.setView(layout);

		dialog.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				passwordCheck(intent, contentId, ABVNavi, edtPassword.getText().toString());
			}
		});

		dialog.setNegativeButton(R.string.cancel, null);
		showAlertDialog(dialog);
	}

	private void passwordCheck(final Intent intent, final long contentId, final NaviConsts ABVNavi, String password) {
		if (StringUtil.isNullOrEmpty(password)) {
			showPasswordCheckDialog(intent, contentId, getString(R.string.E002), ABVNavi);
		} else {
			UserAuthenticateLogic userAuthenticateLogic;
			userAuthenticateLogic = AbstractLogic.getLogic(UserAuthenticateLogic.class);
			if (userAuthenticateLogic.checkPassword(password)) {
				contentViewActivityMoveWithAccessLocationAlert(intent, contentId, ABVNavi);
			} else {
				showPasswordCheckDialog(intent, contentId, getString(R.string.E129), ABVNavi);
			}
		}

	}

	@Override
	public void onAuthenticationFailed() {
		handleErrorMessageToast(ErrorCode.S_E_ACMS_1403);
		callLoginActivity(true, false, false);
	}

	@Override
	public void onDownloadedContentDetail(HttpDownloadSimpleNotification notification) {
	}

	@Override
	public void onDownloadingContentZip(final ContentZipDownloadNotification notification) {
		if (notification.getError() != null) {
			runOnUiThread(new Runnable() {
				@Override
				public void run() {
					handleError(notification.getError());
				}
			});
		}
	}

	@Override
	public void onRefreshedContent(boolean result, long contentId, final Exception e) {
		if (e != null) {
			Logger.e(TAG, "onRefreshedContent failed. contentId=" + contentId, e);
		}
		runOnUiThread(new Runnable() {
			@Override
			public void run() {
				if (!contentRefresher.isRefreshing()) {
					configureKeepScreen();
				}
				if (e != null) {
					handleError(e);
				}
			}
		});
	}

	/**
	 * メッセージを表示しないコンテンツチェック
	 * 呼び出し元でチェック結果の処理を行う
	 * @param contentId
	 * @return
	 */
	//CustomUrlでダウンロードまたは権限のないコンテンツをダウンロードする前にコンテンツの有効性をチェックするため、(ActivityHandlingHelperで使う)protectedからpublicに変更
	public int contentValidCheck(long contentId) {
		return contentValidCheckAndShowMessage(contentId, 0);
	}

	/**
	 * コンテンツの有効性のチェックを行う
	 * @param contentId
	 * @param showMessageType {@link MessageType}
	 * @return チェック結果 int {@link ContentCheckResultType}
	 */
	protected int contentValidCheckAndShowMessage(long contentId, int showMessageType) {
		int checkStatus;
		try {
			ContentDto dto = contentDao.getContent(contentId);
			if (dto == null) {
                return ContentCheckResultType.ERROR;
            }
			
			ContractLogic contractLogic = AbstractLogic.getLogic(ContractLogic.class);
			checkStatus = contentLogic.getContentCheckDeliverable(contentId, dto.resourceVersion);
			if (checkStatus == ContentCheckResultType.NO_AUTH_DELETE) {
				// サーバ側でコンテンツがダウンロード出来ない状態(非公開、削除など)の時、該当コンテンツを削除する
				if (contractLogic.isDeleteNoAuthContent()) {
					// 強制削除の場合、権限喪失コンテンツを削除する
					if (contentDao.isExist(contentId)) {
						deleteContent(contentDao.getContent(contentId), true);
					}
				} else {
					// 強制削除ではない場合、
					// 削除されているものはアップデートフラグをfalseにする
					ContentDto contentDto = contentDao.getContent(contentId); // FIXME: なぜここで再度コンテンツを取得している？？
					if (contentDto != null && contentDto.downloadedFlg && contentDto.updatedFlg) {
						contentDto.updatedFlg = false;
						contentDao.updateContent(contentDto, false);
					}
				}
				if (showMessageType == MessageType.TYPE_SHOW_TOAST) {
					handleErrorMessageToast(ErrorCode.M002);
				} else if (showMessageType ==  MessageType.TYPE_SHOW_ALERT) {
					handleErrorMessageDialog(R.string.app_name, ErrorCode.M002);
				}
			} else if (checkStatus == ContentCheckResultType.CHANGED_META_INFO) {
				// メタバージョンの違い
				if (showMessageType ==  MessageType.TYPE_SHOW_TOAST) {
					handleErrorMessageToast(ErrorCode.M005);
				} else if (showMessageType ==  MessageType.TYPE_SHOW_ALERT) {
					handleErrorMessageDialog(R.string.app_name, ErrorCode.M005);
				}
			} else {
				DownloadedContentInfoJSON json = ContentFileUtil.getDownloadedContentInfoJSON(contentId);
				// アンケートと試験コンテンツの場合、回答済みの場合ダウンロードさせない
				if(ContentJSON.KEY_ENQUETE_TYPE.equals(json.contentType) || ContentJSON.KEY_EXAM_TYPE.equals(json.contentType)){
					if (ActivityHandlingHelper.getInstance().isAnsweredEnquete(json)) {
						checkStatus = ContentCheckResultType.ERROR;
					}
				}
			}
		} catch (NetworkDisconnectedException e) {
			Logger.e(TAG, "NetworkDisconnectedException" + e);
			handleErrorMessageToast(ErrorCode.NETWORK);
			checkStatus = ContentCheckResultType.NETWORK_ERROR;
		} catch (ABVException e) {
			Logger.e(TAG, "contentCheckDeliverable ", e);

			if (e.getCode() == ABVExceptionCode.S_E_ACMS_1403) {
				onAuthenticationFailed();
			} else {
				handleErrorMessageToast(ErrorMessage.getErrorCode(e));
			}
			checkStatus = ContentCheckResultType.ERROR;
		} catch (Exception e) {
			Logger.e(TAG, "contentCheckDeliverable failed.", e);
			handleErrorMessageToast(ErrorCode.E107);
			checkStatus = ContentCheckResultType.ERROR;
		}
		return checkStatus;
	}

	protected void deleteContent(ContentDto dto, boolean deletePhysical) {
		contentLogic.deleteContent(dto, deletePhysical);
	}

	protected boolean contentDownload(long contentId) {
		return contentDownload(contentId, true);
	}

	protected boolean contentDownload(final long contentId, boolean needCheckWifiFlag) {
		return contentDownload(contentId, true, true);
	}

	/**
	 * ダウンロード処理
	 * @param contentId
	 * @param needCheckWifiFlag
	 * @param isShowToast
	 * @return
	 */
	protected boolean contentDownload(final long contentId, boolean needCheckWifiFlag, final boolean isShowToast) {
		boolean result = true;
		try {
			if (needCheckWifiFlag) {
				// アラートを表示する設定かつ3G回線がアクティブの場合警告を表示
				showWifiDisconnectAlert(R.string.C_E_SYSTEM_0005, new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int which) {
						contentDownload(contentId, false, isShowToast);
					}
				}, new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int which) {
						ContentZipDownloadNotification notification = new ContentZipDownloadNotification();
						notification.contentId = contentId;
						notification.downloadStatus = DownloadStatusType.Canceled;
						onDownloadingContentZip(notification);
					}
				});
			} else {
				// 空き容量が少ない場合警告を表示
				if (!StorageUtil.isFreeSpaceEnough(this)) {
					Logger.w(TAG, "[storage free space enough]");
					if (isShowToast) {
						handleErrorMessageToast(ErrorCode.STORAGE_WARNING);
					}
				}
				contentDownloader.download(contentId);
			}
		} catch (NetworkDisconnectedException e) {
			Logger.e(TAG, "NetworkDisconnectedException" + e);
			if (isShowToast) {
				handleErrorMessageToast(ErrorCode.NETWORK);
			}
			result = false;
		} catch (ABVException e) {
			Logger.e("ABVException", e.toString());
			result = false;
		} catch (Exception e) {
			Logger.e(TAG, "Exception " + e);
			if (isShowToast) {
				handleErrorMessageToast(ErrorCode.E107);
			}
			result = false;
		}
		return result;
	}

	// Wifi非接続時のアラート表示
	public void showWifiDisconnectAlert(final int messageId, final DialogInterface.OnClickListener positive, final DialogInterface.OnClickListener negative) throws NetworkDisconnectedException {
		showWifiDisconnectAlert(messageId, R.string.download, positive, negative);
	}
	
	public void showWifiDisconnectAlert(final int messageId, final int titleId, final DialogInterface.OnClickListener positive, final DialogInterface.OnClickListener negative) throws NetworkDisconnectedException {
		if(ABVEnvironment.getInstance().networkAdapter.getActiveNetworkType() == ConnectivityManager.TYPE_MOBILE && PreferenceUtil.get(this, DefPrefKey.WIFI_ALERT_ENABLE, true)){
			handler.post(new Runnable() {
				@Override
				public void run() {
					final ABookAlertDialog alertDialog = AlertDialogUtil.createABookAlertDialog(ABVAuthenticatedActivity.this);
					alertDialog.setTitle(titleId);
					View checkBoxAlert = getLayoutInflater().inflate(R.layout.item_check_box_alert, null);
					alertDialog.setView(checkBoxAlert);
					TextView message = (TextView) checkBoxAlert.findViewById(R.id.message);
					message.setText(getString(messageId));

					final CheckBox checkBox = (CheckBox) checkBoxAlert.findViewById(R.id.check_box);
					alertDialog.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
						@Override
						public void onClick(DialogInterface dialog, int which) {
							PreferenceUtil.put(ABVAuthenticatedActivity.this, DefPrefKey.WIFI_ALERT_ENABLE, !checkBox.isChecked());
							positive.onClick(dialog, which);
						}
					});

					alertDialog.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
						@Override
						public void onClick(DialogInterface dialog, int which) {
							negative.onClick(alertDialog, which);
						}
					});

					TextView checkBoxMessage = (TextView) checkBoxAlert.findViewById(R.id.check_box_message);
					checkBoxMessage.setText(getString(R.string.not_show_nexttime));
					checkBoxMessage.setOnClickListener(new View.OnClickListener() {
						@Override
						public void onClick(View v) {
							checkBox.setChecked(!checkBox.isChecked());
						}
					});
					showAlertDialog(alertDialog);
				}
			});
		} else {
			positive.onClick(null, -1);
		}
	}

	public abstract boolean contentValidCheckAndDownload(long contentId);

	public void startContentViewActivity(long contentId) {
		startContentViewActivity(contentId, 0);
	}

	public void startContentViewActivity(long contentId, int pageNum) {
		Intent intent = new Intent();
		//		intent.putExtra("className", getClass().getName());
		intent.putExtra("page", pageNum);
		//		intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
		startContentViewActivity(intent, contentId);
	}

	protected void setDisplaySize() {
		mDisplaySize = DisplayUtil.getDisplaySize2(getApplicationContext());
		
		Logger.v(TAG, "[Size] display width=%s, height=%s", mDisplaySize.width, mDisplaySize.height);
	}

	private void handleError(final Exception e) {
		ErrorCode error;
		if (e instanceof AcmsException && ((AcmsException)e).getCode() == ABVExceptionCode.S_E_ACMS_1403) { //	再ログインが必要
			onAuthenticationFailed();
		} else {
			error = ErrorCode.L120;
			ErrorMessage.showErrorMessageToast(ABVAuthenticatedActivity.this, error);
		}
	}
	public void showUnAuthorizedContentWarningDialog(String msg) {
		ABookAlertDialog alertDialog = AlertDialogUtil.createAlertDialog(this, getString(R.string.app_name), msg);
		alertDialog.setPositiveButton(R.string.ok, null);
		alertDialog.show();
	}

	/**
	 * ヘルプ画面を表示
	 * @param helpViewType ヘルプ表示種類
	 */
	public void showHelpViewDialog(int helpViewType) {
		Intent intent = new Intent();
		String className = HelpActivity.class.getName();
		if (!isNormalSize()) {
			className += "Dialog";
		}
		intent.putExtra(ABookKeys.HELP_VIEW_TYPE, helpViewType);
		intent.setClassName(getApplicationContext().getPackageName(), className);
		startActivity(intent);

	}
	/**
	 * 一括同期処理中であるか確認
	 * @return
	 */
	public boolean isShowingBatchSync() {
		return batchSyncView != null && batchSyncView.isShowing();
	}
}
