/*
 * 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.Arrays;
import java.util.HashMap;
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.cayenne.om.account.AvzMUserRole;
import com.aimluck.eip.cayenne.om.security.TurbineUser;
import com.aimluck.eip.orm.Database;
import com.aimluck.eip.orm.query.SelectQuery;

/**
 * <HR>
 * <p>
 * 
 * 役割割当情報のファイルを読み込み、Aipoのデータベースにインポートします。<br>
 * インポート前にテーブルごとデータをクリアします。<br>
 * <P>
 * <HR>
 * <P>
 */
public class UserRoleImporter {

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

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

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

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

    int insertCounter = 0;
    BufferedReader reader = null;

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

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

      // 役割割当情報の全レコードを抽出し、削除する。
      SelectQuery<AvzMUserRole> userRoleQuery =
        Database.query(AvzMUserRole.class);
      userRoleQuery.orderAscending(AvzMUserRole.TO_AVZ_MROLE_PROPERTY);
      List<AvzMUserRole> delList = userRoleQuery.fetchList();

      for (AvzMUserRole delUserRole : delList) {
        // ユーザーIDがシステム用データのユーザーID（1,2,3）と一致する場合はスキップ
        if (Arrays.binarySearch(BatchUtils.SystemUserId, delUserRole
          .getUserId()
          .toString()) >= 0) {
          continue;
        }
        Database.delete(delUserRole);
        dataContext.commitChanges();
      }

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

      List<HashMap<String, String>> userRoleFileList =
        new ArrayList<HashMap<String, String>>();

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

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

        // 処理済み役割割当に存在するか判定
        // 存在する場合はコード重複としてスキップ
        HashMap<String, String> map = new HashMap<String, String>();
        map.put(loginId, roleCode);
        if (userRoleFileList.contains(map)) {
          logger.warn("[更新不可]処理済みの役割コード,ログインIDのためスキップします。　" + line);
          continue;
        }

        // ログインIDでユーザー情報を検索する
        SelectQuery<TurbineUser> userQuery = Database.query(TurbineUser.class);
        // 検索条件：ログイン名と一致
        Expression userExp =
          ExpressionFactory.matchExp(TurbineUser.LOGIN_NAME_PROPERTY, loginId);
        userQuery.setQualifier(userExp); // 検索実行
        TurbineUser user = userQuery.fetchSingle();

        // <ユーザー情報>件数が0件の場合、ログを出力し、次のレコードの処理を行う。
        if (user == null) {
          logger.warn("[更新不可]ユーザーが存在しません。　" + line);
          continue;
        }

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

        // <役割情報>件数が0件の場合、ログを出力し、次のレコードの処理を行う。
        if (roleList.size() == 0) {
          logger.warn("[更新不可]役割が存在しません。　" + line);
          continue;
        }

        logger.debug("user role -> "
          + loginId
          + ", code-> "
          + roleCode
          + " insert start.");

        // <役割割当情報>を登録する。
        AvzMUserRole userRole = Database.create(AvzMUserRole.class);
        userRole.setUserId(user.getUserId());
        userRole.setToAvzMRole(roleList.get(0));
        dataContext.commitChanges();

        // 登録件数をインクリメントする。
        insertCounter++;

        // 役割コード、ログインIDのマップを<役割割当ファイル配列>に追加で格納する。
        userRoleFileList.add(map);
      }

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

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

    } catch (FileNotFoundException e) {
      logger.warn("役割割当情報ファイルが存在しません。");
    } catch (Exception e) {
      try {
        if (reader != null) {
          // 役割割当情報ファイルをクローズする。
          reader.close();
        }
      } catch (Exception ex) {

      }
      logger.error("役割割当情報の更新に失敗しました。", e);
      return false;
    }
    return true;
  }
}
