package march;

import java.util.*;

public class NMarch{
    private int NI, NJ, NK;
    private float start_x, start_y, start_z;
    private float delta_x, delta_y, delta_z;

    private float threshold;
    private float[][][]  slice;
    private boolean[][][] outsideslice;
    private boolean[] inout = new boolean[8];

    
    private int[][] facet_data = Cases.facet_data;
    private int[][] edge_data  = Cases.edge_data;
    
    // Vector of Vertex
    private Vector vertex_table;
    private Vector surface_list;

    public NMarch(float[][][] slice, float threshold, 
                 float start_x, float start_y, float start_z,
                 float delta_x, float delta_y, float delta_z){
       
        this.slice = slice;
        
        this.threshold = threshold;

        NK = slice.length;
        NI = slice[0].length;
        NJ = slice[0][0].length;

        this.start_x = start_x;
        this.start_y = start_y;
        this.start_z = start_z;
        this.delta_x = delta_x;
        this.delta_y = delta_y;
        this.delta_z = delta_z;

        init_outsideslice(threshold);

        vertex_table = new Vector();
        surface_list = new Vector();
    }

    public TriangleStrip march(){        
        for(int k = 0; k < NK-1; k++){
            System.err.println("k = " + k);
            
            boolean[][] lowslice = outsideslice[k];
            boolean[][] highslice = outsideslice[k+1];
            boolean[]   inout = new boolean[8];
            
            for(int i = 0; i < NI-1; i++){
                for(int j = 0; j < NJ-1; j++){
                    set_inout(inout, lowslice, highslice, i, j);
                    int cube_index = Cases.cubeIndex(inout);
                    if(cube_index != 0 && cube_index != 255){
                        load_facet(cube_index, i, j, k);
                    }
                }
            }
        }
        return (new TriangleStrip(vertex_table, surface_list));
    }
    
    private void set_inout(boolean[] inout, 
                           boolean[][] lowslice, boolean[][] highslice,
                           int i, int j){
        inout[0] = lowslice[i][j];
        inout[1] = lowslice[i+1][j];
        inout[2] = lowslice[i+1][j+1];
        inout[3] = lowslice[i][j+1];
        inout[4] = highslice[i][j];
        inout[5] = highslice[i+1][j];
        inout[6] = highslice[i+1][j+1];
        inout[7] = highslice[i][j+1];
    }
            
    private void init_outsideslice(float T){
        outsideslice = new boolean[NK][NI][NJ];

        for(int k = 0; k < NK; k++){
            for(int i = 0; i < NI; i++){
                for(int j = 0; j < NJ; j++){
                    if(slice[k][i][j] < T){
                        outsideslice[k][i][j] = true;
                    }
                }
            }
        }
    }
    
    private void load_facet(int cube_index, 
                            int imarch, int jmarch, int kmarch){
        int[] edge_table = new int[12];
        int edge;
        int[] vertex_list = new int[3];
        int vert_index  = 0;
        int vert_offset = 0;
        int ioffset;
        int joffset;
        
        int[][] facet_data = Cases.facet_data;
        int[][] edge_data = Cases.edge_data;
        
        int i = 0;
        int facet;
        while((i != 12)&&(facet_data[cube_index][i] != -1)){
            Vertex v1,v2,v3;
            v1 = contour_intersect(facet_data[cube_index][i], 
                                   imarch, jmarch, kmarch);
            v2 = contour_intersect(facet_data[cube_index][i+1],
                                   imarch, jmarch, kmarch);            
            v3 = contour_intersect(facet_data[cube_index][i+2],
                                   imarch, jmarch, kmarch);
            surface_list.add(new Triangle(v1,v2,v3));
            i += 3;
        }
    }

