package com.brackeen.javagamebook.math3D;

/**
    Klasa Rectangle3D prostokątem w przestrzeni 3D, zdefiniowanym za pomocą
    początku lokalnego układu i wektorów wskazujących w kierunku jego podstawy 
    (szerokość) i boku (wysokość).
*/
public class Rectangle3D implements Transformable {

    private Vector3D origin;
    private Vector3D directionU;
    private Vector3D directionV;
    private Vector3D normal;
    private float width;
    private float height;

    /**
        Tworzy prostokąt w określonym punkcie początkowym i o szerokości
        oraz wysokości równych zero.
    */
    public Rectangle3D() {
        origin = new Vector3D();
        directionU = new Vector3D(1,0,0);
        directionV = new Vector3D(0,1,0);
        width = 0;
        height = 0;
    }


    /**
        Tworzy nowy prostokąt Rectangle3D o podanym początku
        i kierunkach podstawy(directionU) oraz boku
        (directionV).
    */
    public Rectangle3D(Vector3D origin, Vector3D directionU,
        Vector3D directionV, float width, float height)
    {
        this.origin = new Vector3D(origin);
        this.directionU = new Vector3D(directionU);
        this.directionU.normalize();
        this.directionV = new Vector3D(directionV);
        this.directionV.normalize();
        this.width = width;
        this.height = height;
    }


    /**
        Przypisuje wartościom tego prostokąta Rectangle3D 
        inny podany prostokąt Rectangle3D.
    */
    public void setTo(Rectangle3D rect) {
        origin.setTo(rect.origin);
        directionU.setTo(rect.directionU);
        directionV.setTo(rect.directionV);
        width = rect.width;
        height = rect.height;
    }


    /**
        Pobiera początek tego prostokąta Rectangle3D.
    */
    public Vector3D getOrigin() {
        return origin;
    }


    /**
        Pobiera kierunek podstawy tego prostokąta Rectangle3D.
    */
    public Vector3D getDirectionU() {
        return directionU;
    }


    /**
        Pobiera kierunek boku tego prostokąta Rectangle3D.
    */
    public Vector3D getDirectionV() {
        return directionV;
    }


    /**
        Pobiera szerokość tego prostokąta Rectangle3D.
    */
    public float getWidth() {
        return width;
    }


    /**
        Definiuje szerokość tego prostokąta Rectangle3D.
    */
    public void setWidth(float width) {
        this.width = width;
    }


    /**
        Pobiera wysokość tego prostokąta Rectangle3D.
    */
    public float getHeight() {
        return height;
    }


    /**
        Definiuje wysokość tego prostokąta Rectangle3D.
    */
    public void setHeight(float height) {
        this.height = height;
    }


    /**
        Wylicza wektor normalny tego prostokąta Rectange3D.
    */
    protected Vector3D calcNormal() {
        if (normal == null) {
            normal = new Vector3D();
        }
        normal.setToCrossProduct(directionU, directionV);
        normal.normalize();
        return normal;
    }


    /**
        Pobiera wektor normalny tego prostokąta Rectangle3D.
    */
    public Vector3D getNormal() {
        if (normal == null) {
            calcNormal();
        }
        return normal;
    }


    /**
        Ustawia wektor normalny tego prostokąta Rectangle3D.
    */
    public void setNormal(Vector3D n) {
        if (normal == null) {
            normal = new Vector3D(n);
        }
        else {
            normal.setTo(n);
        }
    }


    public void add(Vector3D u) {
        origin.add(u);
        // nie dokonuj translacji wektorów kierunku ani rozmiaru 
    }

    public void subtract(Vector3D u) {
        origin.subtract(u);
        // nie dokonuj translacji wektorów kierunku ani rozmiaru 
    }

    public void add(Transform3D xform) {
        addRotation(xform);
        add(xform.getLocation());
    }

    public void subtract(Transform3D xform) {
        subtract(xform.getLocation());
        subtractRotation(xform);
    }

    public void addRotation(Transform3D xform) {
        origin.addRotation(xform);
        directionU.addRotation(xform);
        directionV.addRotation(xform);
    }

    public void subtractRotation(Transform3D xform) {
        origin.subtractRotation(xform);
        directionU.subtractRotation(xform);
        directionV.subtractRotation(xform);
    }

}
