//////////////////////////////////////////////////
// JIST (Java In Simulation Time) Project
// Timestamp: <NetAddress.java Tue 2004/04/06 11:32:37 barr pompom.cs.cornell.edu>
//

// Copyright (C) 2004 by Cornell University
// All rights reserved.
// Refer to LICENSE for terms and conditions of use.

package jist.swans.net;

import jist.swans.misc.Pickle;

import java.io.Serializable;
import java.net.InetAddress;

/**
 * Contains a Network address.
 *
 * @author Rimon Barr &lt;barr+jist@cs.cornell.edu&gt;
 * @version $Id: NetAddress.java,v 1.18 2004/04/06 16:07:49 barr Exp $
 * @since SWANS1.0
 */

public class NetAddress implements Serializable
{
  private static final long serialVersionUID = 1L;

  //////////////////////////////////////////////////
  // constants
  //

  /**
   * Loopback network address.
   */
  public static final NetAddress LOCAL = new NetAddress(new byte[] { 127, 0, 0, 1 });

  /**
   * Null/invalid network address.
   */
  public static final NetAddress NULL = new NetAddress(new byte[] { -1, -1, -1, -2 });

  /**
   * Broadcast network address.
   */
  public static final NetAddress ANY = new NetAddress(new byte[] { -1, -1, -1, -1 });

  /**
   * Zero-length array of NetAddress type.
   */
  public static final NetAddress[] EMPTY_ARRAY = new NetAddress[0];

  //////////////////////////////////////////////////
  // address
  //

  /** address as int */
  private int addr;

  private transient InetAddress ip;

  /** ctor for hibernate */
  protected NetAddress() {}

  public NetAddress(String ip) {
    String[] s = ip.split("[.]");
    if (4 != s.length)
      throw new RuntimeException("invalid ip address!");
    for (int i=0; i < s.length; i++)
      this.addr = (this.addr << 8) + Integer.parseInt(s[i]);
  }

  /**
   * Create a new network address object.
   *
   * @param ip address data
   */
  public NetAddress(InetAddress ip)
  {
    this.addr = 0;
    if (null != ip)
      this.addr = byteArrayToInt(ip.getAddress(), 0);
  }

  /**
   * Create a new network address object.
   *
   * @param addr address data
   */
  public NetAddress(byte[] addr)
  {
    this.addr = byteArrayToInt(addr, 0);
  }

  public NetAddress(byte[] addr, int offset)
  {
    this.addr = byteArrayToInt(addr, offset);
  }

  /**
   * Create a new network address object.
   *
   * @param i address data
   */
  public NetAddress(int i)
  {
    this(intToByteArray(i));
  }

  /**
   * Return whether this network address is equal to another object.
   *
   * @param o object to test equality against
   * @return whether object provided is equal to this network address
   */
  public boolean equals(Object o)
  {
    if(this==o) return true;
    if(o==null) return false;
    if(!(o instanceof NetAddress)) return false;
    NetAddress na = (NetAddress)o;
    if(this.addr != na.addr) return false;
    return true;
  }

  /**
   * Return IP address information.
   *
   * @return IP address information
   */
  public InetAddress toIP()
  {
    if (null == ip) {
      ip = Pickle.arrayToInetAddress(intToByteArray(addr), 0);
    }
    return ip;
  }

  public int getId() {
    return addr;
  }

  public byte[] getBytes() {
    return intToByteArray(addr);
  }

  /**
   * Convert an integer into a byte array.
   *
   * @param i input integer to convert
   * @return corresponding byte array
   */
  private static byte[] intToByteArray(int i)
  {
    byte[] b = new byte[4];
    b[3] = (byte)(i & 0xff);
    b[2] = (byte)((i>>8) & 0xff);
    b[1] = (byte)((i>>16) & 0xff);
    b[0] = (byte)((i>>24) & 0xff);
    return b;
  }

  private static int byteArrayToInt(byte[] b, int offset)
  {
    int[] addr = Pickle.byteToIntArray(b, offset, 4);
    return addr[3] + (addr[2]<<8) + (addr[1]<<16) + (addr[0]<<24);
  }

  /** {@inheritDoc} */
  public String toString()
  {
    if(equals(ANY))
    {
      return "ANY";
    }
    else if(equals(LOCAL))
    {
      return "LOCAL";
    }
    else if(equals(NULL))
    {
      return "NULL";
    }
    else
    {
      byte[] b = intToByteArray(addr);
      int[] i = Pickle.byteToIntArray(b, 0, 4);
      String s= i[0]+"."+ i[1]+"."+ i[2]+"."+ i[3];
      return s;
    }
  }

  /**
   * Compute hash code for network address.
   *
   * @return hash code of address
   */
  public int hashCode() {
    return addr;
  }

} // class NetAddress

