/*
 * 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.modules.screens;

import java.io.ByteArrayOutputStream;
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 javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

import net.fortuna.ical4j.filter.Filter;
import net.fortuna.ical4j.filter.PeriodRule;
import net.fortuna.ical4j.model.Component;
import net.fortuna.ical4j.model.DateList;
import net.fortuna.ical4j.model.DateTime;
import net.fortuna.ical4j.model.Dur;
import net.fortuna.ical4j.model.ParameterList;
import net.fortuna.ical4j.model.Period;
import net.fortuna.ical4j.model.Recur;
import net.fortuna.ical4j.model.TimeZoneRegistry;
import net.fortuna.ical4j.model.TimeZoneRegistryFactory;
import net.fortuna.ical4j.model.WeekDay;
import net.fortuna.ical4j.model.component.VEvent;
import net.fortuna.ical4j.model.component.VTimeZone;
import net.fortuna.ical4j.model.parameter.TzId;
import net.fortuna.ical4j.model.parameter.Value;
import net.fortuna.ical4j.model.property.Clazz;
import net.fortuna.ical4j.model.property.Created;
import net.fortuna.ical4j.model.property.Description;
import net.fortuna.ical4j.model.property.DtEnd;
import net.fortuna.ical4j.model.property.DtStart;
import net.fortuna.ical4j.model.property.ExDate;
import net.fortuna.ical4j.model.property.LastModified;
import net.fortuna.ical4j.model.property.Location;
import net.fortuna.ical4j.model.property.Method;
import net.fortuna.ical4j.model.property.RRule;
import net.fortuna.ical4j.model.property.Summary;
import net.fortuna.ical4j.model.property.Uid;

import org.apache.cayenne.exp.Expression;
import org.apache.cayenne.exp.ExpressionFactory;
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.cayenne.om.portlet.EipTScheduleMap;
import com.aimluck.eip.orm.Database;
import com.aimluck.eip.orm.query.ResultList;
import com.aimluck.eip.orm.query.SelectQuery;
import com.aimluck.eip.util.ALEipUtils;

/**
 * iCalendar形式のスケジュールデータのエクスポートを処理するクラスです。 <br />
 * 
 */
public class CoordinationForGoogleCalICSExportScreen extends ALVelocityScreen {
  /** logger */
  private static final JetspeedLogger logger =
    JetspeedLogFactoryService
      .getLogger(CoordinationForGoogleCalICSExportScreen.class.getName());

  /**
   * 出力ファイル名（接頭辞）
   */
  public static String FILE_NAME = "";

  /**
   * 拡張子名
   */
  public static final String FILE_EXTENTION = ".ics";

  /**
   * 期間指定(month_select or day_select)
   */
  private String time_select_flg = null;

  /**
   * 期間指定の有効/無効
   */
  private String period_flg = null;

  /**
   * 期間指定(from)
   */
  private final ALDateField from_date = new ALDateField();

  /**
   * 期間指定(to)
   */
  private final ALDateField to_date = new ALDateField();

  // ２つ以上のAipoを使用する時対策
  // /** カスタマイズ画面での入力値 */
  // private String uid_pla;

  /** エラーメッセージ */
  private final List error_msg = new ArrayList();

  /**
   * @see org.apache.turbine.modules.screens.RawScreen#doOutput(org.apache.turbine.util.RunData)
   */
  @Override
  protected void doOutput(RunData rundata, Context context) throws Exception {
    ServletOutputStream out = null;

    try {

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

      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();
        }

      }

      // ２つ以上のAipo使用時の対策
      // 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;
      // }

      // エクスポートするスケジュールデータ文字列を取得
      String export_file =
        exportICSReader(rundata, context, period_flg, from_date, to_date);

