/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2008, Open Source Geospatial Foundation (OSGeo)
* (C) 2014, Geomatys
*
* This library 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;
* version 2.1 of the License.
*
* This library 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.
*/
package org.geotoolkit.temporal.reference;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import org.apache.sis.internal.referencing.NilReferencingObject;
import org.apache.sis.referencing.AbstractIdentifiedObject;
import org.apache.sis.referencing.NamedIdentifier;
import org.apache.sis.util.ComparisonMode;
import org.geotoolkit.metadata.Citations;
import org.geotoolkit.temporal.object.DefaultInstant;
import org.geotoolkit.temporal.object.DefaultTemporalNode;
import org.opengis.metadata.Identifier;
import static org.opengis.referencing.IdentifiedObject.NAME_KEY;
import org.opengis.temporal.OrdinalEra;
import org.opengis.temporal.OrdinalReferenceSystem;
import org.opengis.temporal.TemporalNode;
import org.opengis.util.InternationalString;
/**
* Provides a reference to the ordinal era in which the instant occurs.
*
* @author Mehdi Sidhoum (Geomatys)
* @module
*
* @version 4.0
* @since 4.0
*/
@XmlType(name = "TimeOrdinalEra_Type", propOrder = {
"start",
"endd",
"member",
"groupp"
})
@XmlRootElement(name = "TimeOrdinalEra")
public class DefaultOrdinalEra extends AbstractIdentifiedObject implements OrdinalEra {
/**
* This is the temporal position at which the ordinal era began, if it is known.
*/
private Date begin;
/**
* This is the temporal position at which the ordinal era ended.
*/
private Date end;
/**
* {@linkplain OrdinalEra ordinal eras} that subdivide this ordinal era.
*/
private Collection<OrdinalEra> member;
/**
* Define an alone {@link OrdinalEra} implementation witch regroup other {@link OrdinalEra}.
*/
private DefaultOrdinalEra group;
/**
* Create a default implementation of {@link OrdinalEra} initialize by given parameters.
*
* <table class="ISO 19108">
* <caption>Recognized properties (non exhaustive list)</caption>
* <tr>
* <th>Property name</th>
* <th>Value type</th>
* <th>Returned by</th>
* </tr>
* <tr>
* <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td>
* <td>{@link org.opengis.referencing.ReferenceIdentifier} or {@link String}</td>
* <td>{@link #getName()}</td>
* </tr>
* <tr>
* <td>{@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td>
* <td>{@link org.opengis.referencing.ReferenceIdentifier} or {@link String}</td>
* <td>{@link #getIdentifiers() }</td>
* </tr>
* <tr>
* <td>{@value org.opengis.referencing.IdentifiedObject#REMARKS_KEY}</td>
* <td>{@link org.opengis.util.InternationalString}</td>
* <td>{@link #getRemarks()}</td>
* </tr>
* <tr>
* <td>{@value org.opengis.temporal.Calendar#REFERENCE_EVENT_KEY}</td>
* <td>{@link org.opengis.util.InternationalString}</td>
* <td>{@link #getReferenceEvent()}</td>
* </tr>
* </table>
*
* @param name The string that identifies the ordinal era within the {@linkplain OrdinalReferenceSystem TM_OrdinalReferenceSystem}.
* @param beginning The temporal position at which the ordinal era began, if it is known.
* @param end The temporal position at which the ordinal era ended.
*/
public DefaultOrdinalEra(final Map<String, ?> properties, final Date beginning, final Date end) {
super(properties);
if (! beginning.before(end))
throw new IllegalArgumentException("The beginning date of the OrdinalEra must be less than (i.e. earlier than) the end date of this OrdinalEra.");
this.begin = beginning;
this.end = end;
}
/**
* Create a default implementation of {@link OrdinalEra} initialize by given parameters.
*
* <table class="ISO 19108">
* <caption>Recognized properties (non exhaustive list)</caption>
* <tr>
* <th>Property name</th>
* <th>Value type</th>
* <th>Returned by</th>
* </tr>
* <tr>
* <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td>
* <td>{@link org.opengis.referencing.ReferenceIdentifier} or {@link String}</td>
* <td>{@link #getName()}</td>
* </tr>
* <tr>
* <td>{@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td>
* <td>{@link org.opengis.referencing.ReferenceIdentifier} or {@link String}</td>
* <td>{@link #getIdentifiers() }</td>
* </tr>
* <tr>
* <td>{@value org.opengis.referencing.IdentifiedObject#REMARKS_KEY}</td>
* <td>{@link org.opengis.util.InternationalString}</td>
* <td>{@link #getRemarks()}</td>
* </tr>
* <tr>
* <td>{@value org.opengis.temporal.Calendar#REFERENCE_EVENT_KEY}</td>
* <td>{@link org.opengis.util.InternationalString}</td>
* <td>{@link #getReferenceEvent()}</td>
* </tr>
* </table>
*
* @param name The string that identifies the ordinal era within the {@linkplain OrdinalReferenceSystem TM_OrdinalReferenceSystem}.
* @param beginning The temporal position at which the ordinal era began, if it is known.
* @param end The temporal position at which the ordinal era ended.
* @param member The {@linkplain OrdinalEra ordinal eras} that subdivide this ordinal era.
*/
public DefaultOrdinalEra(final Map<String, ?> properties, final Date beginning,
final Date end, final Collection<OrdinalEra> member) {
super(properties);
this.begin = beginning;
this.end = end;
this.member = member;
if (member != null)
for (OrdinalEra ordinalEra : this.member) {
((DefaultOrdinalEra) ordinalEra).setGroup(this);
}
}
/**
* Private constructor adapted for XML binding.
*/
private DefaultOrdinalEra() {
super(NilReferencingObject.INSTANCE);
}
/**
* Constructs a new instance initialized with the values from the specified metadata object.
* This is a <cite>shallow</cite> copy constructor, since the other metadata contained in the
* given object are not recursively copied.
*
* @param object The Calendar to copy values from, or {@code null} if none.
*
* @see #castOrCopy(Calendar)
*/
private DefaultOrdinalEra (final OrdinalEra object) {
super(object);
if (object != null) {
begin = object.getBegin();
end = object.getEnd();
member = object.getMember();
if (member != null)
for (OrdinalEra ordinalEra : member) {
((DefaultOrdinalEra) ordinalEra).setGroup(this);
}
}
}
/**
* Returns a Geotk implementation with the values of the given arbitrary implementation.
* This method performs the first applicable action in the following choices:
*
* <ul>
* <li>If the given object is {@code null}, then this method returns {@code null}.</li>
* <li>Otherwise if the given object is already an instance of
* {@code DefaultCalendar}, then it is returned unchanged.</li>
* <li>Otherwise a new {@code DefaultOrdinalEra} instance is created using the
* {@linkplain #DefaultOrdinalEra(OrdinalEra) copy constructor}
* and returned. Note that this is a <cite>shallow</cite> copy operation, since the other
* metadata contained in the given object are not recursively copied.</li>
* </ul>
*
* @param object The object to get as a Geotk implementation, or {@code null} if none.
* @return A Geotk implementation containing the values of the given object (may be the
* given object itself), or {@code null} if the argument was null.
*/
public static DefaultOrdinalEra castOrCopy(final OrdinalEra object) {
if (object == null || object instanceof DefaultOrdinalEra) {
return (DefaultOrdinalEra) object;
}
return new DefaultOrdinalEra(object);
}
/**
* Returns the temporal position at which the ordinal era began, if it is known.
*
* @return the temporal position at which the ordinal era began, if it is known.
*/
@Override
public Date getBegin() {
return begin;
}
/**
* Returns the temporal position at which the ordinal era ended.
*
* @return the temporal position at which the ordinal era ended.
*/
@Override
// @XmlElement(name = "end")
public Date getEnd() {
return end;
}
/**
* Returns the {@linkplain OrdinalEra ordinal eras} that subdivide this ordinal era.
*
* @return the {@linkplain OrdinalEra ordinal eras} that subdivide this ordinal era.
*/
@Override
@XmlElement(name = "member")
public Collection<OrdinalEra> getMember() {
return member;
}
/**
* Returns an alone {@link OrdinalEra} implementation witch regroup other {@link OrdinalEra}.
*
* @return an alone {@link OrdinalEra} implementation witch regroup other {@link OrdinalEra}.
*/
public DefaultOrdinalEra getGroup() {
return group;
}
/**
* Returns a {@link TemporalNode} create from {@link #begin} object, use for XML binding.
*
* @return a {@link TemporalNode} create from {@link #begin} object, use for XML binding.
*/
@XmlElement(name = "start")
private DefaultTemporalNode getStart() {
final Identifier iden = getName();
final Map<String, Object> instantProp = new HashMap<>();
instantProp.put(NAME_KEY, new NamedIdentifier(Citations.CRS, iden.getCode()+"_begin instant"));
final Map<String, Object> nodeProp = new HashMap<>();
nodeProp.put(NAME_KEY, new NamedIdentifier(Citations.CRS, iden.getCode()+"_start node"));
final DefaultTemporalNode start = new DefaultTemporalNode(nodeProp, new DefaultInstant(instantProp, begin), null, null);
return start;
}
/**
* Returns a {@link TemporalNode} create from {@link #end} object, use for XML binding.
*
* @return a {@link TemporalNode} create from {@link #end} object, use for XML binding.
*/
@XmlElement(name = "end")
private DefaultTemporalNode getEndd() {
final Identifier iden = getName();
final Map<String, Object> instantProp = new HashMap<>();
instantProp.put(NAME_KEY, new NamedIdentifier(Citations.CRS, iden.getCode()+"_end instant"));
final Map<String, Object> nodeProp = new HashMap<>();
nodeProp.put(NAME_KEY, new NamedIdentifier(Citations.CRS, iden.getCode()+"_end node"));
final DefaultTemporalNode start = new DefaultTemporalNode(nodeProp, new DefaultInstant(instantProp, begin), null, null);
return start;
}
/**
* Private method adapted for XML binding.
* Return {@code null} because GML specification do not specify any things about "group".
*
* @return {@code null}.
*/
@XmlElement(name = "group")
private DefaultOrdinalEra getGroupp() {
return null;
}
// /**
// * Set a new temporal position at which the ordinal era began, if it is known.
// *
// * @param beginning The new temporal position at which the ordinal era began, if it is known.
// */
// public void setBeginning(final Date beginning) {
// this.beginning = beginning;
// }
//
// /**
// * Set a new temporal position at which the ordinal era ended.
// *
// * @param end The new temporal position at which the ordinal era ended.
// */
// public void setEnd(final Date end) {
// this.end = end;
// }
//
/**
* Set a new {@link OrdinalEra} implementation witch regroup other {@link OrdinalEra}.
*
* @param group The new {@link OrdinalEra} implementation witch regroup other {@link OrdinalEra}.
*/
public void setGroup(final DefaultOrdinalEra group) {
this.group = group;
}
/**
* {@inheritDoc }
*/
@Override
public boolean equals(Object object, ComparisonMode mode) {
if (object instanceof DefaultOrdinalEra) {
final DefaultOrdinalEra that = (DefaultOrdinalEra) object;
return Objects.equals(this.begin, that.begin) &&
Objects.equals(this.end, that.end) &&
Objects.equals(this.member, that.member) &&
Objects.equals(this.group, that.group);
}
return false;
}
// /**
// * {@inheritDoc }
// */
// @Override
// public boolean equals(Object object, comp) {
// if (object instanceof DefaultOrdinalEra) {
// final DefaultOrdinalEra that = (DefaultOrdinalEra) object;
//
// return Objects.equals(this.beginning, that.beginning) &&
// Objects.equals(this.end, that.end) &&
// Objects.equals(this.member, that.member) &&
// Objects.equals(this.group, that.group);
// }
// return false;
// }
/**
* {@inheritDoc }
*/
@Override
protected long computeHashCode() {
int hash = 5;
hash = 37 * hash + (this.begin != null ? this.begin.hashCode() : 0);
hash = 37 * hash + (this.end != null ? this.end.hashCode() : 0);
hash = 37 * hash + (this.member != null ? this.member.hashCode() : 0);
hash = 37 * hash + (this.group != null ? this.group.hashCode() : 0);
return hash;
}
// /**
// * {@inheritDoc }
// */
// @Override
// public int hashCode() {
// int hash = 5;
// hash = 37 * hash + (this.beginning != null ? this.beginning.hashCode() : 0);
// hash = 37 * hash + (this.end != null ? this.end.hashCode() : 0);
// hash = 37 * hash + (this.member != null ? this.member.hashCode() : 0);
// hash = 37 * hash + (this.group != null ? this.group.hashCode() : 0);
// return hash;
// }
/**
* {@inheritDoc }
*/
@Override
public String toString() {
StringBuilder s = new StringBuilder(super.toString()).append('\n').append("OrdinalEra:").append('\n');
if (begin != null) {
s.append("beginning:").append(begin).append('\n');
}
if (end != null) {
s.append("end:").append(end).append('\n');
}
if (member != null) {
s.append("composition:").append(member).append('\n');
}
if (group != null) {
s.append("group:").append(group.getName().toString() ).append('\n');
}
return s.toString();
}
}