/*
 * Copyright (c) 2009, PostgreSQL Global Development Group
 * See the LICENSE file in the project root for more information.
 */

package org.postgresql.xa;

import org.postgresql.util.Base64;

// import org.checkerframework.checker.nullness.qual.Nullable;

import java.util.Arrays;

import javax.transaction.xa.Xid;

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

  RecoveredXid(int formatId, byte[] globalTransactionId, byte[] branchQualifier) {
    this.formatId = formatId;
    this.globalTransactionId = globalTransactionId;
    this.branchQualifier = branchQualifier;
  }

  public int getFormatId() {
    return formatId;
  }

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

  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;
  }

  public boolean equals(/* @Nullable */ 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;
    }
    if (!Arrays.equals(branchQualifier, other.getBranchQualifier())) {
      return false;
    }

    return true;
  }

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

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

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

  /**
   * @return recovered xid, or null if s does not represent a valid xid encoded by the driver.
   */
  static /* @Nullable */ Xid stringToXid(String s) {
    int a = s.indexOf("_");
    int b = s.lastIndexOf("_");

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

    try {
      int formatId = Integer.parseInt(s.substring(0, a));
      byte[] globalTransactionId = Base64.decode(s.substring(a + 1, b));
      byte[] branchQualifier = Base64.decode(s.substring(b + 1));
      return new RecoveredXid(formatId, globalTransactionId, branchQualifier);
    } catch (Exception ex) {
      // TODO: log warning
      return null; // Doesn't seem to be an xid generated by this driver.
    }
  }
}
