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

import java.util.ArrayList;
import java.util.List;

import jp.agentec.abook.abv.bl.acms.client.AcmsClient;
import jp.agentec.abook.abv.bl.acms.client.json.CategoriesJSON;
import jp.agentec.abook.abv.bl.acms.client.parameters.AcmsParameters;
import jp.agentec.abook.abv.bl.acms.client.parameters.CategoriesParameters;
import jp.agentec.abook.abv.bl.common.exception.ABVException;
import jp.agentec.abook.abv.bl.data.dao.AbstractDao;
import jp.agentec.abook.abv.bl.data.dao.CategoryDao;
import jp.agentec.abook.abv.bl.data.dao.MemberInfoDao;
import jp.agentec.abook.abv.bl.dto.CategoryDto;
import jp.agentec.adf.util.StringUtil;

public class CategoryLogic extends AbstractLogic {
	private CategoryDao categoryDao = AbstractDao.getDao(CategoryDao.class);

	/**
	 * ジャンル情報をサーバから受信し、ローカルに保存します。既存のデータは上書きされます。また、サーバにないジャンルがローカルにある場合、そのジャンルは削除されます。
	 * @throws ABVException　キャッシュにユーザ情報がありません。再度ログインする必要があります。
	 * @throws Exception その他、例外です。
	 * @since 1.0.0
	 */
	public void initializeCategories() throws Exception {
		MemberInfoDao memberInfoDao = AbstractDao.getDao(MemberInfoDao.class);
		AcmsParameters param;
		String lastUpdateDate = memberInfoDao.getLastUpdateInfor();
		param = new CategoriesParameters(cache.getMemberInfo().sid, lastUpdateDate);
		CategoriesJSON json = AcmsClient.getInstance(cache.getUrlPath(), networkAdapter).category(param);
        if (lastUpdateDate == null) {
            initializeCategories(json);
        } else {
            initializeCategories(json, lastUpdateDate);
        }
		//cache.refreshCategory(dao.getCategories(CategoryDto.class));
	}

	private void initializeCategories(CategoriesJSON json, String lastUpdate) throws Exception {
		//ジャンルの更新情報がない場合取得日時保存するだけ
		if ((json.categoryList == null || (json.categoryList.isEmpty() && json.dellCategoryList == null || json.dellCategoryList.isEmpty()))) {
			updateLastUpdateDate(json.updateDate);
			return;
		}
		try {
			categoryDao.beginTransaction();

			if (json.categoryList != null && !json.categoryList.isEmpty()) {
				for (CategoryDto dto: json.categoryList) {
					//	未指定ジャンルIDをキャッシュに入れておく
					if (dto.dispOrder == -1) {
						cache.refreshDefaultCategoryId(dto.categoryId);
					}

					//lastUpdateの情報がないということはデータベースにジャンルデータがないのでジャンルが存在するかどうかのチェックは不要
					if (StringUtil.isNullOrEmpty(lastUpdate)) {
						categoryDao.insertCategory(dto.categoryId, dto.parentCategoryId, dto.dispOrder, dto.categoryName);
					} else {
						CategoryDto categoryDto = categoryDao.getCategory(dto.categoryId);
						if (categoryDto == null) {
							categoryDao.insertCategory(dto.categoryId, dto.parentCategoryId, dto.dispOrder, dto.categoryName);
						} else {
							categoryDao.updateCategory(dto.categoryId, dto.parentCategoryId, dto.dispOrder, dto.categoryName, categoryDto.parentCategoryId);
						}
					}
					//	category_pathを新たに作り直す。
					categoryDao.regenerateCategoryPath();
				}
			}

			if (json.dellCategoryList != null && !json.dellCategoryList.isEmpty()) {
				int size = json.dellCategoryList.size();
				for (int i = 0; i < size; i++) {
					CategoryDto dto = categoryDao.getCategory(json.dellCategoryList.get(i));
					if (dto != null) {
						categoryDao.deleteCategory(dto, cache.getDefaultCategoryId());
					}
				}
			}
			updateLastUpdateDate(json.updateDate);
			categoryDao.commit();
		} catch (Exception e) {
			categoryDao.rollback();
			throw e;
		}
	}

    /**
     * ジャンル情報をサーバから受信し、ローカルに保存します。既存のデータは上書きされます。また、サーバにないジャンルがローカルにある場合、そのジャンルは削除されます。
     * ※1.8.1から追加されたlastUpdateの下位互換性のため、既存のメソッドを復活
     * @throws Exception その他、例外です。
     * @since 1.0.0
     */
    private void initializeCategories(CategoriesJSON json) throws Exception {
        List<CategoryDto> serverCategories = json.categoryList;
        if (serverCategories != null && serverCategories.size() > 0) {
            try {
                categoryDao.beginTransaction();

                List<CategoryDto> localCategories = categoryDao.getAllCategories();
                //List<GroupDto> localGroups = dao.getAllGroups(GroupDto.class);

                for (CategoryDto serverDto : serverCategories) {
                    boolean exist = false;

                    //	未指定ジャンルIDをキャッシュに入れておく
                    if (serverDto.dispOrder == -1) {
                        cache.refreshDefaultCategoryId(serverDto.categoryId);
                    }

                    if (localCategories != null) {
                        for (CategoryDto localDto : localCategories) {
                            exist = serverDto.equals(localDto);

                            if (exist) {
                                //	update
                                categoryDao.updateCategory(serverDto.categoryId, serverDto.parentCategoryId, serverDto.dispOrder, serverDto.categoryName, localDto.parentCategoryId);

                                //	更新したグループはローカルのリストから外しておく。
                                localCategories.remove(localDto);
                                break;
                            }
                        }
                    }

                    if (!exist) {
                        //	insert
                        categoryDao.insertCategory(serverDto.categoryId, serverDto.parentCategoryId, serverDto.dispOrder, serverDto.categoryName);
                    }
                }

                //	category_pathを新たに作り直す。
                categoryDao.regenerateCategoryPath();

                for (CategoryDto serverDto : serverCategories) {
                    categoryDao.updateCategory(serverDto.categoryId, serverDto.parentCategoryId, serverDto.dispOrder, serverDto.categoryName, serverDto.parentCategoryId);
                }

                if (localCategories != null) {
                    for (CategoryDto localDto : localCategories) {
                        //	delete
                        categoryDao.deleteCategory(localDto, cache.getDefaultCategoryId());
                    }
                }

                categoryDao.commit();
            } catch (Exception e) {
                categoryDao.rollback();
                throw e;
            } finally {
            }
        }

        //cache.refreshCategory(dao.getCategories(CategoryDto.class));
    }

	private void updateLastUpdateDate(String lastUpdateDate) {
		MemberInfoDao memberInfoDao = AbstractDao.getDao(MemberInfoDao.class);
		memberInfoDao.updateLastUpdateInfor(lastUpdateDate);
	}

}
