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;
023
024import org.shredzone.commons.pdb.PdbDatabase;
025import org.shredzone.commons.pdb.PdbFile;
026import org.shredzone.commons.pdb.appinfo.AddressAppInfo;
027import org.shredzone.commons.pdb.record.AddressRecord;
028
029/**
030 * A {@link Converter} that reads Address records.
031 *
032 * @see <a href="http://search.cpan.org/~bdfoy/p5-Palm-1.011/lib/Address.pm">Palm::Address</a>
033 */
034public class AddressConverter implements Converter<AddressRecord, AddressAppInfo> {
035
036    private static final String[] COUNTRIES = { "AU", "AT", "BE", "BR", "CA",
037            "DK", "FI", "FR", "DE", "HK", "IS", "IE", "IT", "JP", "LU", "MX",
038            "NL", "NZ", "NO", "ES", "SE", "CH", "GB", "US", };
039
040    private static final AddressRecord.Label[] PHONE_LABELS = {
041        AddressRecord.Label.PHONE1, AddressRecord.Label.PHONE2,
042        AddressRecord.Label.PHONE3, AddressRecord.Label.PHONE4,
043        AddressRecord.Label.PHONE5, AddressRecord.Label.PHONE6,
044        AddressRecord.Label.PHONE7, AddressRecord.Label.PHONE8,
045    };
046
047    private static final int LABEL_LENGTH = 16;
048
049    @Override
050    public boolean isAcceptable(
051            PdbDatabase<AddressRecord, AddressAppInfo> database) {
052        return "AddressDB".equals(database.getName())
053               && "addr".equals(database.getCreator());
054    }
055
056    @Override
057    public AddressRecord convert(PdbFile reader, int record, int size, int attribute,
058            PdbDatabase<AddressRecord, AddressAppInfo> database)
059            throws IOException {
060
061        AddressRecord result = new AddressRecord(attribute);
062        if (result.isDelete()) {
063            return null;
064        }
065
066        int phoneFlags = reader.readInt();
067        int fieldMap = reader.readInt();
068        reader.readByte();
069
070        AddressRecord.Field[] fields = AddressRecord.Field.values();
071        AddressRecord.Label[] labels = AddressRecord.Label.values();
072        for (int ix = 0; ix < fields.length; ix++) {
073            if ((fieldMap & (1 << ix)) != 0) {
074                result.setLabel(fields[ix], mapLabel(labels[ix], phoneFlags));
075                result.setField(fields[ix], reader.readTerminatedString());
076            }
077        }
078
079        result.setDisplayPhone((phoneFlags >> 20) & 0x0F);
080
081        return result;
082    }
083
084    /**
085     * Maps a phone label to the one selected in the phone flags.
086     *
087     * @param label
088     *            Label to be mapped
089     * @param flags
090     *            Phone flags
091     * @return Mapped label
092     * @throws IOException
093     *             if the flags were not readable
094     */
095    private AddressRecord.Label mapLabel(AddressRecord.Label label, int flags)
096    throws IOException {
097        try {
098            switch (label) {
099                case PHONE1: return PHONE_LABELS[flags & 0x0F];
100                case PHONE2: return PHONE_LABELS[(flags >> 4) & 0x0F];
101                case PHONE3: return PHONE_LABELS[(flags >> 8) & 0x0F];
102                case PHONE4: return PHONE_LABELS[(flags >> 12) & 0x0F];
103                case PHONE5: return PHONE_LABELS[(flags >> 16) & 0x0F];
104                default: return label;
105            }
106        } catch (ArrayIndexOutOfBoundsException e) { //NOSONAR
107            throw new IOException("unknown mapping for label " + label);
108        }
109    }
110
111    @Override
112    public AddressAppInfo convertAppInfo(PdbFile reader, int size,
113            PdbDatabase<AddressRecord, AddressAppInfo> database)
114            throws IOException {
115        AddressAppInfo result = new AddressAppInfo();
116        reader.readCategories(result);
117
118        reader.readShort();
119        reader.readInt();
120
121        for (AddressRecord.Label label : AddressRecord.Label.values()) {
122            result.setLabel(label, reader.readTerminatedFixedString(LABEL_LENGTH));
123        }
124
125        int country = reader.readByte();
126        if (country >= 0 && country < COUNTRIES.length) {
127            result.setCountry(COUNTRIES[country]);
128        }
129
130        reader.readByte();
131
132        return result;
133    }
134
135}