001/**
002 * Copyright 2017, Digi International Inc.
003 *
004 * This Source Code Form is subject to the terms of the Mozilla Public
005 * License, v. 2.0. If a copy of the MPL was not distributed with this
006 * file, you can obtain one at http://mozilla.org/MPL/2.0/.
007 *
008 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 
009 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 
010 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 
011 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 
012 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
013 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
014 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
015 */
016package com.digi.xbee.api.models;
017
018import java.util.regex.Pattern;
019
020import com.digi.xbee.api.utils.HexUtils;
021
022/**
023 * This class represents an IMEI address used by cellular devices.
024 * 
025 * <p>This address is only applicable for:</p>
026 * <ul>
027 *   <li>Cellular</li>
028 * </ul>
029 * 
030 * @since 1.2.0
031 */
032public class XBeeIMEIAddress {
033
034        // Constants
035        private static final String ERROR_IMEI_NULL = "IMEI address cannot be null.";
036        private static final String ERROR_IMEI_TOO_LONG = "IMEI address cannot be longer than 8 bytes.";
037        private static final String ERROR_IMEI_INVALID = "Invalid IMEI address.";
038        
039        private static final int HASH_SEED = 23;
040        
041        private static final String IMEI_PATTERN = "^\\d{0,15}$";
042        
043        // Variables
044        private byte[] address;
045        
046        /**
047         * Class constructor. Instantiates a new object of type 
048         * {@code XBeeIMEIAddress} with the given parameter.
049         * 
050         * @param address The IMEI address as byte array.
051         * 
052         * @throws IllegalArgumentException If {@code address.length > 8}.
053         * @throws NullPointerException If {@code address == null}.
054         * 
055         * @see #XBeeIMEIAddress(String)
056         */
057        public XBeeIMEIAddress(byte[] address) {
058                if (address == null)
059                        throw new NullPointerException(ERROR_IMEI_NULL);
060                if (address.length > 8)
061                        throw new IllegalArgumentException(ERROR_IMEI_TOO_LONG);
062                
063                generateByteAddress(address);
064        }
065        
066        /**
067         * Class constructor. Instantiates a new object of type 
068         * {@code XBeeIMEIAddress} with the given parameters.
069         * 
070         * @param address The IMEI address as string.
071         * 
072         * @throws IllegalArgumentException If the given address doesn't match the
073         *                                  IMEI address pattern.
074         * @throws NullPointerException If {@code address == null}.
075         * 
076         * @see #XBeeIMEIAddress(byte[])
077         */
078        public XBeeIMEIAddress(String address) {
079                if (address == null)
080                        throw new NullPointerException(ERROR_IMEI_NULL);
081                
082                if (!Pattern.matches(IMEI_PATTERN, address))
083                        throw new IllegalArgumentException(ERROR_IMEI_INVALID);
084                
085                byte[] byteAddress = HexUtils.hexStringToByteArray(address);
086                
087                generateByteAddress(byteAddress);
088        }
089        
090        /**
091         * Generates and saves the IMEI byte address based on the given byte array.
092         * 
093         * @param byteAddress The byte array used to generate the final IMEI byte 
094         *                    address.
095         */
096        private void generateByteAddress(byte[] byteAddress) {
097                this.address = new byte[8];
098                
099                int diff = 8 - byteAddress.length;
100                for (int i = 0; i < diff; i++)
101                        this.address[i] = 0;
102                for (int i = diff; i < 8; i++)
103                        this.address[i] = byteAddress[i - diff];
104        }
105        
106        /**
107         * Retrieves the IMEI address value.
108         * 
109         * @return IMEI address value.
110         */
111        public String getValue() {
112                return HexUtils.byteArrayToHexString(address).substring(1);
113        }
114        
115        /*
116         * (non-Javadoc)
117         * @see java.lang.Object#equals(java.lang.Object)
118         */
119        @Override
120        public boolean equals(Object obj) {
121                if (obj == null)
122                        return false;
123                if (!(obj instanceof XBeeIMEIAddress))
124                        return false;
125                XBeeIMEIAddress addr = (XBeeIMEIAddress)obj;
126                return addr.getValue().equals(getValue());
127        }
128        
129        /*
130         * (non-Javadoc)
131         * @see java.lang.Object#hashCode()
132         */
133        @Override
134        public int hashCode() {
135                int hash = HASH_SEED;
136                for (byte b:getValue().getBytes())
137                        hash = hash * (hash + b);
138                return hash;
139        }
140        
141        /*
142         * (non-Javadoc)
143         * @see java.lang.Object#toString()
144         */
145        @Override
146        public String toString() {
147                return getValue();
148        }
149}