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

import java.io.File;
import java.io.FileInputStream;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import net.fortuna.ical4j.data.CalendarBuilder;
import net.fortuna.ical4j.filter.Filter;
import net.fortuna.ical4j.filter.PeriodRule;
import net.fortuna.ical4j.model.Component;
import net.fortuna.ical4j.model.DateTime;
import net.fortuna.ical4j.model.Dur;
import net.fortuna.ical4j.model.Period;
import net.fortuna.ical4j.model.Property;
import net.fortuna.ical4j.model.component.VEvent;
import net.fortuna.ical4j.model.property.RRule;

import org.apache.jetspeed.portal.portlets.VelocityPortlet;
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.eip.cayenne.om.portlet.EipTSchedule;
import com.aimluck.eip.common.ALAbstractFormData;
import com.aimluck.eip.common.ALDBErrorException;
import com.aimluck.eip.common.ALPageNotFoundException;
import com.aimluck.eip.coordinationforgooglecal.util.CoordinationForGoogleCalUtils;
import com.aimluck.eip.modules.actions.common.ALAction;
import com.aimluck.eip.orm.Database;
import com.aimluck.eip.util.ALEipUtils;

/**
 * iCalendarのスケジュールデータをインサートするクラスです。 <BR>
 * 
 */
public class CoordinationForGoogleCalInsertFormData extends ALAbstractFormData {

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

  /** 現在選択されているタブ */
  private String currentTab;

  private ALDateField from_date;

  private ALDateField to_date;

  private String time_select_flg;

  private String period_flg;

  private int loginuser;

  // /** カスタマイズ画面での入力値 */
  // private String uid_pla;

  /**
   * init
   * 
   * @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);

    String tabParam = rundata.getParameters().getString("tab");
    currentTab = ALEipUtils.getTemp(rundata, context, "tab");
    if (tabParam == null && currentTab == null) {
      ALEipUtils.setTemp(rundata, context, "tab", "import");
      currentTab = "import";
    } else if (tabParam != null) {
      ALEipUtils.setTemp(rundata, context, "tab", tabParam);
      currentTab = tabParam;
    }

    // ２つ以上のAipoを使用する場合、インポートするUIDの重複を防ぐ
    // try{
    //
    // //UIDを取得する ※初期値はIPを使用
    // VelocityPortlet portlet = ALEipUtils.getPortlet(rundata, context);
    //  
    // String defalt_uid =
    // portlet.getPortletConfig().getInitParameter("p1a-title1");
    // if(defalt_uid==null || "".equals(defalt_uid)){
    // java.util.Enumeration enuIfs = NetworkInterface.getNetworkInterfaces();
    // if (null != enuIfs) {
    // while (enuIfs.hasMoreElements()) {
    // NetworkInterface ni = (NetworkInterface) enuIfs.nextElement();
    // java.util.Enumeration enuAddrs = ni.getInetAddresses();
    // while (enuAddrs.hasMoreElements()) {
    // InetAddress in4 = (InetAddress) enuAddrs.nextElement();
    // if (!in4.isLoopbackAddress()) {
    // uid_pla = in4.getHostAddress();
    //                
    // }
    // }
    // }
    // }
    // }else{
    // uid_pla = portlet.getPortletConfig().getInitParameter("p1a-title1");
    // }
    // if(uid_pla == null || "".equals(uid_pla)){
    // uid_pla = CoordinationForGoogleCalUtils.LOCAL_HOST;
    // }
    // }catch(Exception ex){
    // logger.error("Exception", ex);
    // }

    period_flg = rundata.getParameters().getString("period");

    time_select_flg = rundata.getParameters().getString("time_change");

    from_date = new ALDateField();
    to_date = new ALDateField();

    if ("month_select".equals(time_select_flg)) {

      Calendar from = Calendar.getInstance();

      // インポート対象範囲の開始日に選択値をセット
      int from_year = rundata.getParameters().getInt("view_date_year_from");
      int from_month = rundata.getParameters().getInt("view_date_month_from");

      from.set(Calendar.YEAR, from_year);
      from.set(Calendar.MONTH, from_month - 1);

      int from_day = from.getActualMinimum(Calendar.DATE);
      int from_hour = from.getActualMinimum(Calendar.HOUR_OF_DAY);
      int from_minute = from.getActualMinimum(Calendar.MINUTE);
      int from_second = from.getActualMinimum(Calendar.SECOND);

      from.set(Calendar.DAY_OF_MONTH, from_day);
      from.set(Calendar.HOUR_OF_DAY, from_hour);
      from.set(Calendar.MINUTE, from_minute);
      from.set(Calendar.SECOND, from_second);

      from_date.setValue(from.getTime());

      Calendar to = Calendar.getInstance();

      // インポート対象範囲の終了日に選択値をセット
      int to_year = rundata.getParameters().getInt("view_date_year_to");
      int to_month = rundata.getParameters().getInt("view_date_month_to");

      to.set(Calendar.YEAR, to_year);
      to.set(Calendar.MONTH, to_month - 1);

      int to_day = to.getActualMaximum(Calendar.DATE);
      int to_hour = to.getActualMaximum(Calendar.HOUR_OF_DAY);
      int to_minute = to.getActualMaximum(Calendar.MINUTE);
      int to_second = to.getActualMaximum(Calendar.SECOND);

      to.set(Calendar.DAY_OF_MONTH, to_day);
      to.set(Calendar.HOUR_OF_DAY, to_hour);
      to.set(Calendar.MINUTE, to_minute);
      to.set(Calendar.SECOND, to_second);

      to_date.setValue(to.getTime());

    } else {
      // 日単位指定
      String from_date_str = rundata.getParameters().getString("from_date");
      String to_date_str = rundata.getParameters().getString("to_date");

      try {
        from_date.setValue(DateFormat.getDateInstance().parse(from_date_str));
        to_date.setValue(DateFormat.getDateInstance().parse(to_date_str));
      } catch (ParseException e) {
        e.printStackTrace();
      }

    }
    loginuser = ALEipUtils.getUserId(rundata);

    /**
     * 下記のコメントアウトのようにアクセスコントロールを追加する場合は
     * com.aimluck.eip.services.accessctl.ALAccessControlConstantsに
     * アクセスコントロール用の定数を追加してください。 (例) public static final String
     * POERTLET_FEATURE_COORDINATIONFORGOOGLECAL_COORDINATIONFORGOOGLECAL_OTHER =
     * "coordinationforgooglecal_coordinationforgooglecal_other";
     */

