package nullarbor;

import com.sun.j3d.utils.geometry.Primitive;
import com.sun.j3d.utils.geometry.Box;

import javax.media.j3d.*;
import javax.vecmath.Vector3f;
import javax.vecmath.Color3f;

/**
 * [CLASS DESCRIPTION]
 * Created: 26/01/2006
 *
 * @author Bruce Sutherland
 */
public class Building
{
    //TODO: add option for peak and other decoration


    // ambient and diffuse are usually the same
    // specular is the "reflective" colour of an object
    public static final Material GLASS = new Material
    (
        new Color3f(0.175f, 0.175f, 0.25f), // ambient
        new Color3f(0.175f, 0.175f, 0.25f), // diffuse
        new Color3f(0.8f, 0.8f, 0.8f), // specular
        new Color3f(0.0f, 0.0f, 0.0f), // emissive
        128.0f
    );
    public static final Material OBSIDIAN = new Material
    (
        new Color3f(0.1f, 0.1f, 0.1f), // ambient
        new Color3f(0.1f, 0.1f, 0.1f), // diffuse
        new Color3f(0.8f, 0.8f, 0.8f), // specular
        new Color3f(0.0f, 0.0f, 0.0f), // emissive
        128.0f //shininess
    );
    public static final Material REDBRICK = new Material
    (
        new Color3f(0.25f, 0.175f, 0.175f), // ambient
        new Color3f(0.25f, 0.175f, 0.175f), // diffuse
        new Color3f(0.1f, 0.1f, 0.1f), // specular
        new Color3f(0.0f, 0.0f, 0.0f), // emissive
        32.0f
    );
    public static final Material CONCRETE = new Material
    (
        new Color3f(0.2f, 0.2f, 0.2f), // ambient
        new Color3f(0.2f, 0.2f, 0.2f), // diffuse
        new Color3f(0.2f, 0.2f, 0.2f), // specular
        new Color3f(0.0f, 0.0f, 0.0f), // emissive
        32.0f
    );
    public static final Material SAND = new Material
    (
        new Color3f(0.4f, 0.3f, 0.2f), // ambient
        new Color3f(0.4f, 0.3f, 0.2f), // diffuse
        new Color3f(0.5f, 0.5f, 0.5f), // specular
        new Color3f(0.0f, 0.0f, 0.0f), // emissive
        32.0f
    );
    public static final Material CACTUS = new Material
    (
        new Color3f(0.4f, 0.3f, 0.2f), // ambient
        new Color3f(0.4f, 0.3f, 0.2f), // diffuse
        new Color3f(0.5f, 0.5f, 0.5f), // specular
        new Color3f(0.0f, 0.0f, 0.0f), // emissive
        32.0f
    );
    public static final Material ASPHALT = new Material
    (
            new Color3f(0.1f, 0.1f, 0.1f), // ambient
            new Color3f(0.1f, 0.1f, 0.1f), // diffuse
            new Color3f(0.1f, 0.1f, 0.1f), // specular
            new Color3f(0.0f, 0.0f, 0.0f), // emissive
            32.0f
    );



    private static float SECTION_HEIGHT = 0.55f;
    private static float SECTION_SCALE = 0.85f;

    private Material material;
    private Appearance appearance;

    private float height;
    private float width;
    private float depth;
    private int sections;

    private float [] sectionHeights;


    public Building(float height, float width, float depth, int sections, Material material)
    {
        this.height = height;
        this.width = width;
        this.depth = depth;
        setSections(sections);
        setMaterial(material);
    }

    public Material getMaterial()
    {
        return material;
    }

    public void setMaterial(Material material)
    {
        this.material = material;
        if(appearance == null)
        {
            appearance = new Appearance();
            appearance.setColoringAttributes(new ColoringAttributes(1.0f, 1.0f, 1.0f, ColoringAttributes.SHADE_FLAT));
        }
        appearance.setMaterial(material);
    }

    public float getHeight()
    {
        return height;
    }

    public void setHeight(float height)
    {
        this.height = height;
    }

    public float getWidth()
    {
        return width;
    }

    public void setWidth(float width)
    {
        this.width = width;
    }

    public float getDepth()
    {
        return depth;
    }

    public void setDepth(float depth)
    {
        this.depth = depth;
    }

    public int getSections()
    {
        return sections;
    }

    public void setSections(int sections)
    {
        float total;

        this.sections = sections;
        sectionHeights = new float[sections];

        sectionHeights[0] = height;
        total = height;
        for(int i = 1; i < sections; i++)
        {
            sectionHeights[i] = sectionHeights[i - 1] * SECTION_HEIGHT;
            total += sectionHeights[i];
        }
        for(int i = 0; i < sections; i++)
        {
            sectionHeights[i] *= height;
            sectionHeights[i] /= total;
            //System.out.println("Section "+i+": "+sectionHeights[i]);
        }
    }

    private Primitive getSectionPrimitive(int i)
    {
        float scale = 1;
        for(int j = 0; j < i; j++)
        {
            scale *= SECTION_SCALE;
        }
        return new Box(width * scale / 2, sectionHeights[i] / 2, depth * scale / 2, Box.GENERATE_NORMALS, appearance);
    }

    private Transform3D getVerticalTransform(int i)
    {
        float previous;
        Transform3D transform;
        transform = new Transform3D();
        if(i > 0)
        {
            previous = sectionHeights[i - 1];
        }
        else
        {
            previous = 0;
        }
        transform.setTranslation(new Vector3f(0, (sectionHeights[i] + previous) / 2, 0));
        return transform;
    }

    public Group getBuildingGroup()
    {
        TransformGroup base;
        TransformGroup child;
        TransformGroup parent;

        base = new TransformGroup(getVerticalTransform(0));
        base.addChild(getSectionPrimitive(0));
/*
        if(sections == 2)
        {
            child = new TransformGroup(getVerticalTransform(1));
            child.addChild(getSectionPrimitive(1));
            base.addChild(child);
        }
*/
        parent = base;
        for(int i = 1; i < sections; i++)
        {
            child = new TransformGroup(getVerticalTransform(i));
            parent.addChild(child);
            child.addChild(getSectionPrimitive(i));
            parent = child;
        }
        return base;

    }


}
