/*
* Aipo is a groupware program developed by TOWN, Inc.
* Copyright (C) 2004-2015 TOWN, Inc.
* http://www.aipo.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.aimluck.eip.modules.screens;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletOutputStream;
import net.fortuna.ical4j.model.Date;
import net.fortuna.ical4j.model.DateList;
import net.fortuna.ical4j.model.DateTime;
import net.fortuna.ical4j.model.Recur;
import net.fortuna.ical4j.model.TimeZone;
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.property.CalScale;
import net.fortuna.ical4j.model.property.Description;
import net.fortuna.ical4j.model.property.ExDate;
import net.fortuna.ical4j.model.property.Location;
import net.fortuna.ical4j.model.property.Method;
import net.fortuna.ical4j.model.property.ProdId;
import net.fortuna.ical4j.model.property.RRule;
import net.fortuna.ical4j.model.property.Version;
import net.fortuna.ical4j.model.property.XProperty;
import net.fortuna.ical4j.util.UidGenerator;
import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
import org.apache.jetspeed.services.logging.JetspeedLogger;
import org.apache.turbine.modules.screens.RawScreen;
import org.apache.turbine.util.RunData;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.context.Context;
import com.aimluck.eip.common.ALEipConstants;
import com.aimluck.eip.common.ALEipUser;
import com.aimluck.eip.modules.actions.common.ALAction;
import com.aimluck.eip.schedule.ScheduleSearchResultData;
import com.aimluck.eip.schedule.ScheduleiCalSelectData;
import com.aimluck.eip.util.ALEipUtils;
/**
*
*/
public class ScheduleiCalScreen extends RawScreen implements ALAction {
/** logger */
private static final JetspeedLogger logger = JetspeedLogFactoryService
.getLogger(ScheduleiCalScreen.class.getName());
/**
* @param rundata
* @throws Exception
*/
@SuppressWarnings("unchecked")
@Override
protected void doOutput(RunData rundata) throws Exception {
ScheduleiCalSelectData selectData = new ScheduleiCalSelectData();
selectData.initField();
ALEipUser user = ALEipUtils.getALEipUser(rundata);
VelocityContext context = new VelocityContext();
ALEipUtils.setupContext(rundata, context);
// 前後3ヶ月の予定を取得
Calendar date = Calendar.getInstance();
date.add(Calendar.MONTH, -3);
date.set(Calendar.HOUR_OF_DAY, 0);
date.set(Calendar.MINUTE, 0);
date.set(Calendar.SECOND, 0);
date.set(Calendar.MILLISECOND, 0);
java.util.Date startDate = date.getTime();
date.add(Calendar.MONTH, 6);
java.util.Date endDate = date.getTime();
selectData.doViewList(this, rundata, context);
List<Object> resultList = selectData.getList();
Map<Integer, List<ScheduleSearchResultData>> dummyMaps =
selectData.getDummyMaps();
net.fortuna.ical4j.model.Calendar cal =
new net.fortuna.ical4j.model.Calendar();
cal.getProperties().add(new ProdId("-//TOWN, Inc. //Aipo //JP"));
cal.getProperties().add(Version.VERSION_2_0);
cal.getProperties().add(CalScale.GREGORIAN);
cal.getProperties().add(Method.PUBLISH);
cal.getProperties().add(
new XProperty("X-WR-CALNAME", user.getAliasName().getValue()));
TimeZoneRegistry registry =
TimeZoneRegistryFactory.getInstance().createRegistry();
TimeZone timezone = registry.getTimeZone("Asia/Tokyo");
VTimeZone tz = timezone.getVTimeZone();
cal.getComponents().add(tz);
for (Object result : resultList) {
ScheduleSearchResultData rd = (ScheduleSearchResultData) result;
java.util.Calendar cStart = Calendar.getInstance();
cStart.setTime(rd.getStartDate().getValue());
java.util.Calendar cEnd = Calendar.getInstance();
cEnd.setTime(rd.getEndDate().getValue());
Date dStart = null;
Date dEnd = null;
String ptn = rd.getPattern();
if ("S".equals(rd.getPattern())) {
cStart.add(Calendar.DATE, 1);
dStart = new Date(cStart.getTime());
if (cEnd.get(Calendar.HOUR_OF_DAY) == 0
&& cEnd.get(Calendar.MINUTE) == 0
&& cEnd.get(Calendar.SECOND) == 0) {
cEnd.add(Calendar.DATE, 2);
} else {
cEnd.add(Calendar.DATE, 1);
}
dEnd = new Date(cEnd.getTime());
} else {
dStart = new DateTime(cStart.getTime());
dEnd = new DateTime(cEnd.getTime());
}
java.util.Date currentStartDate = getRepeatStartDate(startDate, ptn);
Recur recur = null;
int count = 0;
// 毎日
if (ptn.charAt(0) == 'D') {
recur = new Recur(Recur.DAILY, null);
count = 1;
// 毎週
} else if (ptn.charAt(0) == 'W' && ptn.length() == 9) {
recur = new Recur(Recur.WEEKLY, null);
if (ptn.charAt(1) != '0') {
recur.getDayList().add(WeekDay.SU);
}
if (ptn.charAt(2) != '0') {
recur.getDayList().add(WeekDay.MO);
}
if (ptn.charAt(3) != '0') {
recur.getDayList().add(WeekDay.TU);
}
if (ptn.charAt(4) != '0') {
recur.getDayList().add(WeekDay.WE);
}
if (ptn.charAt(5) != '0') {
recur.getDayList().add(WeekDay.TH);
}
if (ptn.charAt(6) != '0') {
recur.getDayList().add(WeekDay.FR);
}
if (ptn.charAt(7) != '0') {
recur.getDayList().add(WeekDay.SA);
}
count = 8;
} else if (ptn.charAt(0) == 'W' && ptn.length() == 10) {
recur = new Recur(Recur.MONTHLY, null);
int offset = Character.getNumericValue(ptn.charAt(8));
if (ptn.charAt(1) != '0') {
recur.getDayList().add(new WeekDay(WeekDay.SU, offset));
}
if (ptn.charAt(2) != '0') {
recur.getDayList().add(new WeekDay(WeekDay.MO, offset));
}
if (ptn.charAt(3) != '0') {
recur.getDayList().add(new WeekDay(WeekDay.TU, offset));
}
if (ptn.charAt(4) != '0') {
recur.getDayList().add(new WeekDay(WeekDay.WE, offset));
}
if (ptn.charAt(5) != '0') {
recur.getDayList().add(new WeekDay(WeekDay.TH, offset));
}
if (ptn.charAt(6) != '0') {
recur.getDayList().add(new WeekDay(WeekDay.FR, offset));
}
if (ptn.charAt(7) != '0') {
recur.getDayList().add(new WeekDay(WeekDay.SA, offset));
}
count = 9;
} else if (ptn.charAt(0) == 'M') {
recur = new Recur(Recur.MONTHLY, null);
int mday;
if (ptn.substring(1, 3).equals("XX")) {
mday = -1;
} else {
mday = Integer.parseInt(ptn.substring(1, 3));
}
recur.getMonthList().addAll(
Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12));
recur.getMonthDayList().add(mday);
count = 3;
} else if (ptn.charAt(0) == 'Y') {
recur = new Recur(Recur.YEARLY, null);
int ymonth = Integer.parseInt(ptn.substring(1, 3));
int yday = Integer.parseInt(ptn.substring(3, 5));
recur.getMonthList().add(ymonth);
recur.getMonthDayList().add(yday);
count = 5;
}
if (count > 0) {
if (ptn.charAt(count) == 'L') {
if (endDate.compareTo(cStart.getTime()) < 0
|| cEnd.getTime().compareTo(startDate) < 0) {
// 期間指定の繰り返しスケジュールで、前後3ヶ月の範囲外のスケジュールは表示しない
continue;
}
if (endDate.compareTo(cEnd.getTime()) < 0) {
recur.setUntil(new DateTime(endDate));
} else {
recur.setUntil(new DateTime(cEnd.getTime()));
}
if (cStart.getTime().compareTo(startDate) < 0) {
int hour = cStart.get(Calendar.HOUR_OF_DAY);
int min = cStart.get(Calendar.MINUTE);
cStart.setTime(currentStartDate);
cStart.set(Calendar.HOUR_OF_DAY, hour);
cStart.set(Calendar.MINUTE, min);
hour = cEnd.get(Calendar.HOUR_OF_DAY);
min = cEnd.get(Calendar.MINUTE);
cEnd.setTime(currentStartDate);
cEnd.set(Calendar.HOUR_OF_DAY, hour);
cEnd.set(Calendar.MINUTE, min);
dStart = new DateTime(cStart.getTime());
dEnd = new DateTime(cEnd.getTime());
} else {
java.util.Date RepeatStartDate = getRepeatStartDate(dStart, ptn);
int hour = cStart.get(Calendar.HOUR_OF_DAY);
int min = cStart.get(Calendar.MINUTE);
cStart.setTime(RepeatStartDate);
cStart.set(Calendar.HOUR_OF_DAY, hour);
cStart.set(Calendar.MINUTE, min);
hour = cEnd.get(Calendar.HOUR_OF_DAY);
min = cEnd.get(Calendar.MINUTE);
cEnd.setTime(RepeatStartDate);
cEnd.set(Calendar.HOUR_OF_DAY, hour);
cEnd.set(Calendar.MINUTE, min);
dStart = new DateTime(cStart.getTime());
dEnd = new DateTime(cEnd.getTime());
}
} else {
recur.setUntil(new DateTime(endDate.getTime()));
int hour = cStart.get(Calendar.HOUR_OF_DAY);
int min = cStart.get(Calendar.MINUTE);
cStart.setTime(currentStartDate);
cStart.set(Calendar.HOUR_OF_DAY, hour);
cStart.set(Calendar.MINUTE, min);
hour = cEnd.get(Calendar.HOUR_OF_DAY);
min = cEnd.get(Calendar.MINUTE);
cEnd.setTime(currentStartDate);
cEnd.set(Calendar.HOUR_OF_DAY, hour);
cEnd.set(Calendar.MINUTE, min);
dStart = new DateTime(cStart.getTime());
dEnd = new DateTime(cEnd.getTime());
if (ptn.charAt(0) == 'Y') {
if (endDate.compareTo(cStart.getTime()) < 0
|| startDate.compareTo(cEnd.getTime()) > 0) {
recur = null;
dStart = null;
dEnd = null;
}
}
}
}
VEvent event = new VEvent(dStart, dEnd, rd.getName().getValue());
String place = rd.getPlace().getValue();
if (place != null && place.length() > 0) {
event.getProperties().add(new Location(place));
}
String description = rd.getDescription().getValue();
if (description != null && description.length() > 0) {
event.getProperties().add(new Description(description));
}
event.getProperties().add(
new UidGenerator(rd.getScheduleId().getValueAsString()).generateUid());
if (recur != null) {
event.getProperties().add(new RRule(recur));
if (dummyMaps.containsKey((int) rd.getScheduleId().getValue())) {
List<ScheduleSearchResultData> list =
dummyMaps.get((int) rd.getScheduleId().getValue());
DateList dateList = new DateList();
for (ScheduleSearchResultData dummy : list) {
java.util.Calendar dummyStart = Calendar.getInstance();
dummyStart.setTime(dummy.getStartDate().getValue());
dummyStart.set(Calendar.HOUR_OF_DAY, cStart
.get((Calendar.HOUR_OF_DAY)));
dummyStart.set(Calendar.MINUTE, cStart.get((Calendar.MINUTE)));
dateList.add(new DateTime(dummyStart.getTime()));
}
event.getProperties().add(new ExDate(dateList));
}
}
cal.getComponents().add(event);
}
ServletOutputStream out = null;
try {
out = rundata.getResponse().getOutputStream();
out.write(cal.toString().getBytes(ALEipConstants.DEF_CONTENT_ENCODING));
} catch (Throwable t) {
logger.error("[ScheduleiCalScreen]", t);
} finally {
if (out != null) {
try {
out.flush();
out.close();
} catch (Throwable ignore) {
}
}
}
}
private java.util.Date getRepeatStartDate(java.util.Date startDate, String ptn) {
try {
Calendar cal = Calendar.getInstance();
logger.error(startDate);
cal.setTime(startDate);
if (isView(cal, ptn)) {
return startDate;
} else {
cal.add(Calendar.DATE, 1);
return getRepeatStartDate(cal.getTime(), ptn);
}
} catch (Exception e) {
logger.error(e);
}
return new Date();
}
private boolean isView(Calendar cal, String ptn) {
boolean result = false;
// 毎日
if (ptn.charAt(0) == 'D') {
result = true;
// 毎週
} else if (ptn.charAt(0) == 'W') {
int dow = cal.get(Calendar.DAY_OF_WEEK);
int dowim = cal.get(Calendar.DAY_OF_WEEK_IN_MONTH);
if (ptn.charAt(8) == 'N'
|| ptn.charAt(8) == 'L'
|| dowim == Character.getNumericValue(ptn.charAt(8))) {
switch (dow) {
// 日
case Calendar.SUNDAY:
result = ptn.charAt(1) != '0';
break;
// 月
case Calendar.MONDAY:
result = ptn.charAt(2) != '0';
break;
// 火
case Calendar.TUESDAY:
result = ptn.charAt(3) != '0';
break;
// 水
case Calendar.WEDNESDAY:
result = ptn.charAt(4) != '0';
break;
// 木
case Calendar.THURSDAY:
result = ptn.charAt(5) != '0';
break;
// 金
case Calendar.FRIDAY:
result = ptn.charAt(6) != '0';
break;
// 土
case Calendar.SATURDAY:
result = ptn.charAt(7) != '0';
break;
default:
result = false;
break;
}
}
// 毎月
} else if (ptn.charAt(0) == 'M') {
int mday;
if (ptn.substring(1, 3).equals("XX")) {
mday = cal.getMaximum(Calendar.DATE);
} else {
mday = Integer.parseInt(ptn.substring(1, 3));
}
result = cal.get(Calendar.DATE) == mday;
} else if (ptn.charAt(0) == 'Y') {
int ymonth = Integer.parseInt(ptn.substring(1, 3));
int yday = Integer.parseInt(ptn.substring(3, 5));
result =
cal.get(Calendar.MONTH) == ymonth - 1 && cal.get(Calendar.DATE) == yday;
} else {
return true;
}
return result;
}
/**
* @param rundata
* @return
*/
@Override
protected String getContentType(RunData rundata) {
return "text/calendar";
}
/**
* @param obj
*/
@Override
public void setResultData(Object obj) {
}
/**
* @param obj
*/
@Override
public void addResultData(Object obj) {
}
/**
* @param objList
*/
@Override
public void setResultDataList(List<Object> objList) {
}
/**
* @param msg
*/
@Override
public void addErrorMessage(String msg) {
}
/**
* @param msgs
*/
@Override
public void addErrorMessages(List<String> msgs) {
}
/**
* @param msgs
*/
@Override
public void setErrorMessages(List<String> msgs) {
}
/**
* @param mode
*/
@Override
public void setMode(String mode) {
}
/**
* @return
*/
@Override
public String getMode() {
return null;
}
/**
* @param rundata
* @param context
*/
@Override
public void putData(RunData rundata, Context context) {
}
}