/*
 * Aipo is a groupware program developed by Aimluck,Inc.
 * http://aipostyle.com/
 * 
 * Copyright(C) 2009 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.circulation;

import java.io.File;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

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.turbine.util.RunData;
import org.apache.velocity.context.Context;

import com.aimluck.commons.field.ALDateField;
import com.aimluck.commons.field.ALNumberField;
import com.aimluck.commons.field.ALStringField;
import com.aimluck.eip.cayenne.om.portlet.AvzTCirculationCategory;
import com.aimluck.eip.cayenne.om.portlet.AvzTCirculationFile;
import com.aimluck.eip.cayenne.om.portlet.AvzTCirculationRequest;
import com.aimluck.eip.cayenne.om.portlet.AvzTCirculationRequestMap;
import com.aimluck.eip.cayenne.om.portlet.auto._AvzTCirculationFile;
import com.aimluck.eip.cayenne.om.portlet.auto._AvzTCirculationRequest;
import com.aimluck.eip.cayenne.om.security.TurbineUser;
import com.aimluck.eip.cayenne.om.security.auto._TurbineUser;
import com.aimluck.eip.circulation.util.CirculationUtils;
import com.aimluck.eip.common.ALAbstractFormData;
import com.aimluck.eip.common.ALDBErrorException;
import com.aimluck.eip.common.ALEipManager;
import com.aimluck.eip.common.ALEipUser;
import com.aimluck.eip.common.ALPageNotFoundException;
import com.aimluck.eip.fileupload.util.FileuploadUtils;
import com.aimluck.eip.modules.actions.common.ALAction;
import com.aimluck.eip.orm.DatabaseOrmService;
import com.aimluck.eip.util.ALEipUtils;

/**
 * 回覧板のフォームデータを管理するクラスです。 <BR>
 * 
 */
public class CirculationFormData extends ALAbstractFormData {

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

  /** Request名 */
  private ALStringField request_name;

  /** カテゴリID */
  private ALNumberField category_id;

  /** 重要度 */
  private ALNumberField priority;

  /** メモ */
  private ALStringField note;

  /** カテゴリ一覧 */
  private List categoryList;

  /** 回覧先ユーザIDリスト */
  private ALStringField positions;

  /** 回覧先一覧 */
  private ArrayList<ALEipUser> memberList;

  /** ファイルアップロードリスト */
  private List fileuploadList;

  /** 添付ファイル */
  // private FileuploadLiteBean filebean = null;
  /** 添付フォルダ名 */
  private String folderName = null;

  /** 締切日 */
  private ALDateField limit_date;

  /** 締切日指定フラグ */
  private ALStringField limit_date_check;

  private String org_id;

  private int uid;

  private Date nowDate;

  /** <code>login_user</code> ログインユーザー */
  private ALEipUser login_user;

  private DataContext dataContext;

  /**
   * 
   * @param action
   * @param rundata
   * @param context
   * @see com.aimluck.eip.common.ALAbstractFormData#init(com.aimluck.eip.modules.actions.common.ALAction,
   *      org.apache.turbine.util.RunData, org.apache.velocity.context.Context)
   */
  @Override
  public void init(ALAction action, RunData rundata, Context context)
      throws ALPageNotFoundException, ALDBErrorException {
    super.init(action, rundata, context);

    dataContext = DatabaseOrmService.getInstance().getDataContext();

    login_user = ALEipUtils.getALEipUser(rundata);
    nowDate = Calendar.getInstance().getTime();
    uid = ALEipUtils.getUserId(rundata);
    org_id = DatabaseOrmService.getInstance().getOrgId(rundata);
    folderName = rundata.getParameters().getString("folderName");
  }

  /**
   * 各フィールドを初期化します。 <BR>
   * 
   * @see com.aimluck.eip.common.ALData#initField()
   */
  public void initField() {
    // リクエスト名
    request_name = new ALStringField();
    request_name.setFieldName("表題");
    request_name.setTrim(true);
    // カテゴリID
    category_id = new ALNumberField();
    category_id.setFieldName("カテゴリ");
    // 重要度
    priority = new ALNumberField(3);
    priority.setFieldName("重要度");
    // メモ
    note = new ALStringField();
    note.setFieldName("回覧内容");
    note.setTrim(false);
    // 回覧先のリスト
    positions = new ALStringField();
    positions.setFieldName("回覧先ユーザーリスト");
    positions.setTrim(true);
    // 回覧先一覧
    memberList = new ArrayList<ALEipUser>();
    // ファイルリスト
    fileuploadList = new ArrayList<String>();

    // 締切日
    limit_date = new ALDateField();
    limit_date.setFieldName("締切日");

    // 締切日
    if (limit_date.toString().equals("")) {
      limit_date.setValue(new Date());
    }

    // 締切日非指定フラグ
    limit_date_check = new ALStringField();
    limit_date_check.setFieldName("指定しない");
  }

