package jp.agentec.abook.abv.bl.logic;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.List;

import jp.agentec.abook.abv.bl.acms.client.AcmsClient;
import jp.agentec.abook.abv.bl.acms.client.parameters.ContentReadingLogParameters;
import jp.agentec.abook.abv.bl.acms.type.ContentReadingStatus;
import jp.agentec.abook.abv.bl.common.ABVEnvironment;
import jp.agentec.abook.abv.bl.common.Constant.ReadingLogMode;
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.data.dao.AbstractDao;
import jp.agentec.abook.abv.bl.data.dao.ContentObjectLogDao;
import jp.agentec.abook.abv.bl.data.dao.ContentPageReadingLogDao;
import jp.agentec.abook.abv.bl.data.dao.ContentReadingLogDao;
import jp.agentec.abook.abv.bl.dto.ContentReadingLogDto;
import jp.agentec.adf.util.DateTimeUtil;
import jp.agentec.adf.util.DateTimeUtil.DateUnit;
public  class ContentReadingLogLogic extends AbstractLogic {
	private static final String TAG = "ContentReadingLogLogic";
	private ContentReadingLogDao contentReadingLogDao = AbstractDao.getDao(ContentReadingLogDao.class);
	private ContentPageReadingLogDao contentPageReadingLogDao = AbstractDao.getDao(ContentPageReadingLogDao.class);
    private ContentPageReadingLogLogic contentPageReadingLogLogic = AbstractLogic.getLogic(ContentPageReadingLogLogic.class);
	private ContentObjectLogDao contentObjectLogDao = AbstractDao.getDao(ContentObjectLogDao.class);
	private ContentObjectLogLogic contentObjectLogLogic = AbstractLogic.getLogic(ContentObjectLogLogic.class);
	
	/*package*/ ContentReadingLogLogic() {
	}
	
	public void prepareContentReadLog(long contentId) {
		ContentReadingLogDto dto;
		dto = contentReadingLogDao.getContentReadingLog(contentId);

		if (dto != null) {
			// 強制終了や電源OFFによって以前のログが残っている可能性があるのでページログ、オブジェクトログを削除する 
			contentPageReadingLogDao.deleteContentPageReadingLog(dto.contentId, dto.readingLogId);
			contentObjectLogDao.deleteContentObjectLog(dto.contentId, dto.readingLogId);
		}

		// 送信エラーのログ削除
		List<ContentReadingLogDto> sendErrorLogList = contentReadingLogDao.getContentReadLogs(ContentReadingStatus.sendError);
		for (ContentReadingLogDto sendErrorLog : sendErrorLogList) {
			if (DateTimeUtil.getCurrentDate().after(DateTimeUtil.add(sendErrorLog.startDate, DateUnit.Day, ABVEnvironment.SendErrorLogRetentionPeriod))) {
				contentPageReadingLogDao.deleteContentPageReadingLog(sendErrorLog.contentId, sendErrorLog.readingLogId); // TODO: カスタムログは削除しなくていいのか？
				contentObjectLogDao.deleteContentObjectLog(sendErrorLog.contentId, sendErrorLog.readingLogId);
				contentReadingLogDao.deleteContentReadingLog(sendErrorLog);
			}
		}
	}

	/**
	 * コンテンツダ一覧開始。
	 * @author Minhyuk Seok
	 * @version 1.1.1
	 * @throws Exception 
	 */
	public synchronized int startContentReadLog(long contentId) {
		ContentReadingLogDto dto;
		dto = contentReadingLogDao.getContentReadingLog(contentId);

		if (dto != null) {
			if(dto.status != ContentReadingStatus.reading.type()){
				dto.status = ContentReadingStatus.reading.type();
				dto.resumeDate = DateTimeUtil.getCurrentDate();
				contentReadingLogDao.updateContentReadingLog(dto);
			}
		} else {
			dto = new ContentReadingLogDto();
			dto.readingLogId = contentReadingLogDao.getNewContentReadingLogId();
			dto.contentId = contentId;
			dto.startDate = DateTimeUtil.getCurrentDate();
			dto.resumeDate = DateTimeUtil.getCurrentDate();
			dto.duration = 0;
			dto.mode = ReadingLogMode.DEFAULT;
			dto.status = ContentReadingStatus.reading.type();
			contentReadingLogDao.insertContentReadingLog(dto);
		}

		return dto.readingLogId;
	}

