//////////////////////////////////////////////////
// JIST (Java In Simulation Time) Project
// Timestamp: <MacAddress.java Tue 2004/04/06 11:32:08 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.mac;

import java.io.Serializable;
import java.util.Arrays;

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

public class MacAddress implements Comparable, Serializable
{
  private static final long serialVersionUID = 1L;

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

  private static final int MAC_LEN = 6;

  /**
   * Broadcast Mac address. FF:FF:FF:FF:FF:FF
   */
  public static final MacAddress ANY = new MacAddress(-1);

  /**
   * Loopback Mac address. FF:FF:FF:FF:FF:FE
   */
  public static final MacAddress LOOP = new MacAddress(-2);

  /**
   * Null/invalid Mac address. 00:00:00:00:00:00
   */
  public static final MacAddress NULL = new MacAddress(0);

  //////////////////////////////////////////////////
  // internals
  //

  /**
   * address data.
   */
  private byte[] data;

  protected long addr;

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

  public MacAddress(String addr) {
    this(parseMAC(addr), 0);
 }

 public MacAddress(byte[] addr, int offset) {
    if (addr.length < MAC_LEN)
       throw new IllegalArgumentException(
          "MAC address has wrong number of bytes: " + addr.length);
    this.data = new byte[MAC_LEN];
    System.arraycopy(addr, offset, data, 0, MAC_LEN);

    if (Arrays.equals(this.data, ANY.data))
      this.addr = -1;
    else
      this.addr = (this.data[0]<<40) + (this.data[1]<<32) + (this.data[2]<<24)
        + (this.data[3]<<16) + (this.data[4]<<8) + (this.data[5]);
 }
  /**
   * Create a new Mac address object.
   *
   * @param addr address data
   */
  public MacAddress(long addr)
  {
    this.addr = addr;

    this.data = new byte[MAC_LEN];
    data[5] = (byte)(addr & 0xFF);
    data[4] = (byte)((addr >> 8) & 0xFF);
    data[3] = (byte)((addr >> 16) & 0xFF);
    data[2] = (byte)((addr >> 24) & 0xFF);
    data[1] = (byte)((addr >> 32) & 0xFF);
    data[0] = (byte)((addr >> 40) & 0xFF);
  }

  /**
   * Return whether this mac address is equal to another object.
   *
   * @param o object to test equality against
   * @return whether object provided is equal to this mac address
   */
  public boolean equals(Object o)
  {
    if(o==null) return false;
    if (getClass() != o.getClass())
      return false;
    if(!(o instanceof MacAddress)) return false;
    MacAddress ma = (MacAddress)o;
    return Arrays.equals(data,ma.data);
  }

  /** {@inheritDoc} */
  public String toString()
  {
    if(equals(ANY))
    {
      return "ANY";
    }
    else if(equals(LOOP))
    {
      return "LOOP";
    }

    StringBuffer sb = new StringBuffer();
    for (int i = 0; i < MAC_LEN; i++) {
       appendHexByte(sb, data[i]);
       if (i < MAC_LEN-1)
          sb.append(':');
    }
    return sb.toString();
  }

  /** {@inheritDoc} */
  public int compareTo(Object o)
  {
    if (!(o instanceof MacAddress)) throw new ClassCastException();
    MacAddress mac = (MacAddress)o;
    for (int i = 0; i < MAC_LEN; i++) {
      if (data[i] < mac.data[i])
        return -1;
      if (data[i] > mac.data[i])
        return 1;
    }
    return 0;
  }

  public byte[] getAddress() {
    return data;
  }

  public long getId(){
    return addr;
  }


  /**
   * Compute hash code for mac address.
   *
   * @return hash code of address
   */
  public int hashCode() {
    return Arrays.hashCode(data);
  }

  /**
   * Parses a MAC address on the format 'XX:XX:XX:XX:XX:XX'.
   */
  private static byte[] parseMAC(String mac) {
     String[] bytes = mac.split(":");
     if (bytes.length != MAC_LEN)
        throw new IllegalArgumentException("Bad MAC address: '" + mac + "'");

     byte[] data = new byte[MAC_LEN];
     for (int i = 0; i < bytes.length; i++) {
        int b = Integer.parseInt(bytes[i], 16);
        if (b < 0 || b > 255)
           throw new IllegalArgumentException("Bad MAC address: '"
                                              + mac + "'");
        data[i] = (byte)b;
     }

     return data;
  }

  private static StringBuffer appendHexByte(StringBuffer sb, byte b) {
     sb.append(Character.forDigit((b >> 4) & 0x0f, 16));
     sb.append(Character.forDigit(b & 0x0f, 16));
     return sb;
  }

} // class: MacAddress