  /**
   * 
   * @param rundata
   * @param context
   */
  public void loadCategoryList(RunData rundata, Context context) {
    categoryList = CirculationUtils.loadCategoryList(rundata, context);
  }

  /**
   * 
   * @param rundata
   * @param context
   * @param msgList
   * @return
   * @see com.aimluck.eip.common.ALAbstractFormData#setFormData(org.apache.turbine.util.RunData,
   *      org.apache.velocity.context.Context, java.util.ArrayList)
   */
  @Override
  protected boolean setFormData(RunData rundata, Context context,
      List<String> msgList) throws ALPageNotFoundException, ALDBErrorException {
    boolean res = super.setFormData(rundata, context, msgList);
    if (res) {
      try {
        String userNames[] = rundata.getParameters().getStrings("positions");
        if (userNames != null && userNames.length > 0) {

          DataContext dataContext =
            DatabaseOrmService.getInstance().getDataContext();
          SelectQuery query = new SelectQuery(TurbineUser.class);
          Expression exp1 =
            ExpressionFactory
              .inExp(_TurbineUser.LOGIN_NAME_PROPERTY, userNames);
          Expression exp2 =
            ExpressionFactory.matchExp(_TurbineUser.DISABLED_PROPERTY, "F");
          query.setQualifier(exp1);
          query.andQualifier(exp2);

          List list = dataContext.performQuery(query);

          TurbineUser record = null;
          int length = userNames.length;
          for (int i = 0; i < length; i++) {
            record = getEipUserRecord(list, userNames[i]);
            ALEipUser user = new ALEipUser();
            user.initField();
            user.setUserId(record.getUserId().intValue());
            user.setName(record.getLoginName());
            user.setAliasName(record.getFirstName(), record.getLastName());
            memberList.add(user);
          }
          fileuploadList = FileuploadUtils.getFileuploadList(rundata);
        }
      } catch (Exception ex) {
        logger.error("Exception", ex);
      }

      category_id.getValue();

      String event[] = rundata.getParameters().getStrings("event");
      if (event != null) {
        Iterator i = categoryList.iterator();
        while (i.hasNext()) {
          CirculationCategoryResultData tmp =
            (CirculationCategoryResultData) i.next();
          if (tmp.getCategoryId().getValue() == category_id.getValue()) {
            note.setValue(tmp.getOrderTemplate().toString());
          }
        }
      }
    }
    return res;
  }

  /**
   * テンプレートを渡す
   * 
   * @param num
   * @return
   */
  public String CategoryTemplate(int num) {
    for (Object o : categoryList) {
      CirculationCategoryResultData tmp = (CirculationCategoryResultData) o;
      if (tmp.getCategoryId().getValue() == num) {
        return tmp.getOrderTemplate().toString();
      }
    }
    return "";
  }

  /**
   * 指定したユーザ名のオブジェクトを取得する．
   * 
   * @param userList
   * @param userName
   * @return
   */
  private TurbineUser getEipUserRecord(List userList, String userName) {
    int size = userList.size();
    for (int i = 0; i < size; i++) {
      TurbineUser record = (TurbineUser) userList.get(i);
      if (record.getLoginName().equals(userName)) {
        return record;
      }
    }
    return null;
  }

  /**
   * リクエストの各フィールドに対する制約条件を設定します。 <BR>
   * 
   * @see com.aimluck.eip.common.ALAbstractFormData#setValidator()
   */
  @Override
  protected void setValidator() {
    // リクエスト名の文字数制限
    request_name.setNotNull(true);
    request_name.limitMaxLength(50);
    // メモの文字数制限
    note.setNotNull(true);
    note.limitMaxLength(2000);
  }

