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

import java.io.File;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import javax.imageio.ImageIO;

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

import com.aimluck.commons.field.ALNumberField;
import com.aimluck.commons.field.ALStringField;
import com.aimluck.eip.blog.util.BlogUtils;
import com.aimluck.eip.cayenne.om.portlet.EipTBlog;
import com.aimluck.eip.cayenne.om.portlet.EipTBlogEntry;
import com.aimluck.eip.cayenne.om.portlet.EipTBlogFile;
import com.aimluck.eip.cayenne.om.portlet.EipTBlogThema;
import com.aimluck.eip.common.ALAbstractFormData;
import com.aimluck.eip.common.ALBaseUser;
import com.aimluck.eip.common.ALDBErrorException;
import com.aimluck.eip.common.ALEipConstants;
import com.aimluck.eip.common.ALPageNotFoundException;
import com.aimluck.eip.fileupload.beans.FileuploadLiteBean;
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.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.whatsnew.util.WhatsNewUtils;

/**
 * ブログエントリーのフォームデータを管理するクラスです。 <BR>
 *
 */
public class BlogEntryFormData extends ALAbstractFormData {

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

  /** Title */
  private ALStringField title;

  /** メモ */
  private ALStringField note;

  /** ブログ ID */
  private ALNumberField blog_id;

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

  /** コメント付加フラグ */
  private ALStringField allow_comments;

  private ArrayList themaList;

  /** */
  private boolean is_new_thema;

  /** 添付ファイル */
  private FileuploadLiteBean filebean = null;

  /** 添付ファイルリスト */
  private List fileuploadList = null;

  /** 添付フォルダ名 */
  private String folderName = null;

  private int uid;

  private String user_name;

  private boolean has_photo;

  private EipTBlog blog;

  private EipTBlogThema thema;

  private BlogThemaFormData blogthema;

