/*-------------------------------------------------------------------------
*
* Copyright (c) 2009-2014, PostgreSQL Global Development Group
*
*-------------------------------------------------------------------------
*/

package nl.topicus.jdbc.xa;

import java.util.Arrays;
import javax.transaction.xa.Xid;
import nl.topicus.jdbc.util.Base64;

public class RecoveredXid implements Xid {
  int formatId;
  byte[] globalTransactionId;
  byte[] branchQualifier;

  @Override
  public int getFormatId() {
    return formatId;
  }

  @Override
  public byte[] getGlobalTransactionId() {
    return globalTransactionId;
  }

  @Override
  public byte[] getBranchQualifier() {
    return branchQualifier;
  }

  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + Arrays.hashCode(branchQualifier);
    result = prime * result + formatId;
    result = prime * result + Arrays.hashCode(globalTransactionId);
    return result;
  }

  @Override
  public boolean equals(Object o) {
    if (o == this) {
      // optimization for the common case.
      return true;
    }

    if (!(o instanceof Xid)) {
      return false;
    }

    Xid other = (Xid) o;
    if (other.getFormatId() != formatId) {
      return false;
    }
    if (!Arrays.equals(globalTransactionId, other.getGlobalTransactionId())) {
      return false;
    }
    return Arrays.equals(branchQualifier, other.getBranchQualifier());
  }

  /**
   * This is for debugging purposes only
   */
  @Override
  public String toString() {
    return xidToString(this);
  }

  // --- Routines for converting xid to string and back.

  public static String xidToString(Xid xid) {
    return xid.getFormatId() + "_"
        + Base64.encodeBytes(xid.getGlobalTransactionId(), Base64.DONT_BREAK_LINES) + "_"
        + Base64.encodeBytes(xid.getBranchQualifier(), Base64.DONT_BREAK_LINES);
  }

  /**
   * @param s The string to convert
   * @return recovered xid, or null if s does not represent a valid xid encoded by the driver.
   */
  public static Xid stringToXid(String s) {
    RecoveredXid xid = new RecoveredXid();

    int a = s.indexOf('_');
    int b = s.lastIndexOf('_');

    if (a == b) {
      // this also catches the case a == b == -1.
      return null;
    }

    try {
      xid.formatId = Integer.parseInt(s.substring(0, a));
      xid.globalTransactionId = Base64.decode(s.substring(a + 1, b));
      xid.branchQualifier = Base64.decode(s.substring(b + 1));

      if (xid.globalTransactionId == null || xid.branchQualifier == null) {
        return null;
      }
    } catch (Exception ex) {
      return null; // Doesn't seem to be an xid generated by this driver.
    }

    return xid;
  }
}