      // 出力するファイル名の設定(今日の日付 + ログインユーザー名)
      Calendar today = Calendar.getInstance();
      FILE_NAME =
        ALEipUtils.getUserFullName(ALEipUtils.getUserId(rundata))
          + today.get(Calendar.YEAR)
          + "-"
          + (today.get(Calendar.MONTH) + 1)
          + "-"
          + today.get(Calendar.DAY_OF_MONTH)
          + FILE_EXTENTION;
      String fileName =
        new String(FILE_NAME.getBytes("Shift_JIS"), "ISO-8859-1");

      // ファイルの出力
      HttpServletResponse response = rundata.getResponse();
      response.setHeader("Content-disposition", "attachment; filename=\""
        + fileName
        + "\"");
      response.setHeader("Cache-Control", "no-cache");
      response.setHeader("Pragma", "no-cache");
      // ファイル内容の出力
      out = response.getOutputStream();

      // 期間指定間にスケジュールデータがない場合
      if (export_file == null) {

        String crlf = System.getProperty("line.separator");

        String bvcal = "BEGIN:VCALENDAR" + crlf;
        String prid =
          "PRODID:-//avanza Co.,Ltd.//Aipo5 Schedule Portlet//JP" + crlf;
        String calsc = "CALSCALE:GREGORIAN" + crlf;
        String ver = "VERSION:2.0" + crlf;
        String met = "METHOD:PUBLISH" + crlf;
        String evcal = "END:VCALENDAR" + crlf;

        out.write(bvcal.getBytes("UTF-8"));
        out.write(prid.getBytes("UTF-8"));
        out.write(calsc.getBytes("UTF-8"));
        out.write(ver.getBytes("UTF-8"));
        out.write(met.getBytes("UTF-8"));
        out.write(evcal.getBytes("UTF-8"));

      } else {

        out.write(export_file.getBytes("UTF-8"));

      }

