/*
 * Aipo is a groupware program developed by Aimluck,Inc.
 * http://aipostyle.com/
 *
 * Copyright(C) 2012 avanza Co.,Ltd. All rights reserved.
 * http://www.avnz.co.jp/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package com.aimluck.eip.fileupload;

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

import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
import org.apache.jetspeed.services.logging.JetspeedLogger;
import org.apache.turbine.services.upload.TurbineUpload;
import org.apache.turbine.util.ParameterParser;
import org.apache.turbine.util.RunData;
import org.apache.turbine.util.upload.FileItem;
import org.apache.velocity.context.Context;

import com.aimluck.eip.common.ALAbstractFormData;
import com.aimluck.eip.common.ALDBErrorException;
import com.aimluck.eip.common.ALPageNotFoundException;
import com.aimluck.eip.common.ALPermissionException;
import com.aimluck.eip.fileupload.beans.FileuploadBean;
import com.aimluck.eip.fileupload.util.FileuploadUtils;
import com.aimluck.eip.services.accessctl.ALAccessControlConstants;
import com.aimluck.eip.services.storage.ALStorageService;
import com.aimluck.eip.util.ALEipUtils;

/**
 * 複数添付ファイルアップロード処理 <br />
 * 
 */
public class MultiFileUploadFormData extends ALAbstractFormData {

  private static final JetspeedLogger logger = JetspeedLogFactoryService.getLogger(MultiFileUploadFormData.class.getName());

  /** POSTされたアップロードファイル名 */
  public static final String UPLOAD_POST_NAME = FileuploadFormData.KEY_ATTACHMENT_ID;

  /** ログインユーザ ID */
  private int userId = -1;

  /** アップロード先フォルダ名 */
  private String folderName = null;

  /** アップロードファイル */
  private FileItem[] uploadFileList = null;

  /** 現在のアップロードファイル数 */
  private int nowSize = 0;

  /** アップロード可能数 */
  private int maxSize = 0;

  /**
   * フィールドを初期化する。
   * 
   * @param rundata
   *          実行データ
   * @param context
   *          コンテキスト
   * @param msgList
   *          エラーメッセージのリスト
   * @return 正常終了の場合true、そうでない場合false
   */
  public void init(RunData rundata, Context context, List<String> msgList) throws ALPageNotFoundException, ALDBErrorException {
    userId = ALEipUtils.getUserId(rundata);

    folderName = rundata.getParameters().getString(FileuploadUtils.KEY_FILEUPLOAD_FODLER_NAME);
    if (folderName == null || "".equals(folderName)) {
      folderName = "0_" + String.valueOf(System.nanoTime());
    }
  }

  /**
   * リクエスト元フォームのデータを取得し、フィールドへ設定する。
   * 
   * @param rundata
   *          実行データ
   * @param context
   *          コンテキスト
   * @param msgList
   *          エラーメッセージのリスト（使用しない）
   * @return 必ずtrue
   */
  @Override
  public boolean setFormData(RunData rundata, Context context, List<String> msgList) throws ALPageNotFoundException, ALDBErrorException {

    // アップロードファイルの取得
    ParameterParser parser = rundata.getParameters();
    uploadFileList = parser.getFileItems(UPLOAD_POST_NAME);

    // 現在の添付ファイル数
    nowSize = parser.getInt(FileuploadUtils.KEY_NOW_SIZE, 0);
    // 添付可能数
    maxSize = parser.getInt(FileuploadUtils.KEY_MAX_SIZE, 0);

    return true;
  }

  /**
   * 1ファイル毎の入力チェック
   * 
   * @param uploadFile
   *          アップロードファイル
   * @param msgList
   *          エラーメッセージ
   * @return 正常な場合true、そうでない場合false
   * @throws ALPageNotFoundException
   *           発生しない
   * @throws ALDBErrorException
   *           発生しない
   */
  protected boolean validate(FileItem uploadFile, List<String> msgList) throws ALPageNotFoundException, ALDBErrorException {

    int maxFileSize = TurbineUpload.getSizeMax() / 1024 / 1024;

    // ファイル存在チェック
    if (uploadFile == null) {
      msgList.add("アップロードファイルが見つかりません。");
      return false;
    }

    // 0サイズチェック
    if (uploadFile.getSize() <= 0) {
      msgList.add("サイズが 0KB のファイルを追加することはできません。");
      return false;
    }

    final int FILE_SIZE_MAX = 7 * 1024 * 1024;
    int fileSize = (int) uploadFile.getSize();
    // 1ファイルのサイズチェック
    if (fileSize >= FILE_SIZE_MAX) {
      msgList.add("7MB以上のファイルは追加できません。");
      return false;
    }

    long fileSizeSum = ALStorageService.getTmpFolderSize(userId, folderName);
    fileSizeSum += uploadFile.getSize();
    // 全ファイルのサイズチェック
    if (fileSizeSum > TurbineUpload.getSizeMax()) {
      msgList.add("追加したファイルの全容量が " + maxFileSize + "MB よりも大きくなりました。これ以上、ファイルを追加することはできません。");
      return false;
    }

    // アップロード可能数のチェック
    if (maxSize > 0 && nowSize >= maxSize) {
      msgList.add("これ以上、ファイルを追加することはできません。");
    }

    return true;
  }

