/*
 * ColoredBlock.java
 *
 * Created on January 7, 2001, 9:39 PM
 */

package edu.ou.eml.fea3d;

/**
 *
 * @author  Qiuli Sun
 * @version 1.0
 */



import javax.vecmath.*;
import javax.media.j3d.*;
import javax.swing.*;
import com.sun.j3d.utils.geometry.*;
import java.awt.*;
import java.text.* ; 

public class ColoredBlock  {

    public static float length ;
    public static float width ;
    public static float height ;

    protected Point3f[] vertices ;
    protected Color3f[] colors;
    protected int[] vertexIndices ;
    protected Color3f minColor, halfMinColor, zeroColor, halfMaxColor, maxColor;
    protected int k ;

    protected Text3D minTextGeom, zeroTextGeom , maxTextGeom ;
    protected Font3D font3D;
    protected Appearance textAppearance;
    protected TransformGroup coloredBlockTG;
    protected float minStress, maxStress;
    protected Shape3D coloredBlockShape ;
    protected DecimalFormat scientificNotation ;
    
    public BranchGroup coloredBlockBG ;

    /** Creates new ColoredBlock */
    public ColoredBlock(int id)
    {
        length = 8.0f;
        width = 4.0f;
        height = 16.0f;
        
        coloredBlockBG = new BranchGroup();
        coloredBlockBG.setPickable(false);
        coloredBlockTG = new TransformGroup () ;
  
        coloredBlockShape = new Shape3D();
        coloredBlockShape.setCapability(Shape3D.ALLOW_GEOMETRY_WRITE);
        
        prepareVertexColors(id);
        coloredBlockShape.setGeometry( getGeometry() );
        coloredBlockShape.setAppearance(createAppearance() );

        Transform3D transform3D = new Transform3D();
        transform3D.rotX(-Math.PI/2.0f);
        
        float x0 =  -0.5f * CoordinateSystem.xDiff - 1.5f * length;
        float y0 =  -0.5f * CoordinateSystem.yDiff ;
        float z0 = CoordinateSystem.z0 ;
        
        transform3D.setTranslation(new Vector3f(x0, y0, z0) );
        coloredBlockTG.setTransform(transform3D);

        //font3D can be used three times
        font3D = new Font3D(new Font("Helvetica",
        Font.PLAIN,
        (int)(3*CoordinateSystem.rate)),
        new FontExtrusion());

        textAppearance = createTextAppearance() ;
        scientificNotation = new DecimalFormat( "0.000E0" ) ; 
        
        minStress = 20.0f;
        maxStress = 3000.0f;
        
        minTextGeom = createText( scientificNotation.format(minStress), 0.5f*length, -0.5f*width, -0.8f*width) ;
        zeroTextGeom = createText("0.0", 0.5f*length, -0.5f*width, 0.5f*height) ;
        maxTextGeom = createText(scientificNotation.format(maxStress), 0.5f*length, -0.5f*width, height+0.8f*width) ;
 
        coloredBlockTG.addChild(coloredBlockShape);
        coloredBlockBG.addChild(coloredBlockTG);
        DataContainer.geometryTG.addChild(coloredBlockBG);
        
        zeroTextGeom.setString("Why doesn't setString()  work here?");
    }
    
    
    //************************
    public void setStressID(int id)
    {
        prepareVertexColors(id);  
        coloredBlockShape.setGeometry( getGeometry() );
        
         minTextGeom.setString(scientificNotation.format(minStress));
        zeroTextGeom.setString("0.0");
        maxTextGeom.setString(scientificNotation.format(maxStress));
    }

    //++++++++++++++++++++++++++++++
    private Text3D createText(String string, float xx, float yy, float zz)
    {
        Text3D textGeom = new Text3D( font3D, string );
        textGeom.setCapability(Text3D.ALLOW_STRING_WRITE) ;
        textGeom.setAlignment(Text3D.ALIGN_CENTER);

        //Please note, OrientedShape3D is much better than billboard
        //The reason is that it works in every view and is easy to code
        OrientedShape3D textShape = new OrientedShape3D();
        textShape.setGeometry(textGeom);
        textShape.setAppearance(textAppearance);
        textShape.setAlignmentMode(OrientedShape3D.ROTATE_ABOUT_POINT);
        textShape.setRotationPoint(0.0f, 0.0f, 0.0f );

        TransformGroup textTG = new TransformGroup() ;
        Transform3D tran3D = new Transform3D() ;
        tran3D.setTranslation(new Vector3f(xx, yy, zz) );
        textTG.setTransform(tran3D) ;

        textTG.addChild(textShape) ;
        coloredBlockTG.addChild(textTG) ;
        return textGeom;
    }