      out.flush();
      out.close();

    } catch (Exception ex) {
      logger.error("[CoordinationForGoogleCalICSExportScreen] Exception.", ex);
      ALEipUtils.redirectDBError(rundata);
    }
  }

  protected String exportICSReader(RunData rundata, Context context,
      String period_flg, ALDateField from_date, ALDateField to_date) {
    try {

      // 出力するスケジュール文字列
      String calendarAsString = null;

      // カレンダーの生成 【固定値】
      net.fortuna.ical4j.model.Calendar calendar =
        new net.fortuna.ical4j.model.Calendar();
      calendar.getProperties().add(
        new net.fortuna.ical4j.model.property.ProdId(
          "-//avanza Co.,Ltd.//Aipo5 Schedule Portlet//JP"));
      calendar.getProperties().add(
        net.fortuna.ical4j.model.property.CalScale.GREGORIAN);
      calendar.getProperties().add(
        net.fortuna.ical4j.model.property.Version.VERSION_2_0);
      calendar.getProperties().add(new Method("PUBLISH"));

      // タイムゾーンの設定
      net.fortuna.ical4j.model.TimeZoneRegistry registry =
        net.fortuna.ical4j.model.TimeZoneRegistryFactory
          .getInstance()
          .createRegistry();
      net.fortuna.ical4j.model.TimeZone timezoneAsIcalTimeZone =
        registry.getTimeZone("Asia/Tokyo");
      net.fortuna.ical4j.model.component.VTimeZone tz =
        timezoneAsIcalTimeZone.getVTimeZone();

      SelectQuery<EipTSchedule> q = Database.query(EipTSchedule.class);

      // ログインユーザーのスケジュールを出力
      Expression exp =
        ExpressionFactory.matchExp(EipTSchedule.EIP_TSCHEDULE_MAPS_PROPERTY
          + "."
          + EipTScheduleMap.USER_ID_PROPERTY, ALEipUtils.getUserId(rundata));

      // IDはユーザーTYPEのIDを持つデータを出力
      Expression exp2 =
        ExpressionFactory.matchExp(EipTSchedule.EIP_TSCHEDULE_MAPS_PROPERTY
          + "."
          + EipTScheduleMap.TYPE_PROPERTY, "U");

      // EipTScheduleMapのSTATUSの値が"R"以外のデータを出力
      Expression exp3 =
        ExpressionFactory.noMatchExp(EipTSchedule.EIP_TSCHEDULE_MAPS_PROPERTY
          + "."
          + EipTScheduleMap.STATUS_PROPERTY, "R");

      // dummyスケジュール以外のデータを出力
      Expression exp4 =
        ExpressionFactory.noMatchExp(EipTSchedule.EIP_TSCHEDULE_MAPS_PROPERTY
          + "."
          + EipTScheduleMap.STATUS_PROPERTY, "D");

      q.setQualifier(exp.andExp(exp2).andExp(exp3).andExp(exp4));

      ResultList<EipTSchedule> list = q.getResultList();

      // 上記の条件のスケジュールデータを出力
      getExportSchedule(list, calendar, from_date, to_date, period_flg);

      // カレンダを文字列として書き出す
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      net.fortuna.ical4j.data.CalendarOutputter outputter =
        new net.fortuna.ical4j.data.CalendarOutputter();
      outputter.output(calendar, baos);

      calendarAsString = baos.toString("UTF-8");

      return calendarAsString;

    } catch (Exception ex) {
      logger.error("[CoordinationForGoogleCalICSExportScreen] Exception.", ex);
    }
    return null;
  }

  protected boolean getExportSchedule(List list,
      net.fortuna.ical4j.model.Calendar calendar, ALDateField from_date,
      ALDateField to_date, String period_flg) {

    try {

      // 期間指定した時間(from)
      Calendar fd = Calendar.getInstance();
      fd.setTime(from_date.getValue().getDate());
      DateTime from_d = new DateTime();
      from_d.setTime(fd.getTime().getTime());

      // 期間指定した時間(to)
      Calendar td = Calendar.getInstance();
      td.setTime(to_date.getValue().getDate());
      DateTime to_d = new DateTime();
      to_d.setTime(td.getTime().getTime());

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

        EipTSchedule e = (EipTSchedule) list.get(i);

        // タイムゾーンの設定
        TimeZoneRegistry registry =
          TimeZoneRegistryFactory.getInstance().createRegistry();

        net.fortuna.ical4j.model.TimeZone timezoneAsIcalTimeZone =
          registry.getTimeZone("Asia/Tokyo");

        VTimeZone tz = timezoneAsIcalTimeZone.getVTimeZone();

        // 日付のセット
        // 開始時間
        Date start_date = e.getStartDate();

        DateTime start_idate = new DateTime();
        start_idate.setTime(start_date.getTime());
        start_idate.setTimeZone(timezoneAsIcalTimeZone);

        // 期限有り(繰り返しパターンの末尾が"L"のスケジュール)の完了時間(Untilの時間)
        Date end_date = e.getEndDate();

        DateTime end_idate = new DateTime();
        end_idate.setTime(end_date.getTime());
        end_idate.setTimeZone(timezoneAsIcalTimeZone);

        // 期限有り(繰り返しパターンの末尾が"L"のスケジュール)の終了時間をセット
        // 開始時間の年月日+完了時間の時刻
        Calendar s_d = Calendar.getInstance();
        Calendar e_d = Calendar.getInstance();

        s_d.setTime(start_date);
        e_d.setTime(end_date);
        int year = s_d.get(Calendar.YEAR);
        int month = s_d.get(Calendar.MONTH);
        int day = s_d.get(Calendar.DAY_OF_MONTH);
        int hour = e_d.get(Calendar.HOUR_OF_DAY);
        int minute = e_d.get(Calendar.MINUTE);
        int second = e_d.get(Calendar.SECOND);

        Calendar r_e_d = Calendar.getInstance();
        r_e_d.set(year, month, day, hour, minute, second);
        DateTime r_e_id = new DateTime();
        r_e_id.setTime(r_e_d.getTime().getTime());
        r_e_id.setTimeZone(timezoneAsIcalTimeZone);

        // 予定作成日が何曜日であるかチェック
        Calendar r_s_d = Calendar.getInstance();
        r_s_d.setTime(start_date);
        int day_of_week = r_s_d.get(Calendar.DAY_OF_WEEK);// 1=日曜..7=土曜

        // 更新日
        Date modfied_date = e.getUpdateDate();
        DateTime modfied_idate = new DateTime();
        modfied_idate.setTime(modfied_date.getTime());
        modfied_idate.setTimeZone(timezoneAsIcalTimeZone);

        // 繰り返しパターン
        String repeat = e.getRepeatPattern();
        // 繰り返しパターンの一文字目を取得
        char r_f = repeat.charAt(0);
        // 繰り返しパターンの末尾文字を取得
        char r_l = repeat.charAt(repeat.length() - 1);

        // イベントの作成
        VEvent event = new VEvent();
        // タイムゾーン Asia/Tokyo 【固定値】
        event.getProperties().add(tz.getTimeZoneId());

        if ('S' == r_f || 'N' == r_f) {
          // 期間のみの予定および、単発のスケジュールは処理を行わない
        } else {
          // RRULEのセット
          RRule rrule = new RRule(getRepeatPatern(repeat, end_idate));
          // イベントにRRULEのセット
          event.getProperties().add(rrule);

        }

        // 件名・タイトル
        Summary summary = new Summary(e.getName());
        // イベントに件名・タイトルのセット
        event.getProperties().add(summary);

        // 終日予定の場合
        if ("S".equals(repeat)) {

          // パラメータリストの作成
          ParameterList datepara = new ParameterList();
          // パラメータリストにバリューをセット
          datepara.add(Value.DATE);

          // 終日の場合の開始時間
          // Date型
          net.fortuna.ical4j.model.Date start_idate_allday =
            new net.fortuna.ical4j.model.Date();
          start_idate_allday.setTime(start_date.getTime());

          // 終日の場合の終了時間
          // 例：Aipoで13日までの予定がGoogleカレンダーでは12日までとなるので１を加える
          e_d.set(Calendar.DAY_OF_MONTH, e_d.get(Calendar.DAY_OF_MONTH) + 1);
          net.fortuna.ical4j.model.Date end_idate_allday =
            new net.fortuna.ical4j.model.Date();
          end_idate_allday.setTime(e_d.getTime().getTime());

          // イベントに開始時間のセット
          DtStart dts = new DtStart(datepara, start_idate_allday);
          event.getProperties().add(dts);

          // イベントに終了時間のセット
          DtEnd dte = new DtEnd(datepara, end_idate_allday);
          event.getProperties().add(dte);

          // 終日予定以外
        } else {

          // 毎週の繰り返しスケジュール
          if (r_f == 'W') {

            // Aipoの開始日が予定の作成日になっており、繰り返しパターンにあわせて表示させる
            // 月曜
            if ('1' == repeat.charAt(2)) {

              if (day_of_week < Calendar.MONDAY) {
                int day_change = Calendar.MONDAY - day_of_week;
                s_d.set(Calendar.DAY_OF_MONTH, s_d.get(Calendar.DAY_OF_MONTH)
                  + day_change);
                DateTime s_id = new DateTime();
                s_id.setTime(s_d.getTime().getTime());
                s_id.setTimeZone(timezoneAsIcalTimeZone);

                // イベントに開始時間のセット
                event.getProperties().add(new DtStart(s_id));

                r_e_d.set(Calendar.DAY_OF_MONTH, r_e_d
                  .get(Calendar.DAY_OF_MONTH)
                  + day_change);
                DateTime r_e_id2 = new DateTime();
                r_e_id2.setTime(r_e_d.getTime().getTime());
                r_e_id2.setTimeZone(timezoneAsIcalTimeZone);

                // イベントに終了時間のセット
                event.getProperties().add(new DtEnd(r_e_id2));

              } else {

                // イベントに開始時間のセット
                event.getProperties().add(new DtStart(start_idate));

                if (r_l == 'L') {
                  // イベントに終了時間のセット
                  event.getProperties().add(new DtEnd(r_e_id));

                } else {

                  // イベントに終了時間のセット
                  event.getProperties().add(new DtEnd(end_idate));

                }

              }

              // 火曜
            } else if ('1' == repeat.charAt(3)) {

              if (day_of_week < Calendar.TUESDAY) {
                int day_change = Calendar.TUESDAY - day_of_week;
                s_d.set(Calendar.DAY_OF_MONTH, s_d.get(Calendar.DAY_OF_MONTH)
                  + day_change);
                DateTime s_id = new DateTime();
                s_id.setTime(s_d.getTime().getTime());
                s_id.setTimeZone(timezoneAsIcalTimeZone);

                // イベントに開始時間のセット
                event.getProperties().add(new DtStart(s_id));

                r_e_d.set(Calendar.DAY_OF_MONTH, r_e_d
                  .get(Calendar.DAY_OF_MONTH)
                  + day_change);
                DateTime r_e_id2 = new DateTime();
                r_e_id2.setTime(r_e_d.getTime().getTime());
                r_e_id2.setTimeZone(timezoneAsIcalTimeZone);

                // イベントに終了時間のセット
                event.getProperties().add(new DtEnd(r_e_id2));

              } else {

                // イベントに開始時間のセット
                event.getProperties().add(new DtStart(start_idate));

                if (r_l == 'L') {

                  // イベントに終了時間のセット
                  event.getProperties().add(new DtEnd(r_e_id));

                } else {

                  // イベントに終了時間のセット
                  event.getProperties().add(new DtEnd(end_idate));

                }

              }

              // 水曜
            } else if ('1' == repeat.charAt(4)) {

              if (day_of_week < Calendar.WEDNESDAY) {
                int day_change = Calendar.WEDNESDAY - day_of_week;
                s_d.set(Calendar.DAY_OF_MONTH, s_d.get(Calendar.DAY_OF_MONTH)
                  + day_change);
                DateTime s_id = new DateTime();
                s_id.setTime(s_d.getTime().getTime());
                s_id.setTimeZone(timezoneAsIcalTimeZone);

                // イベントに開始時間のセット
                event.getProperties().add(new DtStart(s_id));

                r_e_d.set(Calendar.DAY_OF_MONTH, r_e_d
                  .get(Calendar.DAY_OF_MONTH)
                  + day_change);
                DateTime r_e_id2 = new DateTime();
                r_e_id2.setTime(r_e_d.getTime().getTime());
                r_e_id2.setTimeZone(timezoneAsIcalTimeZone);

                // イベントに終了時間のセット
                event.getProperties().add(new DtEnd(r_e_id2));

              } else {

                // イベントに開始時間のセット
                event.getProperties().add(new DtStart(start_idate));

                if (r_l == 'L') {

                  // イベントに終了時間のセット
                  event.getProperties().add(new DtEnd(r_e_id));

                } else {

                  // イベントに終了時間のセット
                  event.getProperties().add(new DtEnd(end_idate));

                }

              }

              // 木曜
            } else if ('1' == repeat.charAt(5)) {

              if (day_of_week < Calendar.THURSDAY) {

                int day_change = Calendar.THURSDAY - day_of_week;
                s_d.set(Calendar.DAY_OF_MONTH, s_d.get(Calendar.DAY_OF_MONTH)
                  + day_change);
                DateTime s_id = new DateTime();
                s_id.setTime(s_d.getTime().getTime());
                s_id.setTimeZone(timezoneAsIcalTimeZone);

                // イベントに開始時間のセット
                event.getProperties().add(new DtStart(s_id));

                r_e_d.set(Calendar.DAY_OF_MONTH, r_e_d
                  .get(Calendar.DAY_OF_MONTH)
                  + day_change);
                DateTime r_e_id2 = new DateTime();
                r_e_id2.setTime(r_e_d.getTime().getTime());
                r_e_id2.setTimeZone(timezoneAsIcalTimeZone);

                // イベントに終了時間のセット
                event.getProperties().add(new DtEnd(r_e_id2));

              } else {

                // イベントに開始時間のセット
                event.getProperties().add(new DtStart(start_idate));

                if (r_l == 'L') {

                  // イベントに終了時間のセット
                  event.getProperties().add(new DtEnd(r_e_id));

                } else {

                  // イベントに終了時間のセット
                  event.getProperties().add(new DtEnd(end_idate));

                }

              }

              // 金曜
            } else if ('1' == repeat.charAt(6)) {

              if (day_of_week < Calendar.FRIDAY) {

                int day_change = Calendar.FRIDAY - day_of_week;
                s_d.set(Calendar.DAY_OF_MONTH, s_d.get(Calendar.DAY_OF_MONTH)
                  + day_change);
                DateTime s_id = new DateTime();
                s_id.setTime(s_d.getTime().getTime());
                s_id.setTimeZone(timezoneAsIcalTimeZone);

                // イベントに開始時間のセット
                event.getProperties().add(new DtStart(s_id));

                r_e_d.set(Calendar.DAY_OF_MONTH, r_e_d
                  .get(Calendar.DAY_OF_MONTH)
                  + day_change);
                DateTime r_e_id2 = new DateTime();
                r_e_id2.setTime(r_e_d.getTime().getTime());
                r_e_id2.setTimeZone(timezoneAsIcalTimeZone);

                // イベントに終了時間のセット
                event.getProperties().add(new DtEnd(r_e_id2));

              } else {

                // イベントに開始時間のセット
                event.getProperties().add(new DtStart(start_idate));

                if (r_l == 'L') {

                  // イベントに終了時間のセット
                  event.getProperties().add(new DtEnd(r_e_id));

                } else {

                  // イベントに終了時間のセット
                  event.getProperties().add(new DtEnd(end_idate));

                }

              }

              // 土曜
            } else if ('1' == repeat.charAt(7)) {

              if (day_of_week < Calendar.SATURDAY) {
                int day_change = Calendar.SATURDAY - day_of_week;
                s_d.set(Calendar.DAY_OF_MONTH, s_d.get(Calendar.DAY_OF_MONTH)
                  + day_change);
                DateTime s_id = new DateTime();
                s_id.setTime(s_d.getTime().getTime());
                s_id.setTimeZone(timezoneAsIcalTimeZone);

                // イベントに開始時間のセット
                event.getProperties().add(new DtStart(s_id));
                r_e_d.set(Calendar.DAY_OF_MONTH, r_e_d
                  .get(Calendar.DAY_OF_MONTH)
                  + day_change);
                DateTime r_e_id2 = new DateTime();
                r_e_id2.setTime(r_e_d.getTime().getTime());
                r_e_id2.setTimeZone(timezoneAsIcalTimeZone);

                // イベントに終了時間のセット
                event.getProperties().add(new DtEnd(r_e_id2));

              } else {

                // イベントに開始時間のセット
                event.getProperties().add(new DtStart(start_idate));

                if (r_l == 'L') {

                  // イベントに終了時間のセット
                  event.getProperties().add(new DtEnd(r_e_id));

                } else {

                  // イベントに終了時間のセット
                  event.getProperties().add(new DtEnd(end_idate));

                }

              }

            } else {

              // イベントに開始時間のセット
              event.getProperties().add(new DtStart(start_idate));

              if (r_l == 'L') {

                // イベントに終了時間のセット
                event.getProperties().add(new DtEnd(r_e_id));

              } else {

                // イベントに終了時間のセット
                event.getProperties().add(new DtEnd(end_idate));

              }

            }

            // 月毎の繰り返し
          } else if (r_f == 'M') {

            // 毎月何日に繰り返すかを取得
            String bymonthday =
              "" + repeat.charAt(1) + "" + "" + repeat.charAt(2) + "";
            int by_month_day = Integer.valueOf(bymonthday).intValue();

            // 開始日の設定
            if (by_month_day < s_d.get(Calendar.DAY_OF_MONTH)) {

              s_d.set(Calendar.MONTH, s_d.get(Calendar.MONTH) + 1);

            }

            s_d.set(Calendar.DAY_OF_MONTH, by_month_day);
            DateTime s_id = new DateTime();
            s_id.setTime(s_d.getTime().getTime());
            s_id.setTimeZone(timezoneAsIcalTimeZone);

            // イベントに開始時間のセット
            event.getProperties().add(new DtStart(s_id));

            if (by_month_day < r_e_d.get(Calendar.DAY_OF_MONTH)) {

              r_e_d.set(Calendar.MONTH, r_e_d.get(Calendar.MONTH) + 1);

            }

            r_e_d.set(Calendar.DAY_OF_MONTH, by_month_day);
            DateTime r_e_id2 = new DateTime();
            r_e_id2.setTime(r_e_d.getTime().getTime());
            r_e_id2.setTimeZone(timezoneAsIcalTimeZone);

            // イベントに終了時間のセット
            event.getProperties().add(new DtEnd(r_e_id2));

          } else {

            // イベントに開始時間のセット
            event.getProperties().add(new DtStart(start_idate));

            if (r_l == 'L') {

              // イベントに終了時間のセット
              event.getProperties().add(new DtEnd(r_e_id));

            } else {

              // イベントに終了時間のセット
              event.getProperties().add(new DtEnd(end_idate));
            }
          }
        }

        // 作成日のセット
        DateTime create_idate = new DateTime();
        create_idate.setTime(e.getCreateDate().getTime());
        create_idate.setTimeZone(timezoneAsIcalTimeZone);
        event.getProperties().add(new Created(create_idate));

        // 公開フラグ
        if ("C".equals(e.getPublicFlag())) {
          event.getProperties().add(new Clazz("PRIVATE"));
        } else {
          event.getProperties().add(new Clazz("PUBLIC"));
        }

        // 場所
        event.getProperties().add(new Location(e.getPlace()));

        // コメント
        event.getProperties().add(new Description(e.getNote()));

        // //UID
        // try {
        // String uid = CoordinationForGoogleCalUtils.crypt(uid_pla);

        event.getProperties().add(
          new Uid("Aipo:" + "avanza:" + e.getScheduleId().toString() + ""));

        // } catch (NoSuchAlgorithmException e1) {
        // // 自動生成された catch ブロック
        // e1.printStackTrace();
        // }

        // 最終更新日時
        event.getProperties().add(new LastModified(modfied_idate));

        // dummyチェック
        int dmy_check = e.getScheduleId();
        SelectQuery<EipTSchedule> q = Database.query(EipTSchedule.class);
        Expression exp =
          ExpressionFactory.matchExp(EipTSchedule.PARENT_ID_PROPERTY, ""
            + dmy_check
            + "");
        Expression exp2 =
          ExpressionFactory.matchExp(EipTSchedule.NAME_PROPERTY, "dummy");
        q.setQualifier(exp.andExp(exp2));
        ResultList<EipTSchedule> dummyList = q.getResultList();

        if (dummyList.size() != 0) {

          DateList datelist = new DateList();

          for (int j = 0; j < dummyList.size(); j++) {

            EipTSchedule dummy = dummyList.get(j);

            SelectQuery<EipTSchedule> qu = Database.query(EipTSchedule.class);
            Expression exp3 =
              ExpressionFactory.matchDbExp(
                EipTSchedule.SCHEDULE_ID_PK_COLUMN,
                dmy_check);
            qu.setQualifier(exp3);
            ResultList<EipTSchedule> parent = qu.getResultList();

            EipTSchedule parent_schedule = parent.get(0);

            // ペアレントスケジュールの開始日時
            Calendar parent_time = Calendar.getInstance();
            parent_time.setTime(parent_schedule.getStartDate());

            // dummyスケジュールの開始日時
            Calendar dummy_time = Calendar.getInstance();
            dummy_time.setTime(dummy.getStartDate());

            // dummyスケジュールの日付 + ペアレントスケジュールの時刻 をセット
            dummy_time.set(Calendar.HOUR_OF_DAY, parent_time
              .get(Calendar.HOUR_OF_DAY));
            dummy_time.set(Calendar.MINUTE, parent_time.get(Calendar.MINUTE));

            DateTime dummy_idate = new DateTime();
            dummy_idate.setTime(dummy_time.getTime().getTime());
            dummy_idate.setTimeZone(timezoneAsIcalTimeZone);

            datelist.add(dummy_idate);

          }
          if (datelist.size() != 0) {
            // パラメータリストの作成
            ParameterList datepara = new ParameterList();
            // パラメータリストにバリューをセット
            datepara.add(new TzId("Asia/Tokyo"));
            ExDate ex = new ExDate(datepara, datelist);
            event.getProperties().add(ex);
          }
        }

        // カレンダにイベントを追加
        calendar.getComponents().add(event);

      }

      List con = new ArrayList();
      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);

      }

      calendar.getComponents().clear();
      for (int i = 0; i < con.size(); i++) {
        VEvent ve = (VEvent) con.get(i);
        calendar.getComponents().add(ve);
      }

    } catch (Exception ex) {
      logger.error("[CoordinationForGoogleCalICSExportScreen] Exception.", ex);

    }

    return true;
  }

  /**
   * 繰り返しパターンを出力します。 <BR>
   * 
   */
  public static Recur getRepeatPatern(String repeat,
      net.fortuna.ical4j.model.DateTime end_idate) {

    try {

      char r_f = repeat.charAt(0);
      char r_l = repeat.charAt(repeat.length() - 1);
      char DAILY_REPEAT = 'D';
      char WEEKLY_REPEAT = 'W';
      char MONTHLY_REPEAT = 'M';

      if (DAILY_REPEAT == r_f) {
        Recur recur = new Recur("FREQ=DAILY");

        if ('L' == r_l) {

          recur.setUntil(end_idate);

        }

        // RRULEのWKSTにあたる処理 【固定値】
        recur.setWeekStartDay(WeekDay.MO.getDay());
        return recur;

      } else if (WEEKLY_REPEAT == r_f) {

        Recur recur = new Recur("FREQ=WEEKLY");

        if ('1' == repeat.charAt(1)) {

          recur.getDayList().add(WeekDay.SU);

        }
        if ('1' == repeat.charAt(2)) {

          recur.getDayList().add(WeekDay.MO);

        }
        if ('1' == repeat.charAt(3)) {

          recur.getDayList().add(WeekDay.TU);

        }
        if ('1' == repeat.charAt(4)) {

          recur.getDayList().add(WeekDay.WE);

        }
        if ('1' == repeat.charAt(5)) {

          recur.getDayList().add(WeekDay.TH);

        }
        if ('1' == repeat.charAt(6)) {

          recur.getDayList().add(WeekDay.FR);

        }
        if ('1' == repeat.charAt(7)) {

          recur.getDayList().add(WeekDay.SA);

        }
        if ('L' == r_l) {

          recur.setUntil(end_idate);

        }

        // RRULEのWKSTにあたる処理 【固定値】
        recur.setWeekStartDay(WeekDay.MO.getDay());
        return recur;

      } else if (MONTHLY_REPEAT == r_f) {
        Recur recur = new Recur("FREQ=MONTHLY");
        String bymonthday =
          "" + repeat.charAt(1) + "" + "" + repeat.charAt(2) + "";
        int by_month_day = Integer.valueOf(bymonthday).intValue();

        if ('L' == r_l) {

          recur.setUntil(end_idate);

        }

        // RRULEのWKSTにあたる処理 【固定値】
        recur.setWeekStartDay(WeekDay.MO.getDay());
        return recur;

      }

    } catch (Exception ex) {
      logger.error("[CoordinationForGoogleCalICSExportScreen] Exception.", ex);
    }
    return null;
  }

  public List getErrorMsg() {
    return error_msg;
  }

}