    // aclPortletFeature =
    // ALAccessControlConstants.POERTLET_FEATURE_COORDINATIONFORGOOGLECAL_COORDINATIONFORGOOGLECAL_SELF;
  }

  /**
   * 各フィールドを初期化します。 <BR>
   * 
   * @see com.aimluck.eip.common.ALData#initField()
   */
  public void initField() {

  }

  /**
   * データに値をセットする． <BR>
   * 
   * @param rundata
   * @param context
   * @param msgList
   *            エラーメッセージのリスト
   * @return TRUE 成功 FALSE 失敗
   */
  @Override
  protected boolean setFormData(RunData rundata, Context context,
      List<String> msgList) throws ALPageNotFoundException, ALDBErrorException {
    boolean res = super.setFormData(rundata, context, msgList);

    return res;

  }

  /**
   * の各フィールドに対する制約条件を設定します。 <BR>
   * 
   * @see com.aimluck.eip.common.ALAbstractFormData#setValidator()
   */

  @Override
  protected void setValidator() {

  }

  /**
   * のフォームに入力されたデータの妥当性検証を行います。 <BR>
   * 
   * @param msgList
   * @return TRUE 成功 FALSE 失敗
   * @see com.aimluck.eip.common.ALAbstractFormData#validate(java.util.ArrayList)
   */
  @Override
  protected boolean validate(List<String> 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) {

    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) {

    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 {

      VelocityPortlet portlet = ALEipUtils.getPortlet(rundata, context);
      int distribution =
        Integer.parseInt(ALEipUtils
          .getPortlet(rundata, context)
          .getPortletConfig()
          .getInitParameter("p1a-rows"));
      String temp_folder_index =
        rundata.getParameters().getString("temp_folder");
      String filepath =
        CoordinationForGoogleCalUtils
          .getScheduleIcsFolderName(temp_folder_index)
          + File.separator
          + CoordinationForGoogleCalUtils.FOLDER_TMP_FOR_USERINFO_ICS_FILENAME;

      FileInputStream is = new FileInputStream(filepath);
      CalendarBuilder builder = new CalendarBuilder();
      // CalendarBuilderのbuild(FileInputStream)でUTF-8に文字コード設定
      net.fortuna.ical4j.model.Calendar calendar = builder.build(is);

      List con = new ArrayList();

      Calendar fd = Calendar.getInstance();
      fd.setTime(from_date.getValue().getDate());
      DateTime from_d = new DateTime();
      from_d.setTime(fd.getTime().getTime());

      Calendar td = Calendar.getInstance();
      td.setTime(to_date.getValue().getDate());
      DateTime to_d = new DateTime();
      to_d.setTime(td.getTime().getTime());

      if (period_flg == null || "".equals(period_flg)) {

        // Period(final DateTime start, final DateTime end)でインポートする期間を設定する
        Period period = new Period(new DateTime(from_d), new Dur(from_d, to_d));
        Filter filter = new Filter(new PeriodRule(period));

        con = (List) filter.filter(calendar.getComponents(Component.VEVENT));

      } else {

        con = calendar.getComponents(Component.VEVENT);

      }

      // 現在時刻を取得
      Date now = Calendar.getInstance().getTime();

      // VEVENT毎の要素を取得
      if (con.size() == 0) {
        return true;
      }

      EipTSchedule schedule = null;

      List dummyList = new ArrayList();

      for (int i = 0; i < con.size(); i++) {

        Calendar startDate = Calendar.getInstance();
        Calendar endDate = Calendar.getInstance();

        VEvent ve = (VEvent) con.get(i);
        Property pro =
          ve.getProperty(CoordinationForGoogleCalUtils.PROPERTY_NAME_RRULE);
        RRule rrl = (RRule) pro;

        // EXDATEをもつイベントをListにいれておく
        // イベントの中にEXDATEが設定されていたらdummyスケジュールを作成する
        List exdate =
          ve.getProperties(CoordinationForGoogleCalUtils.PROPERTY_NAME_EXDATE);
        if (exdate.size() != 0) {
          dummyList.add(ve);
        }

        if (pro == null) {

          // 繰り返し間隔指定ありの年間終日スケジュールでのみ使用
          int interyear = 0;
          // UID重複チェック実装時には引数にuid_plaを追加
          CoordinationForGoogleCalUtils.insertSchedule(
            ve,
            now,
            loginuser,
            schedule,
            startDate,
            endDate,
            distribution,
            interyear);

        } else {

          int interval = rrl.getRecur().getInterval();

          // 毎日・間隔有
          if (interval > 0
            && CoordinationForGoogleCalUtils.RRULE_FREQ_DAILY.equals(rrl
              .getRecur()
              .getFrequency())) {

            // 保存限度1年先の開始日時をセット
            Calendar start = Calendar.getInstance();
            start.setTime(ve.getStartDate().getDate());
            start.set(Calendar.YEAR, startDate.get(Calendar.YEAR) + 1);

            // 初期の開始・終了日時に戻す
            startDate.setTime(ve.getStartDate().getDate());
            endDate.setTime(ve.getEndDate().getDate());

            // UID重複チェック実装時には引数にuid_plaを追加
            CoordinationForGoogleCalUtils.createDailyIntervalSchedule(
              ve,
              now,
              loginuser,
              rrl,
              schedule,
              startDate,
              endDate,
              to_d,
              start,
              interval,
              distribution);

            // 毎週・間隔有
          } else if (interval > 0
            && CoordinationForGoogleCalUtils.RRULE_FREQ_WEEKLY.equals(rrl
              .getRecur()
              .getFrequency())) {

            // 保存限度1年先の開始日時をセット
            Calendar start = Calendar.getInstance();
            start.setTime(ve.getStartDate().getDate());
            start.set(Calendar.YEAR, startDate.get(Calendar.YEAR) + 1);

            // 初期の開始・終了日時に戻す
            startDate.setTime(ve.getStartDate().getDate());
            endDate.setTime(ve.getEndDate().getDate());

            // UID重複チェック実装時には引数にuid_plaを追加
            CoordinationForGoogleCalUtils.createWeeklyIntervalSchedule(
              ve,
              now,
              loginuser,
              rrl,
              schedule,
              startDate,
              endDate,
              to_d,
              start,
              interval,
              distribution);

            // 毎月・曜日指定・間隔有
          } else if (interval > 0
            && CoordinationForGoogleCalUtils.RRULE_FREQ_MONTHLY.equals(rrl
              .getRecur()
              .getFrequency())
            && rrl.getRecur().getDayList().size() != 0) {

            // 保存限度1年先の開始日時をセット
            Calendar start = Calendar.getInstance();
            start.setTime(ve.getStartDate().getDate());
            start.set(Calendar.YEAR, startDate.get(Calendar.YEAR) + 1);

            startDate.setTime(ve.getStartDate().getDate());
            endDate.setTime(ve.getEndDate().getDate());

            // UID重複チェック実装時には引数にuid_plaを追加
            CoordinationForGoogleCalUtils
              .createMonthlySetDayOfWeekIntervalSchedule(
                ve,
                now,
                loginuser,
                rrl,
                schedule,
                startDate,
                endDate,
                to_d,
                start,
                interval,
                distribution);

            // 毎月・曜日指定
          } else if (CoordinationForGoogleCalUtils.RRULE_FREQ_MONTHLY
            .equals(rrl.getRecur().getFrequency())
            && rrl.getRecur().getDayList().size() != 0) {

            // 保存限度1年先の開始日時をセット
            Calendar start = Calendar.getInstance();
            start.setTime(ve.getStartDate().getDate());
            start.set(Calendar.YEAR, startDate.get(Calendar.YEAR) + 1);

            startDate.setTime(ve.getStartDate().getDate());
            endDate.setTime(ve.getEndDate().getDate());

            // UID重複チェック実装時には引数にuid_plaを追加
            CoordinationForGoogleCalUtils.createMonthlySetDayOfWeekSchedule(
              ve,
              now,
              loginuser,
              rrl,
              schedule,
              startDate,
              endDate,
              to_d,
              start,
              interval,
              distribution);

            // 毎月・間隔有
          } else if (interval > 0
            && CoordinationForGoogleCalUtils.RRULE_FREQ_MONTHLY.equals(rrl
              .getRecur()
              .getFrequency())) {

            // 保存限度1年先の開始日時をセット
            Calendar start = Calendar.getInstance();
            start.setTime(ve.getStartDate().getDate());
            start.set(Calendar.YEAR, startDate.get(Calendar.YEAR) + 1);

            // 初期の開始・終了日時に戻す
            startDate.setTime(ve.getStartDate().getDate());
            endDate.setTime(ve.getEndDate().getDate());

            // UID重複チェック実装時には引数にuid_plaを追加
            CoordinationForGoogleCalUtils.createMonthlyIntervalSchedule(
              ve,
              now,
              loginuser,
              rrl,
              schedule,
              startDate,
              endDate,
              to_d,
              start,
              interval,
              distribution);

            // 毎年間隔有
          } else if (interval > 0
            && CoordinationForGoogleCalUtils.RRULE_FREQ_YEARLY.equals(rrl
              .getRecur()
              .getFrequency())) {

            // 保存限度5年先の開始日時をセット
            Calendar start = Calendar.getInstance();
            start.setTime(ve.getStartDate().getDate());
            start.set(Calendar.YEAR, startDate.get(Calendar.YEAR) + 5);

            // UID重複チェック実装時には引数にuid_plaを追加
            CoordinationForGoogleCalUtils.createYearlyIntervalSchedule(
              ve,
              now,
              loginuser,
              rrl,
              schedule,
              startDate,
              endDate,
              to_d,
              start,
              interval,
              distribution);

            // 毎年
          } else if (CoordinationForGoogleCalUtils.RRULE_FREQ_YEARLY.equals(rrl
            .getRecur()
            .getFrequency())) {

            // UID重複チェック実装時には引数にuid_plaを追加
            CoordinationForGoogleCalUtils.createYearlySchedule(
              ve,
              now,
              loginuser,
              rrl,
              schedule,
              startDate,
              endDate,
              to_d,
              distribution);

          } else {

            // 繰り返し間隔指定ありの年間終日スケジュールでのみ使用
            int interyear = 0;
            // UID重複チェック実装時には引数にuid_plaを追加
            CoordinationForGoogleCalUtils.insertSchedule(
              ve,
              now,
              loginuser,
              schedule,
              startDate,
              endDate,
              distribution,
              interyear);

          }

        }

      }

      Database.commit();

      // EXDATEがある場合dummyスケジュールを作成
      if (dummyList.size() != 0) {
        CoordinationForGoogleCalUtils.insertDummySchedule(loginuser, dummyList);
        Database.commit();

      }

    } catch (Exception ex) {
      Database.rollback();
      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)
   */
  @Override
  protected boolean updateFormData(RunData rundata, Context context,
      List<String> msgList) {
    try {

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

  /**
   * 現在選択されているタブを取得します。 <BR>
   * 
   * @return
   */
  public String getCurrentTab() {
    return currentTab;
  }

  public ALDateField getToDate() {
    return to_date;
  }

  public ALDateField getFromDate() {
    return from_date;
  }

  /**
   * 期間条件の単位 （"unit_day" or "unit_month"）
   */
  public String getTimeSelectFlg() {
    return time_select_flg;
  }

  public String getPeriodFlg() {
    return period_flg;
  }
}
