/*
* -----------------------------------------------------------------------
* Copyright © 2013-2016 Meno Hochschild, <http://www.menodata.de/>
* -----------------------------------------------------------------------
* This file (SPX.java) is part of project Time4J.
*
* Time4J is free software: You can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 2.1 of the License, or
* (at your option) any later version.
*
* Time4J 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Time4J. If not, see <http://www.gnu.org/licenses/>.
* -----------------------------------------------------------------------
*/
package net.time4j.calendar;
import net.time4j.PlainDate;
import net.time4j.PlainTime;
import net.time4j.base.MathUtils;
import net.time4j.history.HistoricEra;
import java.io.Externalizable;
import java.io.IOException;
import java.io.InvalidClassException;
import java.io.InvalidObjectException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.ObjectStreamException;
/**
* <p>Serialisierungsform für verschiedene Kalenderklassen. </p>
*
* @author Meno Hochschild
* @serial include
*/
final class SPX
implements Externalizable {
//~ Statische Felder/Initialisierungen ----------------------------
/** Serialisierungstyp. */
static final int HIJRI = 1;
/** Serialisierungstyp. */
static final int PERSIAN = 2;
/** Serialisierungstyp. */
static final int COPTIC = 3;
/** Serialisierungstyp. */
static final int ETHIOPIAN_DATE = 4;
/** Serialisierungstyp. */
static final int ETHIOPIAN_TIME = 5;
/** Serialisierungstyp. */
static final int MINGUO = 6;
/** Serialisierungstyp. */
static final int JULIAN = 7;
/** Serialisierungstyp. */
static final int THAI_SOLAR = 8;
private static final long serialVersionUID = 1L;
//~ Instanzvariablen ----------------------------------------------
private transient Object obj;
private transient int type;
//~ Konstruktoren -------------------------------------------------
/**
* <p>Benutzt in der Deserialisierung gemäß dem Kontrakt
* von {@code Externalizable}. </p>
*/
public SPX() {
super();
}
/**
* <p>Benutzt in der Serialisierung (writeReplace). </p>
*
* @param obj object to be serialized
* @param type serialization type (corresponds to type of obj)
*/
SPX(
Object obj,
int type
) {
super();
this.obj = obj;
this.type = type;
}
//~ Methoden ------------------------------------------------------
/**
* <p>Implementation method of interface {@link Externalizable}. </p>
*
* <p>The first byte contains the type of the object to be serialized.
* Then the data bytes follow in a possibly bit-compressed representation. </p>
*
* @serialData data layout see {@code writeReplace()}-method of object
* to be serialized
* @param out output stream
* @throws IOException in any case of IO-failures
*/
/*[deutsch]
* <p>Implementierungsmethode des Interface {@link Externalizable}. </p>
*
* <p>Das erste Byte enthält den Typ des zu serialisierenden Objekts.
* Danach folgen die Daten-Bits in einer vielleicht bit-komprimierten Darstellung. </p>
*
* @serialData data layout see {@code writeReplace()}-method of object
* to be serialized
* @param out output stream
* @throws IOException in any case of IO-failures
*/
@Override
public void writeExternal(ObjectOutput out)
throws IOException {
out.writeByte(this.type);
switch (this.type) {
case HIJRI:
this.writeHijri(out);
break;
case PERSIAN:
this.writePersian(out);
break;
case COPTIC:
this.writeCoptic(out);
break;
case ETHIOPIAN_DATE:
this.writeEthiopianDate(out);
break;
case ETHIOPIAN_TIME:
this.writeEthiopianTime(out);
break;
case MINGUO:
this.writeMinguo(out);
break;
case JULIAN:
this.writeJulian(out);
break;
case THAI_SOLAR:
this.writeThaiSolar(out);
break;
default:
throw new InvalidClassException("Unsupported calendar type.");
}
}
/**
* <p>Implementation method of interface {@link Externalizable}. </p>
*
* @param in input stream
* @throws IOException in any case of IO-failures
* @throws ClassNotFoundException if class loading fails
*/
/*[deutsch]
* <p>Implementierungsmethode des Interface {@link Externalizable}. </p>
*
* @param in input stream
* @throws IOException in any case of IO-failures
* @throws ClassNotFoundException if class loading fails
*/
@Override
public void readExternal(ObjectInput in)
throws IOException, ClassNotFoundException {
byte header = in.readByte();
switch (header) {
case HIJRI:
this.obj = this.readHijri(in);
break;
case PERSIAN:
this.obj = this.readPersian(in);
break;
case COPTIC:
this.obj = this.readCoptic(in);
break;
case ETHIOPIAN_DATE:
this.obj = this.readEthiopianDate(in);
break;
case ETHIOPIAN_TIME:
this.obj = this.readEthiopianTime(in);
break;
case MINGUO:
this.obj = this.readMinguo(in);
break;
case JULIAN:
this.obj = this.readJulian(in);
break;
case THAI_SOLAR:
this.obj = this.readThaiSolar(in);
break;
default:
throw new InvalidObjectException("Unknown calendar type.");
}
}
private Object readResolve() throws ObjectStreamException {
return this.obj;
}
private void writeHijri(ObjectOutput out)
throws IOException {
HijriCalendar hijri = (HijriCalendar) this.obj;
out.writeUTF(hijri.getVariant());
out.writeUTF(HijriCalendar.getVersion(hijri.getVariant()));
out.writeInt(hijri.getYear());
out.writeByte(hijri.getMonth().getValue());
out.writeByte(hijri.getDayOfMonth());
}
private HijriCalendar readHijri(ObjectInput in)
throws IOException, ClassNotFoundException {
String variant = in.readUTF();
String version = in.readUTF();
if (!HijriCalendar.getVersion(variant).equals(version)) {
throw new InvalidObjectException(
"Hijri calendar object with different data version not supported: " + variant + "/" + version);
}
int year = in.readInt();
int month = in.readByte();
int dom = in.readByte();
return HijriCalendar.of(variant, year, month, dom);
}
private void writePersian(ObjectOutput out)
throws IOException {
PersianCalendar persian = (PersianCalendar) this.obj;
out.writeInt(persian.getYear());
out.writeByte(persian.getMonth().getValue());
out.writeByte(persian.getDayOfMonth());
}
private PersianCalendar readPersian(ObjectInput in)
throws IOException, ClassNotFoundException {
int year = in.readInt();
int month = in.readByte();
int dom = in.readByte();
return PersianCalendar.of(year, month, dom);
}
private void writeCoptic(ObjectOutput out)
throws IOException {
CopticCalendar coptic = (CopticCalendar) this.obj;
out.writeInt(coptic.getYear());
out.writeByte(coptic.getMonth().getValue());
out.writeByte(coptic.getDayOfMonth());
}
private CopticCalendar readCoptic(ObjectInput in)
throws IOException, ClassNotFoundException {
int year = in.readInt();
int month = in.readByte();
int dom = in.readByte();
return CopticCalendar.of(year, month, dom);
}
private void writeEthiopianDate(ObjectOutput out)
throws IOException {
EthiopianCalendar ethio = (EthiopianCalendar) this.obj;
out.writeByte(ethio.getEra().ordinal());
out.writeInt(ethio.getYear());
out.writeByte(ethio.getMonth().getValue());
out.writeByte(ethio.getDayOfMonth());
}
private EthiopianCalendar readEthiopianDate(ObjectInput in)
throws IOException, ClassNotFoundException {
EthiopianEra era = EthiopianEra.values()[in.readByte()];
int year = in.readInt();
int month = in.readByte();
int dom = in.readByte();
return EthiopianCalendar.of(era, year, month, dom);
}
private void writeEthiopianTime(ObjectOutput out)
throws IOException {
EthiopianTime ethio = (EthiopianTime) this.obj;
int tod =
ethio.get(EthiopianTime.DIGITAL_HOUR_OF_DAY).intValue() * 3600
+ ethio.getMinute() * 60
+ ethio.getSecond();
out.writeInt(tod);
}
private EthiopianTime readEthiopianTime(ObjectInput in)
throws IOException, ClassNotFoundException {
int tod = in.readInt();
int second = tod % 60;
int minutes = tod / 60;
int minute = minutes % 60;
int hour24 = minutes / 60;
PlainTime time = PlainTime.of(hour24, minute, second);
return EthiopianTime.from(time);
}
private void writeMinguo(ObjectOutput out)
throws IOException {
MinguoCalendar mc = (MinguoCalendar) this.obj;
out.writeObject(mc.toISO());
}
private MinguoCalendar readMinguo(ObjectInput in)
throws IOException, ClassNotFoundException {
PlainDate iso = PlainDate.class.cast(in.readObject());
return iso.transform(MinguoCalendar.class);
}
private void writeJulian(ObjectOutput out)
throws IOException {
JulianCalendar jc = (JulianCalendar) this.obj;
out.writeInt(jc.getProlepticYear());
out.writeInt(jc.getMonth().getValue());
out.writeInt(jc.getDayOfMonth());
}
private JulianCalendar readJulian(ObjectInput in)
throws IOException, ClassNotFoundException {
int pyear = in.readInt();
int month = in.readInt();
int dom = in.readInt();
HistoricEra era = ((pyear >= 1) ? HistoricEra.AD : HistoricEra.BC);
int yearOfEra = ((pyear >= 1) ? pyear : MathUtils.safeSubtract(1, pyear));
return JulianCalendar.of(era, yearOfEra, month, dom);
}
private void writeThaiSolar(ObjectOutput out)
throws IOException {
ThaiSolarCalendar tsc = (ThaiSolarCalendar) this.obj;
out.writeObject(tsc.toISO());
}
private ThaiSolarCalendar readThaiSolar(ObjectInput in)
throws IOException, ClassNotFoundException {
PlainDate iso = PlainDate.class.cast(in.readObject());
return iso.transform(ThaiSolarCalendar.class);
}
}