package com.aimluck.eip.libdocument.util;

import java.io.File;
import java.util.ArrayList;
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.cayenne.query.SelectQuery;
import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
import org.apache.jetspeed.services.logging.JetspeedLogger;
import org.apache.jetspeed.services.resources.JetspeedResources;
import org.apache.turbine.services.TurbineServices;
import org.apache.turbine.util.RunData;

import com.aimluck.eip.cayenne.om.portlet.ImwTDocumentFile;
import com.aimluck.eip.cayenne.om.portlet.ImwTDocumentFileMap;
import com.aimluck.eip.cayenne.om.portlet.ImwTDocumentRelationMap;
import com.aimluck.eip.orm.DatabaseOrmService;
import com.aimluck.eip.services.accessctl.ALAccessControlConstants;
import com.aimluck.eip.services.accessctl.ALAccessControlFactoryService;
import com.aimluck.eip.services.accessctl.ALAccessControlHandler;
import com.aimluck.eip.services.eventlog.ALEventlogConstants;
import com.aimluck.eip.services.eventlog.ALEventlogFactoryService;
import com.aimluck.eip.util.ALEipUtils;
import com.aimluck.eip.util.orgutils.ALOrgUtilsFactoryService;
import com.aimluck.eip.util.orgutils.ALOrgUtilsHandler;

public class LibDocumentUtils {
  
  /** logger */
  private static final JetspeedLogger logger = JetspeedLogFactoryService
      .getLogger(LibDocumentUtils.class.getName());

  /** 文書を保管するディレクトリのカテゴリキーの指定 */
  protected static final String CATEGORY_KEY = JetspeedResources.getString(
      "aipo.document.categorykey", "");
  
  /** 文書を保管するディレクトリの指定 */
  private static final String FOLDER_FILEDIR_DOCUMENT = JetspeedResources
      .getString("aipo.filedir", "");
  
  /**
   * 文書ファイルテーブルと文書ファイルマップテーブルと文書ファイル関連マップのレコードを削除します。(コミットはしません） <BR>
   * requestStatus = 1 のとき、　申請中のデータのみ削除します。<BR>
   * requestStatus = null のとき、文書IDが一致する全てのレコードを削除します。<BR>
   * @param dataContext
   * @param 文書ファイルオブジェクト
   * @param 申請状態
   * @return　成否
   */
  public static boolean deleteDocument(DataContext dataContext,
      ImwTDocumentFile file, Integer requestStatus) {
    try {
      if (file == null) {
        dataContext.rollbackChanges();
        return false;
      }

      //文書ファイルマップIDの取得
      String relFileId = file.getDocId().toString();

      //文書ファイル
      Expression expressionFile;
      if (requestStatus == null) {
        expressionFile = ExpressionFactory.matchExp(
            ImwTDocumentFile.DOC_ID_PROPERTY, file.getDocId());
      } else {
        expressionFile = ExpressionFactory.matchDbExp(
          ImwTDocumentFile.FILE_ID_PK_COLUMN, file.getFileId());
      }
      //文書ファイルマップ
      Expression expressionFileMap = ExpressionFactory.matchExp(
          ImwTDocumentFileMap.DOC_ID_PROPERTY, relFileId);
          //.andExp(ExpressionFactory.matchExp(
            //  ImwTDocumentFileMap.REQUEST_STATUS_PROPERTY,1));
      //文書ファイル関連マップ
      Expression expressionRelationMap = ExpressionFactory.matchExp(
          ImwTDocumentRelationMap.DOC_ID_PROPERTY, relFileId);
          //.andExp(ExpressionFactory.matchExp(
            //  ImwTDocumentRelationMap.REQUEST_STATUS_PROPERTY,1));;

      SelectQuery queryFile = new SelectQuery(ImwTDocumentFile.class);
      SelectQuery queryFileMap = new SelectQuery(ImwTDocumentFileMap.class);
      SelectQuery queryRelationMap = new SelectQuery(
          ImwTDocumentRelationMap.class);

      queryFile.setQualifier(expressionFile);
      queryFileMap.setQualifier(expressionFileMap);
      queryRelationMap.setQualifier(expressionRelationMap);

      //申請状態
      if (requestStatus != null) {
        Expression expressionFileMap2 = ExpressionFactory.matchExp(
            ImwTDocumentFileMap.REQUEST_STATUS_PROPERTY, requestStatus);
        Expression expressionRelationMap2 = ExpressionFactory.matchExp(
            ImwTDocumentRelationMap.REQUEST_STATUS_PROPERTY, requestStatus);

        queryFileMap.andQualifier(expressionFileMap2);
        queryRelationMap.andQualifier(expressionRelationMap2);
      }

      List listFile = dataContext.performQuery(queryFile);
      List listFileMap = dataContext.performQuery(queryFileMap);
      List listFileRelationMap = dataContext.performQuery(queryRelationMap);

      //文書ファイルマップ
      dataContext.deleteObjects(listFileMap);
      //関連文書ファイルマップ
      dataContext.deleteObjects(listFileRelationMap);
      //文書ファイル
      dataContext.deleteObjects(listFile);
    } catch (Exception ex) {
      dataContext.rollbackChanges();
      logger.error("Exception", ex);
      return false;
    }
    return true;
  }