  /**
   * 1ファイルのアップロード処理
   * 
   * @param uploadFile
   *          アップロードファイル
   * @param rundata
   *          実行データ
   * @param context
   *          コンテキスト
   * @return アップロードファイル詳細情報Bean
   * @exception Exception
   *              ファイルアップロードに失敗した場合
   */
  protected FileuploadBean uploadFileData(FileItem uploadFile, RunData rundata, Context context) throws Exception {

    FileuploadBean filebean = new FileuploadBean();

    try {
      // ファイルID
      int fileId = Long.valueOf(System.nanoTime()).intValue();

      // 一時保存用ファイル名
      String newAttachmentFileName = String.valueOf(fileId);

      // 実ファイル名
      String realfilename = FileuploadUtils.getRealFileName(uploadFile.getName());

      // ファイル実サイズ(バイト)
      int fileSize = (int) uploadFile.getSize();

      // 表示用ファイルサイズ
      String dispFileSize = FileuploadUtils.getDispFileSize(fileSize);

      ALStorageService.createNewTmpFile(uploadFile.getInputStream(), userId, folderName, newAttachmentFileName, realfilename);

      filebean.setFolderName(folderName);
      filebean.setFileId(fileId);
      filebean.setFileName(realfilename + dispFileSize);
      filebean.setUploadResult(true);
    } catch (Exception e) {
      logger.error("1ファイルのアップロード中に例外が発生しました。", e);
      throw e;
    }
    return filebean;
  }

  /**
   * ファイルアップロード処理を実行します。
   * 
   * @param rundata
   *          実行データ
   * @param context
   *          コンテキスト
   * @return アップロードファイル情報一覧
   */
  public List<FileuploadBean> doUpload(RunData rundata, Context context) throws Exception {

    List<String> msgList = new ArrayList<String>(0);
    List<FileuploadBean> resultList = new ArrayList<FileuploadBean>(0);

    try {

      if (!doCheckSecurity(rundata, context)) {
        throw new Exception("セッションタイムアウトです。この画面を閉じてから再編集してください。");
      }

      init(rundata, context, msgList);

      doCheckAclPermission(rundata, context, ALAccessControlConstants.VALUE_ACL_UPDATE);

      setFormData(rundata, context, msgList);

      for (FileItem uploadFile : uploadFileList) {
        FileuploadBean bean = null;
        if (validate(uploadFile, msgList)) {
          // 入力値が正常の場合
          bean = uploadFileData(uploadFile, rundata, context);
        } else {
          // 入力エラーの場合
          bean = new FileuploadBean();
          bean.setFolderName(folderName);
          bean.setFileName(FileuploadUtils.getRealFileName(uploadFile.getName()));
          bean.setUploadResult(false);
          // エラーメッセージ設定
          String resutMsg = "";
          int index = 0;
          for (String msg : msgList) {
            if (index > 0) {
              resutMsg += ",";
            }
            resutMsg += msg;
            index++;
          }
          bean.setResultMessage(resutMsg);
        }
        resultList.add(bean);
      }

      return resultList;
    } catch (ALPermissionException e) {
      logger.error("権限例外が発生しました。", e);
      throw e;
    } catch (ALPageNotFoundException e) {
      logger.error("ページ例外が発生しました。", e);
      throw e;
    } catch (ALDBErrorException e) {
      logger.error("DB例外が発生しました。", e);
      throw e;
    }
  }

  /*
   * @see com.aimluck.eip.common.ALAbstractFormData#deleteFormData(RunData
   * rundata, Context context, List<String> msgList)
   */
  @Override
  protected boolean deleteFormData(RunData rundata, Context context, List<String> msgList) throws ALPageNotFoundException, ALDBErrorException {
    return false;
  }

  /*
   * @see com.aimluck.eip.common.ALAbstractFormData#insertFormData(RunData
   * rundata, Context context, List<String> msgList)
   */
  @Override
  protected boolean insertFormData(RunData rundata, Context context, List<String> msgList) throws ALPageNotFoundException, ALDBErrorException {
    return false;
  }

  /*
   * @see com.aimluck.eip.common.ALAbstractFormData#loadFormData(RunData
   * rundata, Context context, List<String> msgList)
   */
  @Override
  protected boolean loadFormData(RunData rundata, Context context, List<String> msgList) throws ALPageNotFoundException, ALDBErrorException {
    return false;
  }

  /*
   * @see com.aimluck.eip.common.ALAbstractFormData#setValidator()
   */
  @Override
  protected void setValidator() throws ALPageNotFoundException, ALDBErrorException {
  }

  /*
   * @see com.aimluck.eip.common.ALAbstractFormData#updateFormData(RunData
   * rundata, Context context, List<String> msgList)
   */
  @Override
  protected boolean updateFormData(RunData rundata, Context context, List<String> msgList) throws ALPageNotFoundException, ALDBErrorException {
    return false;
  }

  /*
   * @see com.aimluck.eip.common.ALAbstractFormData#validate(List<String>
   * msgList)
   */
  @Override
  protected boolean validate(List<String> msgList) throws ALPageNotFoundException, ALDBErrorException {
    return false;
  }

  /*
   * @see com.aimluck.eip.common.ALData#initField()
   */
  public void initField() {
  }

}
