package jp.agentec.abook.abv.cl.util;

import jp.agentec.abook.abv.bl.acms.client.json.content.MediaInfoJSON;
import jp.agentec.abook.abv.bl.acms.client.json.content.PageObjectJSON;
import jp.agentec.abook.abv.bl.common.Constant;
import jp.agentec.abook.abv.bl.common.log.Logger;
import jp.agentec.abook.abv.bl.data.dao.AbstractDao;
import jp.agentec.abook.abv.bl.data.dao.ContentObjectLogDao;
import jp.agentec.abook.abv.bl.dto.ContentObjectLogDto;
import jp.agentec.abook.abv.bl.logic.AbstractLogic;
import jp.agentec.abook.abv.bl.logic.ContentObjectLogLogic;
import jp.agentec.abook.abv.bl.logic.ContentPageReadingLogLogic;
import jp.agentec.abook.abv.bl.logic.ContentReadingLogLogic;
import jp.agentec.abook.abv.bl.logic.ContractLogic;
import jp.agentec.abook.abv.bl.websocket.MeetingManager;
import jp.agentec.abook.abv.launcher.android.R;
import jp.agentec.abook.abv.ui.home.helper.ABookPermissionHelper;
import jp.agentec.adf.util.DateTimeUtil;

import org.json.adf.JSONException;

import android.content.Context;
import android.location.Location;

public class ContentLogUtil {

	private static ContentLogUtil contentLogUtil;

	private ContentReadingLogLogic contentReadingLogLogic = AbstractLogic.getLogic(ContentReadingLogLogic.class);
	private ContentPageReadingLogLogic contentPageReadingLogLogic = AbstractLogic.getLogic(ContentPageReadingLogLogic.class);
	private ContentObjectLogLogic contentObjectLogLogic = AbstractLogic.getLogic(ContentObjectLogLogic.class);
	private ContractLogic contractLogic = AbstractLogic.getLogic(ContractLogic.class);
	private ContentObjectLogDao contentObjectLogDao = AbstractDao.getDao(ContentObjectLogDao.class);
	private MeetingManager meetingManager = MeetingManager.getInstance();
	private LocationManagerUtil locationManagerUtil;

	public static synchronized ContentLogUtil getInstance() {
		if (contentLogUtil == null) {
			contentLogUtil = new ContentLogUtil();
		}
		return contentLogUtil;
	}

	/**
	 * 閲覧ログ開始
	 * 
	 * @param context
	 * @param contentId
	 * @return
	 */
	public int startContentReadLog(Context context, final long contentId, boolean permissionAccessLocation) {
		// 閲覧ログ開始
		int readingLogId = contentReadingLogLogic.startContentReadLog(contentId);

		// 位置情報取得許可、サービスオプション、ビルドオプションチェック
		if (checkUsableReadinglogGps(contentId)) { //20190529 アプリ側の位置情報許可チェックはしない
            ABookPermissionHelper helper = new ABookPermissionHelper(context, Constant.ABookPermissionType.AccessFineLocation, null);
            // 権限チェックして、falseの場合、以下の処理は行わない
            if (!helper.checkMultiPermissions(false)) {
                return readingLogId;
            }
            // 位置情報取得
			locationManagerUtil = new LocationManagerUtil(context, new LocationManagerUtil.LocationManagerUtilListener() {
				@Override
				public void onGetLocationFailed() {
					// 取得に失敗した場合、何もしない
					Logger.e("**********onGetLocationFailed");
				}

				@Override
				public void onGetLocation(Location location) {
					contentReadingLogLogic.updateLocationContentReadLog(contentId, location.getLatitude(), location.getLongitude());
				}
			});
			locationManagerUtil.startLocationService();
		}

		return readingLogId;
	}

	/**
	 * GPS送信が有効かチェックする
	 * 
	 * @param contentId
	 * @return
	 */
	private boolean checkUsableReadinglogGps(long contentId) {
		return contractLogic.getUsableReadinglogGps();
	}
	
