
// Obstacles.java
// Andrew Davison, April 2005, ad@fivedots.coe.psu.ac.th

/* Překážky uložené ve 2D-poli logických hodnot (obs) představují
   rozivnu XZ. Index řádku je osa z a sloupce reprezentují osu x.
   Prvek obs[0][0] je zadní levý roh roviny,
   což je bod (0-FLOOR_LEN/2, 0-FLOOR_LEN/2).

   Překážky mohou být umístěny pouze do celočíselných pozic,
   což je dáno tím, že pro označení pozic překážek značky v tomto poli.
*/

import java.util.*;
import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.utils.geometry.*;


public class Obstacles
{
  private final static float RADIUS = 0.1f;   // poloměr překázky
  private final static float HEIGHT = 1.0f;   // výška překážky

  private final static int FLOOR_LEN = 20;  
      // mělo by jít o tutéž hodnotu jako ve třídě CheckerFloor, a měla by být sudá

  // barvy materiálu překážek
  private final static Color3f black = new Color3f(0.0f, 0.0f, 0.0f);
  private final static Color3f specular = new Color3f(1.0f, 1.0f, 1.0f);
  private final static Color3f red = new Color3f(0.9f, 0.1f, 0.2f);


  private boolean obs[][];    // zda-li bod (x,z) obsahuje překážku
  private BoundingSphere obsBounds[][];   // ohraničující koule pro obs
  private Group obsGroup;     // skupina 3D-překážek zobrazených ve světě


  public Obstacles()
  {
    obs = new boolean[FLOOR_LEN+1][FLOOR_LEN+1];    // větší než FLOOR_LEN*FLOOR_LEN
    obsBounds = new BoundingSphere[FLOOR_LEN+1][FLOOR_LEN+1];
    for (int z=0; z <= FLOOR_LEN; z++)
      for(int x=0; x <= FLOOR_LEN; x++) {
        obs[z][x] = false;
        obsBounds[z][x] = null;
      }

    obsGroup = new Group();

  }  // konec metody: Obstacles()


  public void store(String line)
  /* Řáek bude mít následujícíc formtá:
        (x1,z1) (x2,z2) ...
  */
  {
    int x=0, z=0;
    String coordStr;
    StringTokenizer points;
    StringTokenizer coords = new StringTokenizer(line);
    while (coords.hasMoreTokens()) {
      coordStr = coords.nextToken();    // should be a single (x,z)
      points = new StringTokenizer(coordStr, "(,)");
      try {
        x = Integer.parseInt(points.nextToken());
        z = Integer.parseInt(points.nextToken());
      }
      catch (NumberFormatException ex){ 
        System.out.println("Nesprávný formát pro data překážek v konfiguračním souboru"); 
        break;
      } 
      markObstacle(x,z);
    }
  }  // konec metody: store()


  private void markObstacle(int x, int z)
  {
    if ((x < -FLOOR_LEN/2) || (x > FLOOR_LEN/2)) {
      System.out.println("x-ová souřadnice překážka mimo hranice: " + x);
      x = 0;
    }
    if ((z < -FLOOR_LEN/2) || (z > FLOOR_LEN/2)) {
      System.out.println("z-ová souřadnice překážka mimo hranice: " + z);
      z = 0;
    }
    obs[z+(FLOOR_LEN/2)][x+(FLOOR_LEN/2)] = true;
    obsBounds[z+(FLOOR_LEN/2)][x+(FLOOR_LEN/2)] =
			new BoundingSphere( new Point3d(x, 0.0, z), RADIUS);

   obsGroup.addChild( makeObs(x, z));

  }  // konec metody: markObstacle()


  public void print()
  {
    // hlavička - zmačky po každých 5 dílcích a řádek
    for(int x=(-FLOOR_LEN/2); x <= (FLOOR_LEN/2); x++) {
      if (x == 0)
        System.out.print("0");
      else if (x%5 == 0)
        System.out.print("*");
      else
        System.out.print(" ");
    }
    System.out.println("");
    for(int x=(-FLOOR_LEN/2); x <= (FLOOR_LEN/2); x++)
      System.out.print("-");
    System.out.println("");

    // tělo tabulky: nuly a z-ová osa na konci každého řádku
    for (int z=0; z <= FLOOR_LEN; z++) {
      for(int x=0; x <= FLOOR_LEN; x++) {
        if (obs[z][x])
          System.out.print("O");
        else
          System.out.print(" ");
      }
      if ((z-FLOOR_LEN/2)%5 == 0)
        System.out.println("| " + (z-FLOOR_LEN/2));
      else 
        System.out.println("|");
    }

    // patička: řádek
    for(int x=(-FLOOR_LEN/2); x <= (FLOOR_LEN/2); x++)
      System.out.print("-");
    System.out.println("");
  }  // konec metody: print()


  public boolean nearObstacle(Point3d pos, double radius)
  /* posn je omezeno pouze na oblast uvnitř plochy podlahy.
     Dále se kontroluje proti pozici pos ohraničující koule každé překážky 
  */
  {
    if ((pos.x < -FLOOR_LEN/2) || (pos.x > FLOOR_LEN/2) ||
        (pos.z < -FLOOR_LEN/2) || (pos.z > FLOOR_LEN/2))     // mimo podlahu
      return true;

    // zkontroluj, jsme-li blízko nějaké překážky
    BoundingSphere bs = new BoundingSphere( pos, radius);
    for (int z=0; z <= FLOOR_LEN; z++)
      for(int x=0; x <= FLOOR_LEN; x++)
        if (obs[z][x]) {
          if (obsBounds[z][x].intersect(bs))
            return true;
        }
     return false;
   }  // konec metody: nearObstacle()



  private TransformGroup makeObs(int x, int z)
  // červený válec, jehož základna je v bodě (x,z)
  {
    // vytvoř uzel překážky
    Appearance obsApp = new Appearance();
    Material mat = new Material(black, black, red, specular, 100.f);
    mat.setLightingEnable(true);
    obsApp.setMaterial( mat );
    Cylinder obs = new Cylinder( RADIUS, HEIGHT, Cylinder.GENERATE_NORMALS, obsApp);

    // oprav pozici překážky
    TransformGroup posnTG = new TransformGroup();
    Transform3D trans = new Transform3D();
    trans.setTranslation( new Vector3d(x, HEIGHT/2, z) );
    posnTG.setTransform(trans);
    posnTG.addChild(obs); 
    return posnTG;
  }  // konec metody: makeObs()


  public Group getObsGroup()
  {  return obsGroup;  }


}  // konec třídy: Obstacles