package me.chyxion.tigon.shiro.model;

import java.util.Arrays;
import java.io.Serializable;
import org.apache.shiro.codec.Hex;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.util.ByteSource;

/**
 * @version 0.0.1
 * @since 0.0.1
 * @author Shaun Chyxion <br>
 * chyxion@163.com <br>
 * May 12, 2016 1:52:00 PM
 */
public class SerializableByteSource implements ByteSource, Serializable  {
    private static final long serialVersionUID = 1L;

    private byte[] bytes;
    private transient String cachedHex;
    private transient String cachedBase64;

    public SerializableByteSource() {

    }

    public SerializableByteSource(byte[] bytes) {
        this.bytes = bytes;
    }

    /**
     * Creates an instance using the sources bytes directly - it does not create a copy of the
     * argument's byte array.
     * @param source the source to use to populate the underlying byte array.
     */
    public SerializableByteSource(ByteSource source) {
        this(source.getBytes());
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public byte[] getBytes() {
        return this.bytes;
    }

    /**
     * @param bytes bytes
     */
    public void setBytes(byte[] bytes) {
        this.bytes = bytes;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isEmpty() {
        return this.bytes == null || this.bytes.length == 0;
    }
   
    /**
     * {@inheritDoc}
     */
    @Override
    public String toHex() {
        if (cachedHex == null) {
            cachedHex = Hex.encodeToString(getBytes());
        }
        return cachedHex;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String toBase64() {
        if (cachedBase64 == null) {
            cachedBase64 = Base64.encodeToString(getBytes());
        }
        return cachedBase64;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String toString() {
        return toBase64();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int hashCode() {
        if (bytes == null || bytes.length == 0) {
            return 0;
        }
        return Arrays.hashCode(bytes);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean equals(Object o) {
        if (o == this) {
            return true;
        }
        if (o instanceof ByteSource) {
            ByteSource bs = (ByteSource) o;
            return Arrays.equals(getBytes(), bs.getBytes());
        }
        return false;
    }
}