    private Vertex contour_intersect(int v, 
                                     int imarch, int jmarch, int kmarch){
        
       
        switch(v){
          case 0:
            {
                float s = slice[kmarch][imarch][jmarch];
                float e = slice[kmarch][imarch+1][jmarch];
                float x = start_x + delta_x*imarch;
                float y = start_y + delta_y*jmarch;
                float z = start_z + delta_z*kmarch;
                float xx = x + delta_x*(threshold-s)/(e-s);
                return new Vertex(xx,y,z);
            }
          case 1:
            {
                float s = slice[kmarch][imarch+1][jmarch];
                float e = slice[kmarch][imarch+1][jmarch+1];
                float x = start_x + delta_x*(imarch+1);
                float y = start_y + delta_y*jmarch;
                float z = start_z + delta_z*kmarch;
                float yy = y + delta_y*(threshold-s)/(e-s);
                return new Vertex(x,yy,z);
            }
          case 2:
            {
                float s = slice[kmarch][imarch][jmarch+1];
                float e = slice[kmarch][imarch+1][jmarch+1];
                float x = start_x + delta_x*imarch;
                float y = start_y + delta_y*(jmarch+1);
                float z = start_z + delta_z*kmarch;
                float xx = x + delta_x*(threshold-s)/(e-s);
                return new Vertex(xx,y,z);
            }
          case 3:
            {
                float s = slice[kmarch][imarch][jmarch];
                float e = slice[kmarch][imarch][jmarch+1];
                float x = start_x + delta_x*imarch;
                float y = start_y + delta_y*(jmarch+1);
                float z = start_z + delta_z*kmarch;
                float yy = y + delta_y*(threshold-s)/(e-s);
                return new Vertex(x,yy,z);
            }
          case 4:
            {
                float s = slice[kmarch+1][imarch][jmarch];
                float e = slice[kmarch+1][imarch+1][jmarch];
                float x = start_x + delta_x*imarch;
                float y = start_y + delta_y*jmarch;
                float z = start_z + delta_z*(kmarch+1);
                float xx = x + delta_y*(threshold-s)/(e-s);
                return new Vertex(xx,y,z);
            }
          case 5:
            {
                float s = slice[kmarch+1][imarch+1][jmarch];
                float e = slice[kmarch+1][imarch+1][jmarch+1];
                float x = start_x + delta_x*(imarch+1);
                float y = start_y + delta_y*jmarch;
                float z = start_z + delta_z*(kmarch+1);
                float yy = y + delta_y*(threshold-s)/(e-s);
                return new Vertex(x,yy,z);
            }
          case 6:
            {
                float s = slice[kmarch+1][imarch][jmarch+1];
                float e = slice[kmarch+1][imarch+1][jmarch+1];
                float x = start_x + delta_x*(imarch);
                float y = start_y + delta_y*(jmarch+1);
                float z = start_z + delta_z*(kmarch+1);
                float xx = x + delta_x*(threshold-s)/(e-s);
                return new Vertex(xx,y,z);
            }
          case 8:
            {
                float s = slice[kmarch][imarch][jmarch];
                float e = slice[kmarch+1][imarch][jmarch];
                float x = start_x + delta_x*(imarch);
                float y = start_y + delta_y*(jmarch);
                float z = start_z + delta_z*kmarch;
                float zz = z + delta_z*(threshold-s)/(e-s);
                return new Vertex(x,y,zz);
            }
          case 9:
            {
                float s = slice[kmarch][imarch+1][jmarch];
                float e = slice[kmarch+1][imarch+1][jmarch];
                float x = start_x + delta_x*(imarch+1);
                float y = start_y + delta_y*(jmarch);
                float z = start_z + delta_z*kmarch;
                float zz = z + delta_z*(threshold-s)/(e-s);
                return new Vertex(x,y,zz);
            }
          case 10:
            {
                float s = slice[kmarch][imarch+1][jmarch+1];
                float e = slice[kmarch+1][imarch+1][jmarch+1];
                float x = start_x + delta_x*(imarch+1);
                float y = start_y + delta_y*(jmarch+1);
                float z = start_z + delta_z*kmarch;
                float zz = z + delta_z*(threshold-s)/(e-s);
                return new Vertex(x,y,zz);
            }
          case 11:
        }       
    } 

}



