001package ezvcard.parameter;
002
003import ezvcard.property.ClientPidMap;
004
005/*
006 Copyright (c) 2012-2023, Michael Angstadt
007 All rights reserved.
008
009 Redistribution and use in source and binary forms, with or without
010 modification, are permitted provided that the following conditions are met: 
011
012 1. Redistributions of source code must retain the above copyright notice, this
013 list of conditions and the following disclaimer. 
014 2. Redistributions in binary form must reproduce the above copyright notice,
015 this list of conditions and the following disclaimer in the documentation
016 and/or other materials provided with the distribution. 
017
018 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
019 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
020 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
021 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
022 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
023 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
024 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
025 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
026 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
027 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028
029 The views and conclusions contained in the software and documentation are those
030 of the authors and should not be interpreted as representing official policies, 
031 either expressed or implied, of the FreeBSD Project.
032 */
033
034/**
035 * Represents a PID parameter value. A PID uniquely identifies a property. They
036 * are used when two different versions of the same vCard have to be merged
037 * together (called "synchronizing").
038 * @author Michael Angstadt
039 * @see <a href="http://tools.ietf.org/html/rfc6350#section-5.5">RFC 6350
040 * Section 5.5</a>
041 */
042public class Pid {
043        private final Integer localId, clientPidMapReference;
044
045        /**
046         * Creates a new PID.
047         * @param localId the local ID (cannot be null, must be positive)
048         * @param clientPidMapReference an integer that references the property's
049         * globally unique ID (optional, must be positive). It must match the first
050         * value in an existing {@link ClientPidMap} property
051         * @throws NullPointerException if local ID is null
052         */
053        public Pid(Integer localId, Integer clientPidMapReference) {
054                if (localId == null) {
055                        throw new NullPointerException("Local ID must not be null.");
056                }
057                this.localId = localId;
058                this.clientPidMapReference = clientPidMapReference;
059        }
060
061        /**
062         * Creates a new PID.
063         * @param localId the local ID (cannot be null, must be positive)
064         * @throws NullPointerException if local ID is null
065         */
066        public Pid(Integer localId) {
067                this(localId, null);
068        }
069
070        /**
071         * Gets the local ID
072         * @return the local ID
073         */
074        public Integer getLocalId() {
075                return localId;
076        }
077
078        /**
079         * Gets the reference to the property's globally unique ID (stored in a
080         * {@link ClientPidMap} property).
081         * @return the reference ID or null if not set
082         */
083        public Integer getClientPidMapReference() {
084                return clientPidMapReference;
085        }
086
087        /**
088         * Parses a string into a {@link Pid} object.
089         * @param value the string value (e.g. "1.2")
090         * @return the {@link Pid} object
091         * @throws NumberFormatException if there's a problem parsing the string
092         */
093        public static Pid valueOf(String value) {
094                int dot = value.indexOf('.');
095                String localIdStr, clientPidMapReferenceStr;
096                if (dot < 0) {
097                        localIdStr = value;
098                        clientPidMapReferenceStr = null;
099                } else {
100                        localIdStr = value.substring(0, dot);
101                        clientPidMapReferenceStr = (dot == value.length() - 1) ? null : value.substring(dot + 1);
102                }
103
104                Integer localId = Integer.valueOf(localIdStr);
105                Integer clientPidMapReference = (clientPidMapReferenceStr == null) ? null : Integer.valueOf(clientPidMapReferenceStr);
106                return new Pid(localId, clientPidMapReference);
107        }
108
109        @Override
110        public String toString() {
111                return (clientPidMapReference == null) ? Integer.toString(localId) : localId + "." + clientPidMapReference;
112        }
113
114        @Override
115        public int hashCode() {
116                final int prime = 31;
117                int result = 1;
118                result = prime * result + ((clientPidMapReference == null) ? 0 : clientPidMapReference.hashCode());
119                result = prime * result + localId.hashCode();
120                return result;
121        }
122
123        @Override
124        public boolean equals(Object obj) {
125                if (this == obj) return true;
126                if (obj == null) return false;
127                if (getClass() != obj.getClass()) return false;
128                Pid other = (Pid) obj;
129                if (clientPidMapReference == null) {
130                        if (other.clientPidMapReference != null) return false;
131                } else if (!clientPidMapReference.equals(other.clientPidMapReference)) return false;
132                if (!localId.equals(other.localId)) return false;
133                return true;
134        }
135}