/*
 * 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.AvzMPositionPosition;
import com.aimluck.eip.cayenne.om.account.EipMPosition;
import com.aimluck.eip.cayenne.om.security.TurbineUserGroupRole;
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 PositionImporter {
  /** ロガー */
  private static final JetspeedLogger logger =
    JetspeedLogFactoryService.getLogger(PositionImporter.class.getName());

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

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

  /**
   * 役職情報インポート
   * <p>
   * 役職情報のファイルを読み込み、Aipoのデータベースにインポートします。<br>
   * 
   * @param dataContext
   * 
   * @return boolean True(処理成功)、False(処理失敗)
   * @exception DBエラー
   *                、ファイルなし 、データ件数エラーの際に発生
   */
  public boolean importPosition(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
          + POSITION_FILE_NAME); // データファイル
      if (!csvFile.exists()) {
        throw new FileNotFoundException();
      }

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

      List<EipMPosition> positionList = new ArrayList<EipMPosition>();
      List<String> positionAddedList = new ArrayList<String>(); // 処理済みの役職コード格納配列

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

        logger.debug("position code -> " + positionCode + ".");

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

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

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

        EipMPosition position = null;
        // <役職情報>件数が1件の場合
        if (resultList.size() == 1) {
          // 役職情報を更新する。
          position = resultList.get(0);
          logger.debug("position -> "
            + position.getPositionId()
            + " update start.");
          position.setPositionName(positionName);
          position.setUpdateDate(new Date());

          dataContext.commitChanges();
          // 更新件数をインクリメントする。
          updateCounter++;
        }

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

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

          position = new EipMPosition();
          position = Database.create(EipMPosition.class);
          position.setPositionName(positionName);
          position.setCreateDate(new Date());
          position.setUpdateDate(new Date());
          position.setPositionCode(positionCode);

          dataContext.commitChanges();

          // 役職順位情報に登録
          List<AvzMPositionPosition> posposlist =
            Database.query(AvzMPositionPosition.class).fetchList();
          int new_pos =
            (posposlist != null && posposlist.size() > 0)
              ? posposlist.size() + 1
              : 1;
          AvzMPositionPosition positionPosition =
            Database.create(AvzMPositionPosition.class);
          positionPosition.setToEipMPosition(position);
          positionPosition.setPosition(Integer.valueOf(new_pos));
          logger.debug("position position inserted -> " + new_pos + ".");

          dataContext.commitChanges();
          // 登録件数をインクリメントする。
          insertCounter++;
        }

        // 処理済みの役職コード格納配列に保持
        positionAddedList.add(positionCode);

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

      }

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

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

      // 全レコードに対して判定
      for (Iterator<EipMPosition> dbPosition = delList.iterator(); dbPosition
        .hasNext();) {
        EipMPosition pos = dbPosition.next();
        for (EipMPosition filePosition : positionList) {
          // 役職コードが一致したら削除リストから削除
          if (filePosition.getPositionId() == pos.getPositionId()) {
            dbPosition.remove();
            break;
          }
        }
      }
      // 削除リストの役職を削除
      for (EipMPosition delPosition : delList) {
        AvzMPositionPosition delPositionPosition = new AvzMPositionPosition();
        // 役職表示順位を削除
        delPositionPosition.setToEipMPosition(delPosition);
        Database.delete(delPositionPosition);
        // 役職を削除
        Database.delete(delPosition);

        // ユーザーグループロールの役職をnullで更新
        SelectQuery<TurbineUserGroupRole> userGroupRoleQuery =
          Database.query(TurbineUserGroupRole.class);
        Expression exp =
          ExpressionFactory.matchExp(
            TurbineUserGroupRole.EIP_MPOSITION_PROPERTY,
            delPosition);
        userGroupRoleQuery.setQualifier(exp);

        List<TurbineUserGroupRole> userGroupRoleList =
          userGroupRoleQuery.fetchList();
        for (TurbineUserGroupRole userGroupRole : userGroupRoleList) {
          userGroupRole.setEipMPosition(null);
        }
        logger
          .debug("position deleted -> " + delPosition.getPositionId() + ".");

        // 削除件数をインクリメントする。
        deleteCounter++;
      }
      dataContext.commitChanges();

      // 表示順位の更新
      // 役職表示順位情報の一覧を取得
      SelectQuery<AvzMPositionPosition> posposQuery =
        Database.query(AvzMPositionPosition.class);
      posposQuery.orderAscending(AvzMPositionPosition.POSITION_PROPERTY);
      List<AvzMPositionPosition> posposList = posposQuery.fetchList();
      int counter = 1;
      for (AvzMPositionPosition pospos : posposList) {
        pospos.setPosition(counter);
        counter++;
      }
      dataContext.commitChanges();
      logger.debug("position position updated.");

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

      // 終了メッセージ
      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;
  }
}