  /**
   * リクエストのフォームに入力されたデータの妥当性検証を行います。 <BR>
   * 
   * @param msgList
   * @return TRUE 成功 FALSE 失敗
   * @see com.aimluck.eip.common.ALAbstractFormData#validate(java.util.ArrayList)
   */
  @Override
  protected boolean validate(List<String> msgList) {
    // リクエスト名
    request_name.validate(msgList);
    // メモ
    note.validate(msgList);
    // 回覧先
    if (memberList == null || memberList.size() <= 0) {
      msgList.add("『 <span class='em'>回覧先</span> 』を指定してください。");
    }

    // 締切日非指定フラグが設定されている場合は締切日入力フォームチェックを行いません。
    if (limit_date_check.getValue() == null) {
      // 開始日
      limit_date.validate(msgList);
    }
    return (msgList.size() == 0);

  }

  /**
   * リクエストをデータベースから読み出します。 <BR>
   * 
   * @param rundata
   * @param context
   * @param msgList
   * @return TRUE 成功 FALSE 失敗
   * @see com.aimluck.eip.common.ALAbstractFormData#loadFormData(org.apache.turbine.util.RunData,
   *      org.apache.velocity.context.Context)
   */
  @Override
  protected boolean loadFormData(RunData rundata, Context context,
      List<String> msgList) {
    try {
      // オブジェクトモデルを取得
      AvzTCirculationRequest request =
        CirculationUtils.getAvzTCirculationRequest(rundata, context);
      if (request == null) {
        return false;
      }

      // リクエスト名
      request_name.setValue(request.getRequestName());
      // カテゴリID
      category_id.setValue(request
        .getToAvzTCirculationCategory()
        .getCategoryId()
        .longValue());
      // 優先度
      priority.setValue(request.getPriority().longValue());
      // メモ
      note.setValue(request.getNote());

      List maps = CirculationUtils.getAvzTCirculationRequestMaps(request);
      AvzTCirculationRequestMap map = null;
      int size = maps.size();
      for (int i = 0; i < size; i++) {
        map = (AvzTCirculationRequestMap) maps.get(i);
        int user_id = map.getUserId().intValue();
        memberList.add(ALEipUtils.getALEipUser(user_id));
      }

      // ファイル
      SelectQuery query = new SelectQuery(AvzTCirculationFile.class);
      query.andQualifier(ExpressionFactory.matchDbExp(
        _AvzTCirculationFile.TO_AVZ_TCIRCULATION_REQUEST_PROPERTY
          + "."
          + _AvzTCirculationRequest.REQUEST_ID_PK_COLUMN,
        request.getRequestId()));
      fileuploadList = dataContext.performQuery(query);

    } catch (Exception ex) {
      logger.error("Exception", ex);
      return false;
    }
    return true;
  }

  /**
   * リクエストをデータベースから削除します。 <BR>
   * 
   * @param rundata
   * @param context
   * @param msgList
   * @return TRUE 成功 FALSE 失敗
   * @see com.aimluck.eip.common.ALAbstractFormData#deleteFormData(org.apache.turbine.util.RunData,
   *      org.apache.velocity.context.Context)
   */
  @Override
  protected boolean deleteFormData(RunData rundata, Context context,
      List<String> msgList) {
    try {
      // オブジェクトモデルを取得
      AvzTCirculationRequest request =
        CirculationUtils.getAvzTCirculationRequestForOwner(rundata, context);
      if (request == null) {
        return false;
      }

      // ファイル削除処理
      ArrayList<String> fpaths = new ArrayList<String>();
      SelectQuery query = new SelectQuery(AvzTCirculationFile.class);
      query.andQualifier(ExpressionFactory.matchDbExp(
        _AvzTCirculationFile.TO_AVZ_TCIRCULATION_REQUEST_PROPERTY,
        request.getRequestId()));
      List files = dataContext.performQuery(query);
      if (files != null && files.size() > 0) {
        int fsize = files.size();
        for (int j = 0; j < fsize; j++) {
          fpaths.add(((AvzTCirculationFile) files.get(j)).getFilePath());
        }
      }

      if (fpaths.size() > 0) {
        // ローカルファイルに保存されているファイルを削除する．
        File file = null;
        int fsize = fpaths.size();
        for (int i = 0; i < fsize; i++) {
          file =
            new File(CirculationUtils.getSaveDirPath(org_id, uid)
              + fpaths.get(i));
          if (file.exists()) {
            file.delete();
          }
        }
      }

      // リクエストを削除
      dataContext.deleteObject(request);
      dataContext.commitChanges();

    } catch (Exception ex) {
      logger.error("Exception", ex);
      dataContext.rollbackChanges();
      return false;
    }
    return true;
  }

