package com.googlecode.mp4parser.util;

import com.coremedia.iso.IsoTypeReader;
import com.coremedia.iso.IsoTypeWriter;

import java.nio.ByteBuffer;

/**
 * Transformation Matrix as used in <code>Track-</code> and <code>MovieHeaderBox</code>.
 */
public class Matrix {
    double u, v, w;
    double a, b, c, d, tx, ty;

    public Matrix(double a, double b, double c, double d, double u, double v, double w, double tx, double ty) {
        this.u = u;
        this.v = v;
        this.w = w;
        this.a = a;
        this.b = b;
        this.c = c;
        this.d = d;
        this.tx = tx;
        this.ty = ty;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Matrix matrix = (Matrix) o;

        if (Double.compare(matrix.a, a) != 0) return false;
        if (Double.compare(matrix.b, b) != 0) return false;
        if (Double.compare(matrix.c, c) != 0) return false;
        if (Double.compare(matrix.d, d) != 0) return false;
        if (Double.compare(matrix.tx, tx) != 0) return false;
        if (Double.compare(matrix.ty, ty) != 0) return false;
        if (Double.compare(matrix.u, u) != 0) return false;
        if (Double.compare(matrix.v, v) != 0) return false;
        if (Double.compare(matrix.w, w) != 0) return false;

        return true;
    }

    @Override
    public int hashCode() {
        int result;
        long temp;
        temp = Double.doubleToLongBits(u);
        result = (int) (temp ^ (temp >>> 32));
        temp = Double.doubleToLongBits(v);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        temp = Double.doubleToLongBits(w);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        temp = Double.doubleToLongBits(a);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        temp = Double.doubleToLongBits(b);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        temp = Double.doubleToLongBits(c);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        temp = Double.doubleToLongBits(d);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        temp = Double.doubleToLongBits(tx);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        temp = Double.doubleToLongBits(ty);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        return result;
    }


    @Override
    public String toString() {
        if (this.equals(ROTATE_0)) {
            return "Rotate 0°";
        }
        if (this.equals(ROTATE_90)) {
            return "Rotate 90°";
        }
        if (this.equals(ROTATE_180)) {
            return "Rotate 180°";
        }
        if (this.equals(ROTATE_270)) {
            return "Rotate 270°";
        }
        return "Matrix{" +
                "u=" + u +
                ", v=" + v +
                ", w=" + w +
                ", a=" + a +
                ", b=" + b +
                ", c=" + c +
                ", d=" + d +
                ", tx=" + tx +
                ", ty=" + ty +
                '}';
    }

    public static final Matrix ROTATE_0 = new Matrix(1, 0, 0, 1, 0, 0, 1, 0, 0);
    public static final Matrix ROTATE_90 = new Matrix(0, 1, -1, 0, 0, 0, 1, 0, 0);
    public static final Matrix ROTATE_180 = new Matrix(-1, 0, 0, -1, 0, 0, 1, 0, 0);
    public static final Matrix ROTATE_270 = new Matrix(0, -1, 1, 0, 0, 0, 1, 0, 0);

    public static Matrix fromFileOrder(double a, double b, double u, double c, double d, double v, double tx, double ty, double w) {
        return new Matrix(a, b, c, d, u, v, w, tx, ty);
    }

    public static Matrix fromByteBuffer(ByteBuffer byteBuffer) {
        return fromFileOrder(
                IsoTypeReader.readFixedPoint1616(byteBuffer),
                IsoTypeReader.readFixedPoint1616(byteBuffer),
                IsoTypeReader.readFixedPoint0230(byteBuffer),
                IsoTypeReader.readFixedPoint1616(byteBuffer),
                IsoTypeReader.readFixedPoint1616(byteBuffer),
                IsoTypeReader.readFixedPoint0230(byteBuffer),
                IsoTypeReader.readFixedPoint1616(byteBuffer),
                IsoTypeReader.readFixedPoint1616(byteBuffer),
                IsoTypeReader.readFixedPoint0230(byteBuffer)
        );
    }

    public void getContent(ByteBuffer byteBuffer) {
        IsoTypeWriter.writeFixedPoint1616(byteBuffer, a);
        IsoTypeWriter.writeFixedPoint1616(byteBuffer, b);
        IsoTypeWriter.writeFixedPoint0230(byteBuffer, u);

        IsoTypeWriter.writeFixedPoint1616(byteBuffer, c);
        IsoTypeWriter.writeFixedPoint1616(byteBuffer, d);
        IsoTypeWriter.writeFixedPoint0230(byteBuffer, v);

        IsoTypeWriter.writeFixedPoint1616(byteBuffer, tx);
        IsoTypeWriter.writeFixedPoint1616(byteBuffer, ty);
        IsoTypeWriter.writeFixedPoint0230(byteBuffer, w);

    }


}
