/*
 * Aipo is a groupware program developed by Aimluck,Inc.
 * Copyright (C) 2004-2011 Aimluck,Inc.
 * http://www.aipo.com
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package aipo.batch.userinfo;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import org.apache.cayenne.access.DataContext;
import org.apache.cayenne.exp.Expression;
import org.apache.cayenne.exp.ExpressionFactory;
import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
import org.apache.jetspeed.services.logging.JetspeedLogger;
import org.apache.jetspeed.services.resources.JetspeedResources;

import aipo.batch.utils.BatchUtils;

import com.aimluck.eip.cayenne.om.account.AvzMRole;
import com.aimluck.eip.common.ALEipManager;
import com.aimluck.eip.orm.Database;
import com.aimluck.eip.orm.query.SelectQuery;

/**
 * <HR>
 * <p>
 * 
 * 役割情報のファイルを読み込み、Aipoのデータベースにインポートします。<br>
 * <P>
 * <HR>
 * <P>
 */
public class RoleImporter {

  /** ロガー */
  private static final JetspeedLogger logger =
    JetspeedLogFactoryService.getLogger(RoleImporter.class.getName());

  /** プロパティファイル */
  private static final String PROPERTY_FILE =
    JetspeedResources.getString("aipo.conf", "")
      + File.separator
      + "Batch.properties";

  /** 役割ファイル名 */
  private static final String ROLE_FILE_NAME =
    (String) BatchUtils.getProperties(PROPERTY_FILE).get(
      "import.role.file.name");

  /**
   * 役割情報インポート
   * <p>
   * 役割情報のファイルを読み込み、Aipoのデータベースにインポートします。<br>
   * 
   * @param dataContext
   * 
   * @return boolean True(処理成功)、False(処理失敗)
   * @exception DBエラー
   *                、ファイルなし 、データ件数エラーの際に発生
   */
  public boolean importRole(DataContext dataContext) throws Exception {

    int updateCounter = 0;
    int insertCounter = 0;
    int deleteCounter = 0;
    BufferedReader reader = null;

    try {
      // 開始メッセージをログに出力
      logger.info("役割情報更新開始");

      // CSVデータファイル
      File csvFile =
        new File(BatchUtils.IMPORT_CSV_FILE_PATH
          + File.separator
          + ROLE_FILE_NAME); // データファイル
      if (!csvFile.exists()) {
        throw new FileNotFoundException();
      }

      List<AvzMRole> roleList = new ArrayList<AvzMRole>();
      List<String> roleAddedList = new ArrayList<String>(); // 処理済みの役割コード格納配列

      reader =
        new BufferedReader(new InputStreamReader(
          new FileInputStream(csvFile),
          BatchUtils.FILE_ENCODING));

      // 最終行まで読み込む
      String line = "";
      while ((line = reader.readLine()) != null) {
        String[] s = line.split(BatchUtils.SEPARATOR);
        String roleCode = BatchUtils.trimDoubleQuotes(s[0]); // 役割コード
        String roleName = BatchUtils.trimDoubleQuotes(s[1]); // 役割名

        logger.debug("role code -> " + roleCode + ".");

        // 処理済み役割コードに存在するか判定
        // 存在する場合はコード重複エラーとしてロールバック
        if (roleAddedList.contains(roleCode)) {
          throw new Exception("役割コードが重複しています。役割コード：[" + roleCode + "]");
        }

        // 役割コードで役割情報を検索する
        SelectQuery<AvzMRole> query = Database.query(AvzMRole.class);
        // 検索条件：役割コードと一致
        Expression exp =
          ExpressionFactory.matchExp(AvzMRole.ROLE_CODE_PROPERTY, roleCode);
        query.setQualifier(exp); // 検索実行
        List<AvzMRole> resultList = query.fetchList();

        // <役割情報>件数が2件以上の場合、例外を発生させる。
        if (resultList.size() >= 2) {
          throw new Exception("役割コードに一致する役割情報が2件以上見つかりました。役割コード：["
            + roleCode
            + "]");
        }

        AvzMRole role = null;
        // <役割情報>件数が1件の場合
        if (resultList.size() == 1) {
          // 役割情報を更新する。
          role = resultList.get(0);
          logger.debug("role -> " + role.getRoleId() + " update start.");
          role.setRoleName(roleName);
          role.setUpdateDate(new Date());
          dataContext.commitChanges();
          // 更新件数をインクリメントする。
          updateCounter++;
        }

        // <役割情報>件数が0件の場合
        if (resultList.size() == 0) {
          logger.debug("role code -> " + roleCode + " insert start.");

          // 役割名の重複チェック
          // if (BatchUtils.getAvzMRoleCount(roleName) > 0) {
          // throw new Exception("役割名がすでに登録されています。役割名：[" + roleName + "]");
          // }

          role = new AvzMRole();
          role = Database.create(AvzMRole.class);
          role.setRoleName(roleName);
          role.setCreateDate(new Date());
          role.setUpdateDate(new Date());
          role.setRoleCode(roleCode);
          dataContext.commitChanges();
          // 登録件数をインクリメントする。
          insertCounter++;
        }

        // 処理済みの役割コード格納配列に保持
        roleAddedList.add(roleCode);

        // <役割情報レコード>を<役割情報ファイル配列>に追加で格納する。
        roleList.add(role);
      }

      // 役割情報ファイルをクローズする。
      reader.close();
      reader = null;

      logger.debug("role delete start.");
      // 役割情報の全レコードを抽出する。
      SelectQuery<AvzMRole> roleQuery = Database.query(AvzMRole.class);
      roleQuery.orderAscending(AvzMRole.ROLE_CODE_PROPERTY);
      // 役割情報の削除用リスト
      List<AvzMRole> delList = roleQuery.fetchList();

      // 全レコードに対して判定
      for (Iterator<AvzMRole> dbRole = delList.iterator(); dbRole.hasNext();) {
        AvzMRole role = dbRole.next();
        for (AvzMRole fileRole : roleList) {
          // 役割コードが一致したら削除リストから削除
          if (fileRole.getRoleId() == role.getRoleId()) {
            dbRole.remove();
            break;
          }
        }
      }
      // 削除リストの役割を削除
      for (AvzMRole delRole : delList) {
        logger.debug("role deleted -> " + delRole.getRoleId() + ".");
        Database.delete(delRole);
        deleteCounter++;
      }
      dataContext.commitChanges();

      // singletonオブジェクトのリフレッシュ
      ALEipManager.getInstance().reloadRole();

      // 終了メッセージ
      logger.info("役割情報更新完了　登録件数：["
        + insertCounter
        + "]　更新件数：["
        + updateCounter
        + "]　削除件数：["
        + deleteCounter
        + "]");

    } catch (FileNotFoundException e) {
      logger.warn("役割情報ファイルが存在しません。");
    } catch (Exception e) {
      try {
        if (reader != null) {
          // 役割情報ファイルをクローズする。
          reader.close();
        }
      } catch (Exception ex) {
      }
      logger.error("役割情報の更新に失敗しました。", e);
      return false;
    }
    return true;
  }
}