  /**
   * 文書削除の後処理を行います。 <BR>
   *
   * @param ファイルID
   * @param ファイル名
   * @param ファイルパス
   * @param 組織ID
   * @param 関連マップのファイルパスのリスト
   * @return　成否
   */
  public static boolean deleteDocumentEnd(ImwTDocumentFile file, String org_id,
      List relation_file_path) {
    
    try {
      if (file == null) {
        return false;
      }

      // ファイルパスの取得
      String local_file_pass = file.getFilePath();
      //　ファイルIDの取得
      int entityId = file.getFileId();
      // ファイルタイトルの取得
      String fileName = file.getFileTitle();

      // イベントログに保存
      ALEventlogFactoryService.getInstance().getEventlogHandler().log(entityId,
          ALEventlogConstants.PORTLET_TYPE_DOCUMENT_FILE, fileName);

      if (local_file_pass != null && !"".equals(local_file_pass)) {
        // ローカルファイルに保存されているファイルを削除する．
        File local_file = null;
        local_file = new File(getSaveDirPath(org_id)
            + local_file_pass);
        if (local_file.exists()) {
          local_file.delete();
        }
      }
      if (relation_file_path != null && relation_file_path.size() > 0) {
        for (int i = 0; i < relation_file_path.size(); i++) {
          // ローカルファイルに保存されている関連文書を削除する．
          File local_file = null;
          local_file = new File(getSaveDirPath(org_id)
              + relation_file_path.get(i).toString());
          if (local_file.exists()) {
            local_file.delete();
          }
        }
      }
    } catch (Exception ex) {
      logger.error("Exception", ex);
      return false;
    }
    return true;
  }
  
  /**
   * 文書削除の後処理を行います。 <BR>
   * @param file
   * @param org_id
   * @param local_file_path
   * @param relation_file_path
   * @return
   */
  public static boolean deleteDocumentEnd(ImwTDocumentFile file, String org_id,
      List local_file_path ,List relation_file_path) {
    try {
      if (file == null) {
        return false;
      }
      
      //　ファイルIDの取得
      int entityId = file.getFileId();
      // ファイルタイトルの取得
      String fileName = file.getFileTitle();

      // イベントログに保存
      ALEventlogFactoryService.getInstance().getEventlogHandler().log(entityId,
          ALEventlogConstants.PORTLET_TYPE_DOCUMENT_FILE, fileName);

      // ファイルの削除
      if (local_file_path != null && !"".equals(local_file_path)) {        
        for (Object obj : local_file_path) {
          String path = (String)obj;
          // ローカルファイルに保存されているファイルを削除する．
          File local_file = null;
          local_file = new File(getSaveDirPath(org_id) + path);
          if (local_file.exists()) {
            local_file.delete();
          }
        }
      }
      
      // 関連文書の削除
      if (relation_file_path != null && relation_file_path.size() > 0) {
        for (int i = 0; i < relation_file_path.size(); i++) {
          // ローカルファイルに保存されている関連文書を削除する．
          File local_file = null;
          local_file = new File(getSaveDirPath(org_id)
              + relation_file_path.get(i).toString());
          if (local_file.exists()) {
            local_file.delete();
          }
        }
      }
    } catch (Exception ex) {
      logger.error("Exception", ex);
      return false;
    }
    return true;
  }

  /**
   * ユーザ毎のルート保存先（絶対パス）を取得します。
   *
   * @param uid
   * @return
   */
  public static String getSaveDirPath(String orgId) {
    ALOrgUtilsHandler handler = ALOrgUtilsFactoryService.getInstance()
        .getOrgUtilsHandler();
    File path = handler.getDocumentPath(FOLDER_FILEDIR_DOCUMENT, orgId,
        CATEGORY_KEY);
    if (!path.exists()) {
      path.mkdirs();
    }
    return path.getAbsolutePath();
  }
  
  /**
   * 文書IDよりファイルオブジェクトモデルを取得します。 <BR>
   *
   * @param rundata
   * @param context
   * @return
   */
  public static ArrayList getDocFilePathList(Integer docId) {
    try {
      if (docId==null){
        return null;
      }
      ArrayList filePaths = new ArrayList();
      filePaths.clear();
      DataContext dataContext = DatabaseOrmService.getInstance()
          .getDataContext();
      SelectQuery query = new SelectQuery(ImwTDocumentFile.class);
      Expression exp = ExpressionFactory.matchExp(
          ImwTDocumentFile.DOC_ID_PROPERTY, docId);
      query.setQualifier(exp);
      List files = dataContext.performQuery(query);
      if (files == null || files.size() == 0) {
        //return null;
        return filePaths;
      } else {
        for (Object obj:files){
          ImwTDocumentFile file = (ImwTDocumentFile)obj;
          if (file.getFilePath()!=null){
            filePaths.add(file.getFilePath());
          }
        }
        return filePaths;
      }
    } catch (Exception ex) {
      logger.error("Exception", ex);
      return null;
    }
  }  
  