    //++++++++++++++++++++++++++++++
    public void prepareVertexColors(int id)
    {
        float red, green, blue ;
        float stress ;
        float[] stresses = new float[2];
        
        //********testing, will be deleted later********
        stresses[0] = - 267.985678f ;
        stresses[1] = 123489.985678f ;
        //****************
        /*
        Element element ;
        if (DataContainer.elementType == Element.BRICK)
        {
            element = DataContainer.brick;
        }
        else
        {
            element = DataContainer.tetra;
        }

        switch (id)
        {
            case Element.STRESS_X:
        {  stresses = element.stressX; break; }
            case Element.STRESS_Y:
        {  stresses = element.stressY; break; }
            case Element.STRESS_Z:
        {  stresses = element.stressZ; break; }
            case Element.SHEAR_XY:
        {  stresses = element.shearXY; break; }
            case Element.SHEAR_YZ:
        {  stresses = element.shearYZ; break; }
            case Element.SHEAR_ZX:
        {  stresses = element.shearZX; break; }
            case Element.PRINCIPAL_STRESS_1:
        {  stresses = element.principalStress1; break; }
            case Element.PRINCIPAL_STRESS_2:
        {  stresses = element.principalStress2; break; }
            case Element.PRINCIPAL_STRESS_3:
        {  stresses = element.principalStress3; break; }
            case Element.VON_MISES:
        {  stresses = element.vonMises; break; }
            case Element.ABSOLUTE_MAX_SHEAR:
        {  stresses = element.absoluteMaxShearingStress; break; }
        }
    */
        minStress = Fea3DFactory.min(stresses);
        maxStress = Fea3DFactory.max(stresses);

        if ( minStress >= 0.0f )
        {
            blue = 0.0f ;

            //stress = 0
            stress = 0.0f ;
            red = 0.1f+ 0.9f*(stress) / (maxStress);
            green = 1.0f - red;
            minColor = new Color3f(red, green, blue) ;
            //stress = 0.25 * maxStress
            stress = 0.25f *maxStress  ;
            red = 0.1f+ 0.9f*(stress) / (maxStress);
            green = 1.0f - red;
            halfMinColor = new Color3f(red, green, blue) ;
            //stress = 0.5* maxStress
            stress = 0.5f *maxStress  ;
            red = 0.1f+ 0.9f*(stress) / (maxStress);
            green = 1.0f - red;
            zeroColor = new Color3f(red, green, blue) ;

            //stress = 0.75* maxStress
            stress = 0.75f *maxStress  ;
            red = 0.1f+ 0.9f*(stress) / (maxStress);
            green = 1.0f - red;
            halfMaxColor = new Color3f(red, green, blue) ;

            //stress = maxStress
            stress = maxStress  ;
            red = 0.1f+ 0.9f*(stress) / (maxStress);
            green = 1.0f - red;
            maxColor = new Color3f(red, green, blue) ;
        }
        else
        {
            red = 0.0f ;
            //stress = minStress
            stress =  minStress ;
            blue = 0.1f + 0.9f*stress / minStress;
            green = 1.0f - blue ;
            minColor = new Color3f(red, green, blue) ;

            //stress = 0.5*minStress
            stress =  0.5f * minStress ;
            blue = 0.1f + 0.9f*stress / minStress;
            green = 1.0f - blue ;
            halfMinColor = new Color3f(red, green, blue) ;

            //stress = 0.0
            stress =  0.0f ;
            red = 0.05f;
            blue = 0.05f;
            green = 0.95f ;
            zeroColor = new Color3f(red, green, blue) ;

            //stress = 0.5*maxStress
            stress = 0.5f * maxStress ;
            red = 0.1f+ 0.9f*(stress) / (maxStress) ;
            green = 1.0f - red ;
            blue = 0.0f ;
            halfMaxColor = new Color3f(red, green, blue) ;

            //stress = maxStress ;
            stress = maxStress ;
            red = 0.1f+ 0.9f*(stress) / (maxStress) ;
            green = 1.0f - red ;
            blue = 0.0f ;
            maxColor = new Color3f(red, green, blue) ;
        }

    }