	private boolean checkUsableReadinglogObject(long contentId) {
		return contractLogic.getUsableReadinglogObject();
	}

	/**
	 * ページ別閲覧ログ開始
	 * 
	 * @param contentId
	 * @param readingLogId
	 * @param pageNum
	 */
	public void startContentPageReadLog(long contentId, int readingLogId, int pageNum) {
		// サービスオプションチェック(オブジェクトログとページ別閲覧ログは連動)
		// 参加者で遠隔連動中はログを記録しない
		if ((!meetingManager.isSubscribed() || meetingManager.isPaused()) && checkUsableReadinglogObject(contentId)) {
			try {
				contentPageReadingLogLogic.startContentPageReadLog(contentId, readingLogId, pageNum);
			} catch (Exception e) { // 司会者で再起動時ここでなぜかconstraint errorとなる。無視。
				Logger.w("ContentLogUtil", "startContentPageReadLog error. contentId=%s, readingLogId=%s, pageNum%s, error=%s", contentId, readingLogId, pageNum, e.toString());
			}
		}
	}

	/**
	 * ページ別閲覧ログ一時停止
	 *
	 * @param contentId
	 * @param readingLogId
	 * @param pageNum
	 */
	public void pauseContentPageReadLog(long contentId, int pageNum, long readingLogId) {
		// サービスオプションチェック(オブジェクトログとページ別閲覧ログは連動)
		if ((!meetingManager.isSubscribed() || meetingManager.isPaused()) && checkUsableReadinglogObject(contentId)) {
			contentPageReadingLogLogic.pauseContentPageReadLog(contentId, pageNum, readingLogId);
		}
	}

	/**
	 * ページ別閲覧ログ終了
	 * 
	 * @param contentId
	 * @param pageNum
	 */
	public void endContentPageReadLog(long contentId, int pageNum, long readingLogId) {
		if (locationManagerUtil != null) {
			locationManagerUtil.stopLocationService();
		}

		// サービスオプションチェック(オブジェクトログとページ別閲覧ログは連動)
		if (checkUsableReadinglogObject(contentId)) {
			contentPageReadingLogLogic.endContentPageReadLog(contentId, pageNum, readingLogId);
		}
	}

	 /**
	 * ページ移動時のログ記録
	 * 移動元のページを終了、移動先のページを開始
	 * 
	 * @param contentId
	 * @param readingLogId
	 * @param fromPageNum
	 * @param toPageNum
	 */
	public void contentPageMove(long contentId, int readingLogId, int fromPageNum, int toPageNum) {
		endContentPageReadLog(contentId, fromPageNum, readingLogId);
		startContentPageReadLog(contentId, readingLogId, toPageNum);
	}

	/**
	 * オブジェクトログ追加
	 * 
	 * @param contentId
	 * @param readingLogId
	 * @param pageObjectJSON
	 * @return
	 */
	public int insertContentObjectLog(long contentId, int readingLogId, PageObjectJSON pageObjectJSON) {
		int contentObjectLogId = -1;
		// サービスオプションチェック(オブジェクトログとページ別閲覧ログは連動)
		// 参加者で遠隔連動中はログを記録しない
		if ((!meetingManager.isSubscribed() || meetingManager.isPaused()) && checkUsableReadinglogObject(contentId)) {
			MediaInfoJSON mediaInfoJSON = pageObjectJSON.getMediaInfo();
			long resourceId = mediaInfoJSON.getResourceId();
			contentObjectLogId = insertContentObjectLog(contentId, readingLogId, pageObjectJSON, resourceId);
		}
		return contentObjectLogId;
	}
	
