/* JFox, the OpenSource J2EE Application Server
 *
 * Copyright (C) 2002 huihoo.com
 * Distributable under GNU LGPL license
 * See the GNU Lesser General Public License for more details.
 */

package org.jfox.tm;

import java.io.Serializable;
import java.net.InetAddress;
import java.net.UnknownHostException;
import javax.transaction.xa.Xid;

/**
 * 
 * @author <a href="mailto:young_yy@hotmail.com">Young Yang</a>
 */

public class XidImpl implements Xid, Serializable {
  private static volatile int hash = 1;

  public static final int FORMAT_ID = 0x0808;

  // ???? oracle ?????¨® Global Id ?? Branch Id ?¨´?? 64 ??????¡Á¨¦
  private byte[] globalId = new byte[Xid.MAXGTRIDSIZE];
  private byte[] branchId = new byte[Xid.MAXBQUALSIZE];

  private static String host;
  static {
    try {
      InetAddress local = InetAddress.getLocalHost();
      host = local.getHostName() + "-" + local.getHostAddress();
    }
    catch (UnknownHostException e) {
      host = "localhost-0.0.0.0";
    }
  }

  public XidImpl() {
    String xid = new StringBuffer().append(host).append("-").append(hash++).toString();
    if (xid.length() > Xid.MAXBQUALSIZE) {
      xid = xid.substring(xid.length()-Xid.MAXBQUALSIZE);
    }

    byte[] _globalId = xid.getBytes();
    if(_globalId.length > Xid.MAXGTRIDSIZE) {
      System.arraycopy(_globalId,0,globalId,_globalId.length-Xid.MAXGTRIDSIZE,Xid.MAXGTRIDSIZE);
    }
    else {
      System.arraycopy(xid.getBytes(),0,globalId,0,xid.getBytes().length);
    }
  }

  private XidImpl(byte[] _globalId, byte[] _branchId) {
    if(_globalId.length > Xid.MAXGTRIDSIZE) {
      System.arraycopy(_globalId,0,globalId,_globalId.length-Xid.MAXGTRIDSIZE,Xid.MAXGTRIDSIZE);
    }
    else {
      System.arraycopy(_globalId,0,globalId,0,_globalId.length);
    }
    if(_branchId.length > Xid.MAXBQUALSIZE) {
      System.arraycopy(_branchId,0,branchId,_branchId.length-Xid.MAXBQUALSIZE,Xid.MAXBQUALSIZE);
    }
    else {
      System.arraycopy(_branchId,0,branchId,0,_branchId.length);
    }

  }

  public static Xid createBranchXid(Xid xid, int branchId) {
    return new XidImpl(xid.getGlobalTransactionId(),Integer.toString(branchId).getBytes());
  }

  public int getFormatId() {
    return FORMAT_ID;
  }

  public byte[] getBranchQualifier() {
    return branchId;
  }

  public byte[] getGlobalTransactionId() {
    return globalId;
  }

  public int hashCode() {
    return globalId.hashCode() + branchId.hashCode();
  }

  public String toString() {
    return new StringBuffer().append(new String(globalId).trim()).append(":").append(new String(branchId).trim()).toString();
  }

  public boolean equals(Object obj) {
    if(!(obj instanceof XidImpl)) return false;

    XidImpl xid2 = (XidImpl) obj;
    if (FORMAT_ID == xid2.getFormatId()
            && java.util.Arrays.equals(branchId, xid2.getBranchQualifier())
            && java.util.Arrays.equals(globalId, xid2.getGlobalTransactionId())) {
      return true;
    }
    else {
      return false;
    }
  }

  public static void main(String[] args) {
    Xid xid = new XidImpl();
    Xid xid1 = (XidImpl.createBranchXid(xid,100));
    Xid xid2 = (XidImpl.createBranchXid(xid,100));
    System.out.println(xid);
    System.out.println(xid1);
    System.out.println(xid1.equals(xid2));
  }
}