    //************************************
    private IndexedGeometryArray getGeometry()
    {
        vertices = new Point3f[20];
        vertices[0] = new Point3f(0.0f, 0.0f, 0.0f);
        vertices[1] = new Point3f(length, 0.0f, 0.0f);
        vertices[2] = new Point3f(length, width, 0.0f);
        vertices[3] = new Point3f(0.0f, width, 0.0f);

        vertices[4] = new Point3f(0.0f, 0.0f, 0.25f*height);
        vertices[5] = new Point3f(length, 0.0f, 0.25f*height);
        vertices[6] = new Point3f(length, width, 0.25f*height);
        vertices[7] = new Point3f(0.0f, width, 0.25f*height);

        vertices[8] = new Point3f(0.0f, 0.0f, 0.5f*height);
        vertices[9] = new Point3f(length, 0.0f, 0.5f*height);
        vertices[10] = new Point3f(length, width, 0.5f*height);
        vertices[11] = new Point3f(0.0f, width, 0.5f*height);

        vertices[12] = new Point3f(0.0f, 0.0f, 0.75f*height);
        vertices[13] = new Point3f(length, 0.0f, 0.75f*height);
        vertices[14] = new Point3f(length, width, 0.75f*height);
        vertices[15] = new Point3f(0.0f, width, 0.75f*height);

        vertices[16] = new Point3f(0.0f, 0.0f, height);
        vertices[17] = new Point3f(length, 0.0f, height);
        vertices[18] = new Point3f(length, width, height);
        vertices[19] = new Point3f(0.0f, width, height);

        //index
        vertexIndices = new int[72];
        k = 0;
        
        //bottom
        vertexIndices[k++] = 0 ;
        vertexIndices[k++] = 3 ;
        vertexIndices[k++] = 2 ;
        vertexIndices[k++] = 1 ;

        for(int i  = 0; i < 16 ; i++)
        {
            setQuadIndices(i);
        }
        //top
        vertexIndices[k++] = 16 ;
        vertexIndices[k++] = 17 ;
        vertexIndices[k++] = 18 ;
        vertexIndices[k++] = 19 ;

        colors = new Color3f[20];
        for(int i = 0 ; i < 4; i++)
          {colors[i] = minColor;}

        for(int i = 4 ; i < 8; i++)
          {colors[i] = halfMinColor;}

        for(int i = 8 ; i < 12; i++)
         { colors[i] = zeroColor;}

        for(int i = 12 ; i < 16; i++)
         { colors[i] = halfMaxColor;}
        for(int i = 16 ; i < 20; i++)
         { colors[i] = maxColor; }

        GeometryInfo gi = new GeometryInfo(GeometryInfo.QUAD_ARRAY);
        gi.setCoordinates(vertices);
        gi.setCoordinateIndices(vertexIndices);

        gi.setColors(colors);
        gi.setColorIndices(vertexIndices);

        NormalGenerator ng = new NormalGenerator();
        ng.setCreaseAngle(2.0*Math.PI/30.0);
        ng.generateNormals(gi);
        gi.recomputeIndices();

        Stripifier st = new Stripifier();
        st.stripify(gi);
        gi.recomputeIndices();
        //release the memory

        ng = null;
        st = null;

        return gi.getIndexedGeometryArray();
    }

    //*************************
    //If start >=16, the function will not work properly.
    //*************************
    private void setQuadIndices(int start)
    {
        int end = 0;
        if ( start < 4)
        {
            end = ( start + 1) % 4 ;
        }
        if ( start >= 4 & start < 7)
        {
            end = ( start + 1) % 8 ;
        }
        if (start == 7 )
        {
            end = 4;
        }
        if ( start >=8 & start < 11)
        {
            end = ( start + 1) % 12 ;
        }
        if (start == 11 )
        {
            end = 8;
        }
        if ( start >=12 & start < 15)
        {
            end = ( start + 1) % 16 ;
        }
        if (start == 15 )
        {
            end = 12;
        }

        vertexIndices[k++] = start ;
        vertexIndices[k++] = end ;
        vertexIndices[k++] = end + 4 ;
        vertexIndices[k++] = start + 4 ;
    }
    
        //******************************************
    private final static  Color3f   ambColor = new Color3f ( 0.3f, 0.3f, 0.3f ) ;
    private final static Color3f  emissColor = new Color3f ( 0.1f,0.1f,0.1f ) ;  
    private final static   float shininess = 50.0f ;
    
     public final   Appearance createTextAppearance()
    {
        Appearance textAppearance = new Appearance ();
        Color3f  diffColor = new Color3f ( 1.0f, 0.0f, 0.3f ) ;
        Color3f  specColor = new Color3f ( 1.0f, 0.3f, 1.0f ) ;
        Material material = new Material (ambColor, emissColor, diffColor, specColor, shininess);
        textAppearance.setMaterial (material);
        return textAppearance ;
    }
    
    //*******************************************************
    public  Appearance createAppearance() {
        Appearance appearance = new Appearance ();
        Material material = new Material();
        material.setLightingEnable(true);
        appearance.setMaterial(material);

        PolygonAttributes polyAttrib = new PolygonAttributes();
        polyAttrib.setCullFace(PolygonAttributes.CULL_NONE);
        polyAttrib.setCapability(PolygonAttributes.ALLOW_NORMAL_FLIP_WRITE);
        polyAttrib.setBackFaceNormalFlip(true);

        appearance.setPolygonAttributes(polyAttrib);
        return appearance;
    }
}