	public int insertContentObjectLog(long contentId, int readingLogId, PageObjectJSON pageObjectJSON, long resourceId) {
		int contentObjectLogId = -1;
		// サービスオプションチェック(オブジェクトログとページ別閲覧ログは連動)
		// 参加者で遠隔連動中はログを記録しない
		if ((!meetingManager.isSubscribed() || meetingManager.isPaused()) && checkUsableReadinglogObject(contentId)) {
			try {
				contentObjectLogId = contentObjectLogLogic.insertContentObjectLog(contentId, readingLogId, pageObjectJSON, resourceId);
			} catch (JSONException e) {
				Logger.e(getClass().getName(), "insertContentObjectLog error.", e); // ログなのでJSON関係のエラーは無視（オブジェクトが表示できていれば、ここに来ることはない）
			}
		}
		return contentObjectLogId;
	}

	public void insertZoomLog(long contentId, int readingLogId, int pageNum, double x, double y, String eventType) {
		if ((!meetingManager.isSubscribed() || meetingManager.isPaused()) && checkUsableReadinglogObject(contentId)) {
			ContentObjectLogDto dto = new ContentObjectLogDto();
			dto.objectLogId = contentObjectLogDao.getNewContentObjectLogId();
			dto.readingLogId = readingLogId;
			dto.actionDate = DateTimeUtil.getCurrentDate();
//			dto.resumeDate;
			dto.contentId = contentId;
			dto.pageNum = pageNum;
			dto.objectId = 0;
			dto.resourceId = -1;
			dto.mediaType = -1;
			dto.actionType = 101;
//			dto.actionValue;
//			dto.actionTime;
			dto.locationX = x;
			dto.locationY = y;
			dto.locationHeight = 0;
			dto.locationWidth = 0;
			dto.eventType = eventType;
			contentObjectLogDao.insertContentObjectLog(dto);
		}
	}

	/**
	 * アクションタイム更新
	 * 
	 * @param objectLogId
	 * @param contentId
	 * @param actionTimeMillis ミリ秒
	 */
	public void updateActionTime(long contentId,int objectLogId, int actionTimeMillis) {
		// サービスオプションチェック(オブジェクトログとページ別閲覧ログは連動)
		// 参加者で遠隔連動中はログを記録しない
		if ((!meetingManager.isSubscribed() || meetingManager.isPaused()) && checkUsableReadinglogObject(contentId) && objectLogId != -1) {
			// ミリ秒から秒に変換
			contentObjectLogLogic.updateActionTime(objectLogId, actionTimeMillis / 1000);
		}
	}

	/**
	 * オブジェクトログ開始（再開）
	 * 
	 * @param objectLogId
	 */
	public void resumeObjectLog(long contentId, int objectLogId) {
		// サービスオプションチェック(オブジェクトログとページ別閲覧ログは連動)
		// 参加者で遠隔連動中はログを記録しない
		if ((!meetingManager.isSubscribed() || meetingManager.isPaused()) && checkUsableReadinglogObject(contentId) && objectLogId != -1) {
			ContentObjectLogDto contentObjectLogDto = contentObjectLogDao.getContentObjectLog(objectLogId);
			if (contentObjectLogDto != null) {
				contentObjectLogDto.resumeDate = DateTimeUtil.getCurrentDate();
				contentObjectLogDao.updateContentObjectLog(contentObjectLogDto);
			}
		}
	}

	/**
	 * オブジェクトログ終了（一時停止）
	 * 
	 * @param objectLogId
	 */
	public void endObjectLog(long contentId, int objectLogId) {
		// サービスオプションチェック(オブジェクトログとページ別閲覧ログは連動)
		// 参加者で遠隔連動中はログを記録しない
		if ((!meetingManager.isSubscribed() || meetingManager.isPaused()) && checkUsableReadinglogObject(contentId) && objectLogId != -1) {
			ContentObjectLogDto contentObjectLogDto = contentObjectLogDao.getContentObjectLog(objectLogId);
			// ミリ秒から秒に変換
			if (contentObjectLogDto != null) {
				int actionTime = (int) (DateTimeUtil.getCurrentDate().getTime() - contentObjectLogDto.resumeDate.getTime()) / 1000;
				actionTime = contentObjectLogDto.actionTime + actionTime;
				contentObjectLogLogic.updateActionTime(objectLogId, actionTime);
			}
		}
	}
}