	/**
	 * コンテンツダ一覧のバッググラウンド。
	 * @author Minhyuk Seok
	 * @version 1.1.1
	 */
	public void pauseContentReadLog(long contentId) {
		ContentReadingLogDto dto = contentReadingLogDao.getContentReadingLog(contentId);
		if (dto == null) {
			Logger.e(TAG, "ContentReadingLogDto not found. contentId=" + contentId);
			return;
		}
		//バッググラウンド
		dto.status = ContentReadingStatus.suspend.type();
		dto.endDate = DateTimeUtil.getCurrentDate();
		// longで計算してからintにする
		long durationMilliSecond = DateTimeUtil.getCurrentDate().getTime() - dto.resumeDate.getTime();
		//ミリ秒から秒に変換（小数点以下切り捨て）
		dto.duration = dto.duration + (int)(durationMilliSecond / 1000L);

		contentReadingLogDao.updateContentReadingLog(dto);
		if (dto.status == ContentReadingStatus.readed.type()) {
			batchSendReadingLog();
		}
	}

	/**
	 * コンテンツダ一覧終了。
	 * @author Minhyuk Seok
	 * @version 1.1.1
	 * @throws NetworkDisconnectedException 
	 */
	public void endContentReadLog(long contentId) {
		ContentReadingLogDto dto = contentReadingLogDao.getContentReadingLog(contentId);
		if (dto != null) {
			//読み終わり
			dto.status = ContentReadingStatus.readed.type();
			dto.endDate = DateTimeUtil.getCurrentDate();
			// longで計算してからintにする
			long durationMilliSecond = DateTimeUtil.getCurrentDate().getTime() - dto.resumeDate.getTime();
			//ミリ秒から秒に変換（小数点以下切り捨て）
			dto.duration = dto.duration + (int)(durationMilliSecond / 1000L);
			contentReadingLogDao.updateContentReadingLog(dto);

			// 送信できてない閲覧ログがあった場合、まとめて1件ずつ送信する
			batchSendReadingLog();
		}
	}

	/**
	 * 未送信閲覧ログの一括送信
	 */
	public synchronized void batchSendReadingLog() {
		List<ContentReadingLogDto> list = contentReadingLogDao.getContentReadLogs();

		try {
			for (ContentReadingLogDto logDto : list) {
				if (networkAdapter.isNetworkConnected() && ContentReadingStatus.readed.type() == logDto.status) {
					//ネットワークに接続
					AcmsClient acms = AcmsClient.getInstance(cache.getUrlPath(), networkAdapter);
					Timestamp StartDate = new Timestamp(logDto.startDate.getTime());
					Timestamp EndDate = new Timestamp(logDto.endDate.getTime());
					ContentReadingLogParameters logParam =
							new ContentReadingLogParameters(cache.getMemberInfo().sid,
									logDto.contentId,
									StartDate,
									EndDate,
									logDto.duration,
									ABVEnvironment.DeviceTypeId,
									logDto.latitude,
									logDto.longitude,
									logDto.mode,
									contentPageReadingLogLogic.getContentPageReadLogJson(logDto.contentId, logDto.readingLogId),
									contentObjectLogLogic.getContentObjectLogJson(logDto.contentId, logDto.readingLogId));
					boolean sendResult;
					try {
						sendResult = acms.contentReadingLog(logParam);
					} catch (AcmsException e) {
						sendResult = false;
						Logger.e(TAG, "Error failed sent content read log.");
					}

					if (sendResult) {
						// 送信完了したログは全て削除
						contentPageReadingLogDao.deleteContentPageReadingLog(logDto.contentId, logDto.readingLogId);
						contentObjectLogDao.deleteContentObjectLog(logDto.contentId, logDto.readingLogId);
						boolean result = contentReadingLogDao.deleteContentReadingLog(logDto);
						if (result) {
							Logger.i(TAG, "sent ContentReadingLog:%s", logDto.contentId);
						}
					} else {
						// 送信エラー
						logDto.status = ContentReadingStatus.sendError.type();
						contentReadingLogDao.updateContentReadingLog(logDto);
					}
				}
			}
		} catch (NetworkDisconnectedException e) {
			// ネットワークエラーは何もしない
		}
	}
	
	/**
	 * 位置情報更新
	 * 
	 * @param contentId
	 * @param latitude
	 * @param longitude
	 */
	public void updateLocationContentReadLog(long contentId, double latitude, double longitude) {
		ContentReadingLogDto dto = contentReadingLogDao.getContentReadingLog(contentId);
		if (dto != null) {
			// 小数第7位を四捨五入
			BigDecimal bigDecimalLatitude = new BigDecimal(latitude);
			dto.latitude = bigDecimalLatitude.setScale(6, BigDecimal.ROUND_HALF_UP).doubleValue();
			BigDecimal bigDecimalLongitude = new BigDecimal(longitude);
			dto.longitude = bigDecimalLongitude.setScale(6, BigDecimal.ROUND_HALF_UP).doubleValue();
			contentReadingLogDao.updateContentReadingLog(dto);
		}
	}
}