  /**
   * リクエストをデータベースに格納します。 <BR>
   * 
   * @param rundata
   * @param context
   * @param msgList
   * @return TRUE 成功 FALSE 失敗
   * @see com.aimluck.eip.common.ALAbstractFormData#insertFormData(org.apache.turbine.util.RunData,
   *      org.apache.velocity.context.Context, java.util.ArrayList)
   */
  @Override
  protected boolean insertFormData(RunData rundata, Context context,
      List<String> msgList) {
    try {
      AvzTCirculationCategory category =
        CirculationUtils.getAvzTCirculationCategory(dataContext, Long
          .valueOf(category_id.getValue()));

      // 新規オブジェクトモデル
      AvzTCirculationRequest request =
        (AvzTCirculationRequest) dataContext
          .createAndRegisterNewObject(AvzTCirculationRequest.class);

      // リクエスト名
      request.setRequestName(request_name.getValue());
      // カテゴリID
      request.setToAvzTCirculationCategory(category);
      // ユーザーID
      request.setUserId(Integer
        .valueOf((int) login_user.getUserId().getValue()));
      // 優先度
      request.setPriority(Short.valueOf((short) priority.getValue()));
      // メモ
      request.setNote(note.getValue());
      // 承認フラグ
      request.setProgress(CirculationUtils.DB_PROGRESS_WAIT);
      // 作成日
      request.setCreateDate(nowDate);
      // 更新日
      request.setUpdateDate(nowDate);

      // 回覧先の設定
      int size = memberList.size();
      for (int i = 0; i < size; i++) {
        insertAvzTCirculationRequestMap(
          request,
          memberList.get(i),
          CirculationUtils.DB_STATUS_REQUEST);
      }

      // 添付ファイル処理
      if (!CirculationUtils.insertFileDataDelegate(
        rundata,
        context,
        request,
        null,
        fileuploadList,
        folderName,
        msgList)) {
        return false;
      }

      // 締切日
      if (limit_date_check.getValue() == null) {
        request.setLimitDate(limit_date.getValue().getDate());
      } else {
        request.setLimitDate(CirculationUtils.getEmptyDate());
      }

      // リクエストを登録
      dataContext.commitChanges();

      File folder = FileuploadUtils.getFolder(org_id, uid, folderName);
      // 添付ファイル保存先のフォルダを削除
      FileuploadUtils.deleteFolder(folder);

    } catch (Exception ex) {
      // ex.printStackTrace();
      logger.error("Exception", ex);
      dataContext.rollbackChanges();
      return false;
    }
    return true;
  }

  /**
   * 
   * @param request
   * @param user
   * @param status
   *            R: 申請 C : 確認 A: 承認 D: 否認
   */
  private void insertAvzTCirculationRequestMap(AvzTCirculationRequest request,
      ALEipUser user, String status) {
    AvzTCirculationRequestMap map =
      (AvzTCirculationRequestMap) dataContext
        .createAndRegisterNewObject(AvzTCirculationRequestMap.class);
    int userid = (int) user.getUserId().getValue();
    map.setToAvzTCirculationRequest(request);
    map.setUserId(Integer.valueOf(userid));
    // R: 未確認 C : 確認済
    map.setStatus(status);
    map.setCreateDate(nowDate);
    map.setUpdateDate(nowDate);
  }

  /**
   * データベースに格納されているリクエストを更新します。 <BR>
   * 
   * @param rundata
   * @param context
   * @param msgList
   * @return TRUE 成功 FALSE 失敗
   * @see com.aimluck.eip.common.ALAbstractFormData#updateFormData(org.apache.turbine.util.RunData,
   *      org.apache.velocity.context.Context, java.util.ArrayList)
   */
  @Override
  protected boolean updateFormData(RunData rundata, Context context,
      List<String> msgList) {
    try {
      // オブジェクトモデルを取得
      AvzTCirculationRequest request =
        CirculationUtils.getAvzTCirculationRequestForOwner(rundata, context);
      if (request == null) {
        return false;
      }

      AvzTCirculationCategory category =
        CirculationUtils.getAvzTCirculationCategory(dataContext, Long
          .valueOf(category_id.getValue()));

      // リクエスト名
      request.setRequestName(request_name.getValue());
      // カテゴリID
      request.setToAvzTCirculationCategory(category);
      // 優先度
      request.setPriority(Short.valueOf((short) priority.getValue()));
      // メモ
      request.setNote(note.getValue());
      // 更新日
      request.setUpdateDate(Calendar.getInstance().getTime());

      // 締切日
      if (limit_date_check.getValue() == null) {
        request.setLimitDate(limit_date.getValue().getDate());
      } else {
        request.setLimitDate(CirculationUtils.getEmptyDate());
      }

      // 回覧先の再設定
      boolean add_new_member = mergeAvzTCirculationRequestMap(request);
      if (add_new_member) {
        // 回覧進行状況を巻き戻す
        request.setProgress(CirculationUtils.DB_PROGRESS_WAIT);
      }

      // 添付ファイル処理
      if (!CirculationUtils.insertFileDataDelegate(
        rundata,
        context,
        request,
        request,
        fileuploadList,
        folderName,
        msgList)) {
        return false;
      }

      // リクエストを登録
      dataContext.commitChanges();

      File folder = FileuploadUtils.getFolder(org_id, uid, folderName);
      // 添付ファイル保存先のフォルダを削除
      FileuploadUtils.deleteFolder(folder);

    } catch (Exception ex) {
      logger.error("Exception", ex);
      dataContext.rollbackChanges();
      // ex.printStackTrace();
      return false;
    }
    return true;
  }