  private String org_id;

  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)
   */
  public void init(ALAction action, RunData rundata, Context context)
      throws ALPageNotFoundException, ALDBErrorException {
    super.init(action, rundata, context);
    is_new_thema = rundata.getParameters().getBoolean("is_new_thema");

    uid = ALEipUtils.getUserId(rundata);
    dataContext = DatabaseOrmService.getInstance().getDataContext();
    org_id = DatabaseOrmService.getInstance().getOrgId(rundata);

    folderName = rundata.getParameters().getString("folderName");

    // 顔写真の取得
    ALBaseUser user = BlogUtils.getBaseUser(uid);
    user_name = user.getLastName() + " " + user.getFirstName();
    if (user.getPhoto() != null) {
      has_photo = true;
    } else {
      has_photo = false;
    }
  }

  /**
   * 各フィールドを初期化します。 <BR>
   *
   * @see com.aimluck.eip.common.ALData#initField()
   */
  public void initField() {
    // Title
    title = new ALStringField();
    title.setFieldName("タイトル");
    title.setTrim(true);
    // メモ
    note = new ALStringField();
    note.setFieldName("記事");
    note.setTrim(false);
    // カテゴリID
    blog_id = new ALNumberField();
    blog_id.setFieldName("ブログ");
    // カテゴリID
    thema_id = new ALNumberField();
    thema_id.setFieldName("テーマ");
    // 公開区分
    allow_comments = new ALStringField();
    allow_comments.setFieldName("コメント付加フラグ");
    allow_comments.setValue("T");
    allow_comments.setTrim(true);

    fileuploadList = new ArrayList();

    blogthema = new BlogThemaFormData();
    blogthema.initField();
  }

  /**
   *
   * @param rundata
   * @param context
   */
  public void loadThemaList(RunData rundata, Context context) {
    themaList = BlogUtils.getThemaList(rundata, context);
  }

  /**
   * エントリーの各フィールドに対する制約条件を設定します。 <BR>
   *
   * @see com.aimluck.eip.common.ALAbstractFormData#setValidator()
   */
  protected void setValidator() {
    // Title必須項目
    title.setNotNull(true);
    // Titleの文字数制限
    title.limitMaxLength(50);
    // メモの文字数制限
    note.limitMaxLength(10000);

    blogthema.setValidator();
  }

  /**
   * エントリーのフォームに入力されたデータの妥当性検証を行います。 <BR>
   *
   * @param msgList
   * @return TRUE 成功 FALSE 失敗
   * @see com.aimluck.eip.common.ALAbstractFormData#validate(java.util.ArrayList)
   */
  protected boolean validate(ArrayList msgList) {
    // Title
    title.validate(msgList);
    // メモ
    note.validate(msgList);
    if (is_new_thema) {
      // テーマ
      blogthema.setMode(ALEipConstants.MODE_INSERT);
      blogthema.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)
   */
  protected boolean loadFormData(RunData rundata, Context context,
      ArrayList msgList) {
    try {
      // オブジェクトモデルを取得
      EipTBlogEntry entry = BlogUtils.getEipTBlogEntry(rundata, context);
      if (entry == null)
        return false;
      // Title
      title.setValue(entry.getTitle());
      // メモ
      note.setValue(entry.getNote());
      // カテゴリID
      thema_id.setValue(entry.getEipTBlogThema().getThemaId().longValue());
      // 状態
      allow_comments.setValue(entry.getAllowComments());

      SelectQuery filequery = new SelectQuery(EipTBlogFile.class);
      Expression fileexp = ExpressionFactory.matchDbExp(
          EipTBlogFile.EIP_TBLOG_ENTRY_PROPERTY + "."
              + EipTBlogEntry.ENTRY_ID_PK_COLUMN, entry.getEntryId());
      filequery.setQualifier(fileexp);
      List files = dataContext.performQuery(filequery);
      FileuploadLiteBean filebean = null;
      int size = files.size();
      for (int i = 0; i < size; i++) {
        EipTBlogFile file = (EipTBlogFile) files.get(i);
        filebean = new FileuploadLiteBean();
        filebean.initField();
        filebean.setFolderName(BlogUtils.PREFIX_DBFILE
            + Integer.toString(file.getFileId()));
        filebean.setFileName(file.getTitle());
        filebean.setFileId(file.getFileId());
        fileuploadList.add(filebean);
      }

    } 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)
   */
  protected boolean deleteFormData(RunData rundata, Context context,
      ArrayList msgList) {
    try {
      // オブジェクトモデルを取得
      EipTBlogEntry entry = BlogUtils.getEipTBlogEntry(rundata, context);
      if (entry == null)
        return false;

      // entityIdの取得
      int entityId = entry.getEntryId();
      // タイトルの取得
      String todoName = entry.getTitle();

      ArrayList fpaths = new ArrayList();
      List files = entry.getEipTBlogFiles();
      if (files != null && files.size() > 0) {
        int size = files.size();
        for (int i = 0; i < size; i++) {
          fpaths.add(((EipTBlogFile) files.get(i)).getFilePath());
        }
      }

      // エントリーを削除
      dataContext.deleteObject(entry);
      dataContext.commitChanges();

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

      if (fpaths.size() > 0) {
        // ローカルファイルに保存されているファイルを削除する．
        File file = null;
        int fsize = fpaths.size();
        for (int i = 0; i < fsize; i++) {
          file = new File(BlogUtils.getSaveDirPath(org_id, uid)
              + (String) fpaths.get(i));
          if (file.exists()) {
            file.delete();
          }
        }
      }
    } 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#insertFormData(org.apache.turbine.util.RunData,
   *      org.apache.velocity.context.Context, java.util.ArrayList)
   */
  protected boolean insertFormData(RunData rundata, Context context,
      ArrayList msgList) {
    boolean res = true;
    try {
      if (is_new_thema) {
        // テーマの登録処理
        res = blogthema.insertFormData(rundata, context, msgList);
        if (res)
          thema_id.setValue(blogthema.getThemaId());
      }

      if (res) {
        thema = (EipTBlogThema) DataObjectUtils.objectForPK(dataContext,
            EipTBlogThema.class, Integer.valueOf((int) thema_id.getValue()));

        blog = BlogUtils.getEipTBlog(rundata, context);
        if (blog == null) {
          if (!insertBlogData(rundata, context)) {
            // TODO ロールバック
          }
        } else {
          blog_id.setValue(blog.getBlogId().longValue());
        }

        // 新規オブジェクトモデル
        EipTBlogEntry entry = (EipTBlogEntry) dataContext
            .createAndRegisterNewObject(EipTBlogEntry.class);
        // Owner ID
        entry.setOwnerId(Integer.valueOf(uid));
        // Title
        entry.setTitle(title.getValue());
        // Note
        entry.setNote(note.getValue());
        // ブログID
        entry.setEipTBlog(blog);
        // テーマID
        entry.setEipTBlogThema(thema);
        // コメント付加フラグ
        entry.setAllowComments("T");
        // 作成日
        entry.setCreateDate(Calendar.getInstance().getTime());
        // 更新日
        entry.setUpdateDate(Calendar.getInstance().getTime());

        // 添付ファイルを登録する．
        insertAttachmentFiles(fileuploadList, folderName, uid, entry, msgList);

        dataContext.commitChanges();

        /* 自分以外の全員に新着ポートレット登録 */
        WhatsNewUtils.insertWhatsNewPublic(dataContext,
            WhatsNewUtils.WHATS_NEW_TYPE_BLOG_ENTRY, entry.getEntryId()
                .intValue(), uid);

        // イベントログに保存
        ALEventlogFactoryService.getInstance().getEventlogHandler().log(
            blog.getBlogId(), ALEventlogConstants.PORTLET_TYPE_BLOG_ENTRY,
            title.getValue());

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

  private List getRequestedHasFileIdList(List attachmentFileNameList) {
    List idlist = new ArrayList();
    FileuploadLiteBean filebean = null;
    // if (attachmentFileNameList != null && !"".equals(attachmentFileNameList))
    // {
    if (attachmentFileNameList != null) {
      int size = attachmentFileNameList.size();
      for (int i = 0; i < size; i++) {
        filebean = (FileuploadLiteBean) attachmentFileNameList.get(i);
        if (!filebean.isNewFile()) {
          int index = filebean.getFileId();
          idlist.add(Integer.valueOf(index));
        }
      }
    }
    return idlist;
  }

  private List getRequestedFileIdList(List attachmentFileNameList) {
    List idlist = new ArrayList();
    FileuploadLiteBean filebean = null;
    // if (attachmentFileNameList != null && !"".equals(attachmentFileNameList))
    // {
    if (attachmentFileNameList != null) {
      int size = attachmentFileNameList.size();
      for (int i = 0; i < size; i++) {
        filebean = (FileuploadLiteBean) attachmentFileNameList.get(i);
        String foldername = filebean.getFolderName();
        if (foldername != null
            && foldername.startsWith(BlogUtils.PREFIX_DBFILE)) {
          String index = foldername.substring(BlogUtils.PREFIX_DBFILE.length(),
              foldername.length());
          idlist.add(Integer.valueOf(index));
        }
      }
    }
    return idlist;
  }

  private boolean insertAttachmentFiles(List fileuploadList, String folderName,
      int uid, EipTBlogEntry entry, ArrayList msgList) {

    if (fileuploadList == null || fileuploadList.size() <= 0) {
      return true;
    }

    try {
      int length = fileuploadList.size();
      ArrayList newfilebeans = new ArrayList();
      FileuploadLiteBean filebean = null;
      for (int i = 0; i < length; i++) {
        filebean = (FileuploadLiteBean) fileuploadList.get(i);
        if (filebean.isNewFile()) {
          newfilebeans.add(filebean);
        }
      }
      int newfilebeansSize = newfilebeans.size();
      if (newfilebeansSize > 0) {
        FileuploadLiteBean newfilebean = null;
        for (int j = 0; j < length; j++) {
          newfilebean = (FileuploadLiteBean) newfilebeans.get(j);
          // サムネイル処理
          String[] acceptExts = ImageIO.getWriterFormatNames();
          byte[] fileThumbnail = FileuploadUtils.getBytesShrinkFilebean(org_id,
              folderName, uid, newfilebean, acceptExts,
              FileuploadUtils.DEF_THUMBNAIL_WIDTH,
              FileuploadUtils.DEF_THUMBNAIL_HEIGTH, msgList);

          String filename = FileuploadUtils.getNewFileName(BlogUtils
              .getSaveDirPath(org_id, uid));

          // 新規オブジェクトモデル
          EipTBlogFile file = (EipTBlogFile) dataContext
              .createAndRegisterNewObject(EipTBlogFile.class);
          file.setOwnerId(Integer.valueOf(uid));
          file.setTitle(newfilebean.getFileName());
          file.setFilePath(BlogUtils.getRelativePath(filename));
          if (fileThumbnail != null) {
            file.setFileThumbnail(fileThumbnail);
          }
          file.setEipTBlogEntry(entry);
          file.setCreateDate(Calendar.getInstance().getTime());
          file.setUpdateDate(Calendar.getInstance().getTime());

          // ファイルの移動
          File srcFile = FileuploadUtils.getAbsolutePath(org_id, uid,
              folderName, newfilebean.getFileId());
          File destFile = new File(BlogUtils.getAbsolutePath(org_id, uid,
              filename));
          FileuploadUtils.copyFile(srcFile, destFile);

          srcFile = null;
          destFile = null;
        }

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

    } catch (Exception e) {
      e.printStackTrace();
    }
    return true;
  }

  private boolean insertBlogData(RunData rundata, Context context) {
    try {
      // 新規オブジェクトモデル
      blog = (EipTBlog) dataContext.createAndRegisterNewObject(EipTBlog.class);
      // ユーザーID
      blog.setOwnerId(Integer.valueOf(uid));
      // 作成日
      blog.setCreateDate(Calendar.getInstance().getTime());
      // 更新日
      blog.setUpdateDate(Calendar.getInstance().getTime());
      // ブログを登録
      dataContext.commitChanges();
      // ブログIDの設定
      blog_id.setValue(blog.getBlogId().longValue());
    } 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#updateFormData(org.apache.turbine.util.RunData,
   *      org.apache.velocity.context.Context, java.util.ArrayList)
   */
  protected boolean updateFormData(RunData rundata, Context context,
      ArrayList msgList) {
    boolean res = false;
    try {
      // オブジェクトモデルを取得
      EipTBlogEntry entry = BlogUtils.getEipTBlogEntry(rundata, context);
      if (entry == null)
        return false;

      if (is_new_thema) {
        // テーマの登録処理
        res = blogthema.insertFormData(rundata, context, msgList);

        if (res) {
          thema = (EipTBlogThema) BlogUtils.getEipTBlogThema(dataContext, (long) blogthema.getThemaId());
          thema_id.setValue(thema.getThemaId().longValue());
        }
      } else {
        thema = (EipTBlogThema) DataObjectUtils.objectForPK(dataContext,
            EipTBlogThema.class, Integer.valueOf((int) thema_id.getValue()));
        res = true;
      }

      if (res) {
        // Title
        entry.setTitle(title.getValue());
        // メモ
        entry.setNote(note.getValue());
        // カテゴリID
        entry.setEipTBlogThema(thema);
        // ユーザーID
        entry.setOwnerId(Integer.valueOf(uid));
        // コメント付加フラグ
        entry.setAllowComments("T");
        // 更新日
        entry.setUpdateDate(Calendar.getInstance().getTime());

        // List attIdList = getRequestedFileIdList(fileuploadList);
        // List files = entry.getEipTBlogFiles();
        // int size = files.size();
        // for (int i = 0; i < size; i++) {
        // EipTBlogFile file = (EipTBlogFile) files.get(i);
        // if (!attIdList.contains(file.getFileId())) {
        // // orm_file.doDelete(file);
        // dataContext.deleteObject(file);
        // }
        // }

        // サーバーに残すファイルのID
        List attIdList = getRequestedHasFileIdList(fileuploadList);
        // 現在選択しているエントリが持っているファイル
        List files = BlogUtils.getEipTBlogFileList(entry.getEntryId());
        if (files != null) {
          int size = files.size();
          for (int i = 0; i < size; i++) {
            EipTBlogFile file = (EipTBlogFile) files.get(i);
            if (!attIdList.contains(file.getFileId())) {
              // ファイルシステムから削除
              File fileonsysytem = new File(BlogUtils.getSaveDirPath(org_id,
                  uid)
                  + (String) file.getFilePath());
              if (fileonsysytem.exists()) {
                fileonsysytem.delete();
              }
              // DBから削除
              dataContext.deleteObject(file);

            }
          }
        }

        // 添付ファイルを登録する．
        insertAttachmentFiles(fileuploadList, folderName, uid, entry, msgList);

        dataContext.commitChanges();

        // イベントログに保存
        ALEventlogFactoryService.getInstance().getEventlogHandler().log(
            entry.getEntryId(), ALEventlogConstants.PORTLET_TYPE_BLOG_ENTRY,
            title.getValue());
      }
    } catch (Exception ex) {
      logger.error("Exception", ex);
      return false;
    }
    return res;
  }

  /**
   *
   * @see com.aimluck.eip.common.ALAbstractFormData#setFormData(org.apache.turbine.util.RunData,
   *      org.apache.velocity.context.Context, java.util.ArrayList)
   */
  protected boolean setFormData(RunData rundata, Context context,
      ArrayList msgList) throws ALPageNotFoundException, ALDBErrorException {

    boolean res = super.setFormData(rundata, context, msgList);

    if (res) {
      try {
        blogthema.setFormData(rundata, context, msgList);

        // fileuploadList = FileuploadUtils.getFileuploadList(rundata);
        fileuploadList = BlogUtils.getFileuploadList(rundata);
      } catch (Exception ex) {
        logger.error("Exception", ex);
      }
    }
    return res;
  }

  /**
   * 添付ファイルを削除する．
   *
   * @param action
   * @param rundata
   * @param context
   * @return TRUE 成功 FALSE 失敗
   */
  public boolean doDeleteAttachments(ALAction action, RunData rundata,
      Context context) {
    try {
      init(action, rundata, context);
      action.setMode(ALEipConstants.MODE_DELETE);
      ArrayList msgList = new ArrayList();
      setValidator();
      boolean res = (setFormData(rundata, context, msgList) && deleteAttachments(
          rundata, context, msgList));
      action.setResultData(this);
      action.addErrorMessages(msgList);
      action.putData(rundata, context);
      return res;
    } catch (ALPageNotFoundException e) {
      ALEipUtils.redirectPageNotFound(rundata);
      return false;
    } catch (ALDBErrorException e) {
      ALEipUtils.redirectDBError(rundata);
      return false;
    }
  }

  /**
   * @see com.aimluck.eip.common.ALAbstractFormData#updateFormData(org.apache.turbine.util.RunData,
   *      org.apache.velocity.context.Context, java.util.ArrayList)
   */
  protected boolean deleteAttachments(RunData rundata, Context context,
      ArrayList msgList) {
    if (rundata == null || context == null) {
      msgList.add("システム上の問題のため、削除できませんでした。");
      return false;
    }

    return FileuploadUtils.deleteAttachments(org_id, uid, folderName,
        fileuploadList);
  }

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

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

  /**
   * Title を取得します。 <BR>
   *
   * @return
   */
  public ALStringField getTitle() {
    return title;
  }

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

  /**
   * @return
   */
  public boolean isNewThema() {
    return is_new_thema;
  }

  /**
   * テーマを取得します。
   *
   * @return
   */
  public BlogThemaFormData getBlogThema() {
    return blogthema;
  }

  public List getAttachmentFileNameList() {
    return fileuploadList;
  }

  public String getFolderName() {
    return folderName;
  }

  public int getUserId() {
    return uid;
  }

  public String getUserName() {
    return user_name;
  }

  public boolean hasPhoto() {
    return has_photo;
  }

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