  /**
   * 関連マップのファイルパスを取得します。 <BR>
   *
   * @param 文書ID
   * @param 申請状態
   * @return　関連マップのファイルパス
   */
  public static ArrayList getRelationFilePaths(Integer docId,
      Integer requestStatus) {

    try {
      if (docId == null || Integer.valueOf(docId) == null) {
        return null;
      }

      ArrayList paths = new ArrayList();
      paths.clear();

      DataContext dataContext = DatabaseOrmService.getInstance()
          .getDataContext();
      SelectQuery query = new SelectQuery(ImwTDocumentRelationMap.class);
      Expression exp = ExpressionFactory.matchExp(
          ImwTDocumentRelationMap.DOC_ID_PROPERTY, docId);
      query.setQualifier(exp);
      if (requestStatus != null) {
        Expression exp2 = ExpressionFactory.matchExp(
            ImwTDocumentRelationMap.REQUEST_STATUS_PROPERTY, requestStatus);
        query.andQualifier(exp2);
      }

      List files = dataContext.performQuery(query);
      if (files == null || files.size() == 0) {
        // 指定したファイル IDのレコードが見つからない場合
        logger.debug("[Document Relation Map] Not found Map ID...");
        //return null;
        return paths;
      } else {
        for (Object file : files) {
          paths.add(((ImwTDocumentRelationMap) file).getFilePath());
        }
      }

      return paths;
    } catch (Exception ex) {
      logger.error("Exception", ex);
      return null;
    }
  }
  
  /**
   * 文書ファイルマップテーブルと文書ファイル関連マップのレコードを削除します。(コミットはしません） <BR>
   *
   * @param dataContext
   * @param 文書ID
   * @param 申請状態
   * @return　true:成功　false:失敗
   */
  public static boolean deleteFileMap(DataContext dataContext, Integer docId,
      Integer requestStatus) {
    try {
      if (docId == null){
        dataContext.rollbackChanges();
        return false;
      }

      SelectQuery query = new SelectQuery(ImwTDocumentFileMap.class);
      Expression exp;
      Expression exp2;
      exp = ExpressionFactory.matchExp(ImwTDocumentFileMap.DOC_ID_PROPERTY,
          docId);
      query.setQualifier(exp);
      if (requestStatus != null) {
        exp2 = ExpressionFactory.matchExp(
            ImwTDocumentFileMap.REQUEST_STATUS_PROPERTY, requestStatus);
        query.andQualifier(exp2);
      }
      List filemaps = dataContext.performQuery(query);
      dataContext.deleteObjects(filemaps);

    } catch (Exception ex) {
      dataContext.rollbackChanges();
      logger.error("Exception", ex);
      return false;
    }
    return true;
  }
  
  /**
   * 現在有効な最新の文書オブジェクトを取得します。
   * @return　文書申請のデフォルトの申請経路オブジェクト
   */
  public static ImwTDocumentFile getLastDoc(DataContext dataContext, Integer docId){
    try {
      if (docId==null) {
        return null;
      }
      
      if (dataContext == null){
        dataContext = DatabaseOrmService.getInstance().getDataContext();
      }
      SelectQuery query = new SelectQuery(ImwTDocumentFile.class);
      Expression exp = ExpressionFactory.matchExp(
          ImwTDocumentFile.DOC_ID_PROPERTY, docId);
      Expression exp2 = ExpressionFactory.matchExp(
          ImwTDocumentFile.STATUS_PROPERTY, 0);
      Expression exp3 = ExpressionFactory.matchExp(
          ImwTDocumentFile.STATUS_PROPERTY, 1);
      query.setQualifier(exp);
      query.andQualifier(exp2.orExp(exp3));
      List records = dataContext.performQuery(query);
      
      if (records != null){
        ImwTDocumentFile file = (ImwTDocumentFile) records.get(0);
        return file;
      }
      return null;

    } catch (Exception ex){
      logger.error("Exception", ex);
      return null;
    }
  }
  
  public static ImwTDocumentFile getLastDoc(Integer docId){
    return getLastDoc(null, docId);
  }
  
  /**
   * ログインユーザが文書管理システム管理者かどうかを返します
   * @param rundata
   * @return
   */
  public static boolean isDocAdmin(RunData rundata) {
    // ログインユーザが文書管理システム管理者かどうか
    // フォルダの削除権限があるかどうかで判断する。
    ALAccessControlFactoryService aclservice = (ALAccessControlFactoryService) ((TurbineServices) TurbineServices
        .getInstance()).getService(ALAccessControlFactoryService.SERVICE_NAME);
    ALAccessControlHandler aclhandler = aclservice.getAccessControlHandler();
    boolean ret = aclhandler.hasAuthority((int) ALEipUtils
        .getALEipUser(rundata).getUserId().getValue(),
        ALAccessControlConstants.POERTLET_FEATURE_DOCUMENT_FOLDER,
        ALAccessControlConstants.VALUE_ACL_DELETE);
    return ret;
  }
}
