001/* 002 * Shredzone Commons - pdb 003 * 004 * Copyright (C) 2009 Richard "Shred" Körber 005 * http://commons.shredzone.org 006 * 007 * This program is free software: you can redistribute it and/or modify 008 * it under the terms of the GNU Library General Public License as 009 * published by the Free Software Foundation, either version 3 of the 010 * License, or (at your option) any later version. 011 * 012 * This program is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 015 * GNU General Public License for more details. 016 * 017 * You should have received a copy of the GNU Library General Public License 018 * along with this program. If not, see <http://www.gnu.org/licenses/>. 019 */ 020package org.shredzone.commons.pdb.converter; 021 022import java.io.IOException; 023import java.util.Calendar; 024 025import org.shredzone.commons.pdb.PdbDatabase; 026import org.shredzone.commons.pdb.PdbFile; 027import org.shredzone.commons.pdb.appinfo.CategoryAppInfo; 028import org.shredzone.commons.pdb.appinfo.CategoryAppInfo.Category; 029import org.shredzone.commons.pdb.record.ScheduleRecord; 030import org.shredzone.commons.pdb.record.ScheduleRecord.Alarm.Unit; 031import org.shredzone.commons.pdb.record.ScheduleRecord.Repeat.Mode; 032 033/** 034 * An {@link Converter} that reads Calendar records. 035 * 036 * @see <a href="http://search.cpan.org/~bdfoy/p5-Palm-1.011/lib/Datebook.pm">Palm::Datebook</a> 037 */ 038public class ScheduleConverter implements Converter<ScheduleRecord, CategoryAppInfo> { 039 040 public static final int FLAG_ALARM = 0x4000; 041 public static final int FLAG_REPEAT = 0x2000; 042 public static final int FLAG_NOTE = 0x1000; 043 public static final int FLAG_EXCEPTIONS = 0x0800; 044 public static final int FLAG_DESCRIPTION = 0x0400; 045 public static final int FLAG_LOCATION = 0x0200; // only if creator is "PDat" 046 047 @Override 048 public boolean isAcceptable(PdbDatabase<ScheduleRecord, CategoryAppInfo> database) { 049 return "PDat".equals(database.getCreator()); 050 } 051 052 @Override 053 public ScheduleRecord convert(PdbFile reader, int record, int size, int attribute, 054 PdbDatabase<ScheduleRecord, CategoryAppInfo> database) throws IOException { 055 ScheduleRecord result = new ScheduleRecord(attribute); 056 if (result.isDelete()) { 057 return null; 058 } 059 060 Category cat = database.getAppInfo().getCategoryByIndex(result.getCategoryIndex()); 061 if (cat != null) { 062 result.setCategory(cat.getName()); 063 } 064 065 byte startHour = reader.readByte(); 066 byte startMinute = reader.readByte(); 067 byte endHour = reader.readByte(); 068 byte endMinute = reader.readByte(); 069 Calendar date = reader.readPackedDate(); 070 int flags = reader.readShort(); 071 072 if (startHour >= 0 && startMinute >= 0) { 073 result.setStartTime(new ScheduleRecord.ShortTime(startHour, startMinute)); 074 } 075 076 if (endHour >= 0 && endMinute >= 0) { 077 result.setEndTime(new ScheduleRecord.ShortTime(endHour, endMinute)); 078 } 079 080 result.setSchedule(new ScheduleRecord.ShortDate(date)); 081 082 if ((flags & FLAG_ALARM) != 0) { 083 int advance = reader.readByte(); 084 int unit = reader.readUnsignedByte(); 085 086 ScheduleRecord.Alarm.Unit alarmUnit; 087 switch (unit) { 088 case 0: alarmUnit = Unit.MINUTES; break; 089 case 1: alarmUnit = Unit.HOURS; break; 090 case 2: alarmUnit = Unit.DAYS; break; 091 default: throw new IOException("Unknown alarm unit: " + unit); 092 } 093 094 result.setAlarm(new ScheduleRecord.Alarm(advance, alarmUnit)); 095 } 096 097 if ((flags & FLAG_REPEAT) != 0) { 098 int type = reader.readUnsignedByte(); 099 reader.readByte(); 100 101 ScheduleRecord.Repeat.Mode repeatMode; 102 switch (type) { 103 case 1: repeatMode = Mode.DAILY; break; 104 case 2: repeatMode = Mode.WEEKLY; break; 105 case 3: repeatMode = Mode.MONTHLY_BY_DAY; break; 106 case 4: repeatMode = Mode.MONTHLY; break; 107 case 5: repeatMode = Mode.YEARLY; break; 108 default: throw new IOException("Unknown repeat mode: " + type); 109 } 110 111 ScheduleRecord.ShortDate endDate = null; 112 Calendar ending = reader.readPackedDate(); 113 if (ending != null) { 114 endDate = new ScheduleRecord.ShortDate(ending); 115 } 116 117 int frequency = reader.readUnsignedByte(); 118 int repeatOn = reader.readUnsignedByte(); 119 reader.readUnsignedByte(); 120 reader.readByte(); 121 122 boolean[] weeklyDays = new boolean[7]; 123 if (repeatMode == Mode.WEEKLY) { 124 for (int ix = 0; ix < weeklyDays.length; ix++) { 125 weeklyDays[ix] = (repeatOn & (1 << ix)) != 0; 126 } 127 } 128 129 int monthlyWeek = 0; 130 int monthlyDay = 0; 131 if (repeatMode == Mode.MONTHLY_BY_DAY) { 132 monthlyWeek = repeatOn / 7; 133 monthlyDay = repeatOn % 7; 134 } 135 136 result.setRepeat(new ScheduleRecord.Repeat( 137 repeatMode, 138 frequency, 139 endDate, 140 weeklyDays, 141 monthlyWeek, 142 monthlyDay 143 )); 144 } 145 146 if ((flags & FLAG_EXCEPTIONS) != 0) { 147 int numExceptions = reader.readUnsignedShort(); 148 for (int ix = 0; ix < numExceptions; ix++) { 149 Calendar excDate = reader.readPackedDate(); 150 result.getExceptions().add(new ScheduleRecord.ShortDate(excDate)); 151 } 152 } 153 154 if ((flags & FLAG_DESCRIPTION) != 0) { 155 result.setDescription(reader.readTerminatedString()); 156 } 157 158 if ((flags & FLAG_NOTE) != 0) { 159 result.setNote(reader.readTerminatedString()); 160 } 161 162 if ((flags & FLAG_LOCATION) != 0) { 163 result.setLocation(reader.readTerminatedString()); 164 } 165 166 return result; 167 } 168 169 @Override 170 public CategoryAppInfo convertAppInfo(PdbFile reader, int size, 171 PdbDatabase<ScheduleRecord, CategoryAppInfo> database) throws IOException { 172 CategoryAppInfo result = new CategoryAppInfo(); 173 reader.readCategories(result); 174 return result; 175 } 176 177}