/*
 * AccountEntry.java
 *
 * Status: Tentatively complete, minus some documentation
 */

package finance;

import java.math.BigDecimal;
import java.nio.ByteBuffer;
import java.util.*;

public class AccountEntry
 {
  /**
   * Comparator class to compare account entries based on the journal entries in
   * which they are recorded.
   */
  public static class Comparator<T extends AccountEntry> implements java.util.Comparator<T>
   {
    public int compare(T o1, T o2)
     { return JournalEntry.COMP_DATE.compare(o1.entry, o2.entry); }


    public boolean equals(Object obj)
     { return (obj != null) && (this.getClass() == obj.getClass()); }
   }


  /** Comparator to order account entries in the same order as their journal entries. */
  public static final Comparator<AccountEntry> COMPARATOR = new Comparator<AccountEntry>();


  /**
   * Converts an {@code AccountEntry} object into an array of bytes suitable for
   * writing to a file.
   *
   * @param obj the {@code AccountEntry} object to convert.
   *
   * @return an array of bytes representing the given {@code AccountEntry}
   * object.
   */
  public static byte[] convertToBytes(AccountEntry obj)
   {
    int size = 4;

    byte[] accountBytes = new byte[4];
    ByteBuffer.wrap(accountBytes).putInt(obj.account.getID());
    byte[] amountBytes = Amount.convertToBytes(obj.amount);
    size += amountBytes.length;

    byte[] bytes = new byte[size];
    System.arraycopy(accountBytes, 0, bytes, 0, 4);
    System.arraycopy(amountBytes, 0, bytes, 4, amountBytes.length);

    return bytes;
   }


  /**
   * Converts an array of bytes into an {@code AccountEntry} object.
   *
   * @param bytes the array of bytes to convert.
   *
   * @return an {@code AccountEntry} object constructed from the given array of
   * bytes.
   */
  public static AccountEntry convertFromBytes(byte[] bytes)
   {
    Account account = gui.Main.getDB().getAccountByID(ByteBuffer.wrap(bytes, 0, 4).getInt());

    byte[] amountBytes = new byte[bytes.length-4];
    System.arraycopy(bytes, 4, amountBytes, 0, amountBytes.length);

    return new AccountEntry(account, Amount.convertFromBytes(amountBytes));
   }


  /**
   * Returns an independent copy of the specified {@code AccountEntry}.
   *
   * @param entry the {@code AccountEntry} to copy.
   */
  public static AccountEntry copy(AccountEntry entry)
   {
    AccountEntry ret = new AccountEntry(entry.account, entry.amount);
    ret.entry = entry.entry;
    ret.balance = entry.balance;

    return ret;
   }


  /** The {@code Account} affected by this {@code AccountEntry}. */
  Account account = null;
  /** The {@code JournalEntry} in which this {@code AccountEntry} was entered. */
  JournalEntry entry = null;
  /** The {@code Amount} of this {@code AccountEntry}.*/
  Amount amount = Amount.ZERO;
  /** The resulting balance in the {@code Account} after this {@code AccountEntry}. */
  Amount balance = Amount.ZERO;


  /**
   * Constructs a new {@code AccountEntry}.
   *
   * @param account the {@code Account} affected by this {@code AccountEntry}.
   * @param amount the {@code Amount} of this {@code AccountEntry}.
   */
  public AccountEntry(Account account, Amount amount)
   {
    this.account = account;
    this.amount = amount;
   }


  /**
   * Gets the {@code Account} affected by this entry.
   */
  public Account getAccount()
   { return account; }


  /**
   * Gets the amount of this entry.
   */
  public Amount getAmount()
   { return amount; }


  public Amount getBalance()
   { return balance; }


  /**
   * Gets the date of this entry.
   */
  public Date getDate()
   { return entry.getDate(); }


  /**
   * Gets the name of the {@code Account} affected by this entry.  This is a
   * shortcut for {@code getAccount().getName()}.
   */
  public String getAccountName()
   { return account.getName(); }


  /**
   * Gets the normal balance of the {@code Account} affected by this entry.
   * This is a shortcut for {@code getAccount().getType().getNormalBalance()}.
   */
  public BalanceType getBalanceType()
   { return account.getType().getNormalBalance(); }


  /**
   * Gets the description of this entry.
   */
  public String getDescription()
   { return entry.getDescription(); }

  public String getDebit()
   {
    return getAmount(BalanceType.DEBIT);
   }

  public String getCredit()
   {
    return getAmount(BalanceType.CREDIT);
   }

  public String getBalanceString()
   {
    return String.format("%.2f", balance.getValue());
   }

  String getAmount(BalanceType t)
   {
    if(amount.getType() == t)
      return String.format("%.2f", amount.getValue());
    else
      return "";
   }
 }