  private boolean mergeAvzTCirculationRequestMap(AvzTCirculationRequest request) {

    boolean add_new_member = false;

    // 既存の回覧メンバーを削除した場合
    // List<AvzTCirculationRequestMap> oldList =
    // request.getAvzTCirculationRequestMapArray();
    List<AvzTCirculationRequestMap> oldList =
      CirculationUtils.getAvzTCirculationRequestMaps(request);
    for (AvzTCirculationRequestMap obj : oldList) {
      boolean found = false;
      for (ALEipUser user : memberList) {
        if (obj.getUserId().longValue() == user.getUserId().getValue()) {
          found = true;
          break;
        }
      }
      if (!found) {
        dataContext.deleteObject(obj);
      }
    }

    // 新たに回覧メンバーを増やした場合
    // oldList = request.getAvzTCirculationRequestMapArray();
    // oldList = CirculationUtils.getAvzTCirculationRequestMaps(request);
    for (ALEipUser user : memberList) {
      boolean found = false;
      for (AvzTCirculationRequestMap obj : oldList) {
        if (obj.getUserId().longValue() == user.getUserId().getValue()) {
          found = true;
          break;
        }
      }
      if (!found) {
        insertAvzTCirculationRequestMap(
          request,
          user,
          CirculationUtils.DB_STATUS_REQUEST);
        add_new_member = true;
      }
    }
    return add_new_member;
  }

  /**
   * カテゴリIDを取得します。 <BR>
   * 
   * @return
   */
  public ALNumberField getCategoryId() {
    return category_id;
  }

  /**
   * メモを取得します。 <BR>
   * 
   * @return
   */
  public ALStringField getNote() {
    return note;
  }

  /**
   * メモのフィールドを設定します。 <BR>
   * 
   * @param str
   * @return
   */
  public void setNote(String str) {
    note.setValue(str);
  }

  /**
   * 優先度を取得します。 <BR>
   * 
   * @return
   */
  public ALNumberField getPriority() {
    return priority;
  }

  /**
   * 優先度を設定します。 <BR>
   * 
   * @param str
   * @return
   */
  public void setPriority(String str) {
    priority.setValue(str);
  }

  /**
   * リクエスト名を取得します。 <BR>
   * 
   * @return
   */
  public ALStringField getRequestName() {
    return request_name;
  }

  /**
   * リクエスト名を格納します。 <BR>
   * 
   * @param str
   * @return
   */

  public void setRequestName(String str) {
    request_name.setValue(str);
  }

  /**
   * カテゴリ一覧を取得します。 <BR>
   * 
   * @return
   */
  public List getCategoryList() {
    return categoryList;
  }

  /**
   * グループメンバーを取得します。 <BR>
   * 
   * @return
   */
  public List getMemberList() {
    return memberList;
  }

  /**
   * 
   * @param groupname
   * @return
   */
  public List getUsers(String groupname) {
    return ALEipUtils.getUsers(groupname);
  }

  /**
   * 
   * @return
   */
  public Map getPostMap() {
    return ALEipManager.getInstance().getPostMap();
  }

  public List getAttachmentFileNameList() {
    return fileuploadList;
  }

  /**
   * @return
   */
  public ALDateField getLimitDate() {
    return limit_date;
  }

  /**
   * アクセス権限チェック用メソッド。<br />
   * アクセス権限の機能名を返します。
   * 
   * @return
   */
  @Override
  public String getAclPortletFeature() {
    return null;
  }
}
