import java.net.URL;
import java.net.MalformedURLException;
import java.applet.Applet;
import java.awt.Panel;
import java.awt.BorderLayout;
import java.awt.GraphicsEnvironment;
import java.util.Enumeration;
import java.io.*;
import javax.sound.sampled.*;
import com.sun.j3d.utils.behaviors.keyboard.KeyNavigatorBehavior;

import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.utils.geometry.*;
import com.sun.j3d.audioengines.*;
import com.sun.j3d.utils.universe.SimpleUniverse;
import com.sun.j3d.utils.applet.MainFrame;

public class Java3DSoundTest extends Applet {

    // Universe
    private SimpleUniverse universe_     = null;
    private Canvas3D can_                = null;
    private BranchGroup sceneRoot_       = null;
    private TransformGroup viewTrans_    = null;

// -----------------------------------------------------------------------------
// CT
// -----------------------------------------------------------------------------
    public Java3DSoundTest () {
    }

// -----------------------------------------------------------------------------
// INIT
// -----------------------------------------------------------------------------
    public void init() {
        this.setLayout(new BorderLayout());

        // Canvas
        can_ = new Canvas3D(
            SimpleUniverse.getPreferredConfiguration()
        );
        this.add("Center", can_);

        // SimpleUniverse
        universe_ = new SimpleUniverse(can_);
        universe_.getViewer().getView().setBackClipDistance(2000);
        // AudioDevice
        AudioDevice dev = universe_.getViewer().createAudioDevice();
        dev.initialize();

        // - Scene
        sceneRoot_ = new BranchGroup();

        // - Viewing
        viewTrans_ = universe_.getViewingPlatform().getViewPlatformTransform();
        Transform3D tr3d = new Transform3D();
        tr3d.setTranslation(new Vector3f(0,0,60));

        // Navigators
        KeyNavigatorBehavior keyNav = new KeyNavigatorBehavior(viewTrans_);
        keyNav.setSchedulingBounds(new BoundingSphere(new Point3d(), 5000.0));
        sceneRoot_.addChild(keyNav);

        sceneRoot_.addChild(new PositionTrace(viewTrans_));

        // marking origin
        sceneRoot_.addChild(new ColorCube(1));

        // PointSound at (0,0,-50)
        sceneRoot_.addChild(createPointSound(new Point3f(0,0,-50), getDocumentBase(), "hello_universe.au"));
        // PointSound at (50,0,0)
        sceneRoot_.addChild(createPointSound(new Point3f(50,0,0), getDocumentBase(), "roar.au"));
        // PointSound at (50,0,-50)
        sceneRoot_.addChild(createPointSound(new Point3f(50,0,-50), getDocumentBase(), "techno_machine.au"));

        // Liven
        universe_.addBranchGraph(sceneRoot_);
    }


// -----------------------------------------------------------------------------
// pointsound and colorcube at designated position
// -----------------------------------------------------------------------------
    private Group createPointSound(Point3f pos, URL url, String sndSrc) {
        System.out.println("PointSound at : " + pos);

        // capture sample
        URL soundURL = null;
        try {
            soundURL = new URL(url, sndSrc);
        } catch(Exception ex) {
            System.out.println("URL not found:\n" + ex);
        }

        MediaContainer media = new MediaContainer(soundURL);
        media.setCapability(MediaContainer.ALLOW_URL_READ);
        media.setCapability(MediaContainer.ALLOW_URL_WRITE);
        media.setCacheEnable(true);

        // upcoming point sound
        PointSound point = new PointSound();
        point.setSoundData(media);
        Point2f[] depthGain = {
            new Point2f(0,   1.0f),
            // new Point2f(0.6f,   0.0f)
            new Point2f(1f,  0.75f),
            new Point2f(3f,  0.5f),
            new Point2f(6f,  0.25f),
            new Point2f(10f, 0.0f),
        };
        point.setDistanceGain(depthGain);     // seems to work fine
        point.setSchedulingBounds(new BoundingSphere(new Point3d(0,0,0), 100));
        point.setLoop(-1);
        point.setEnable(true);

        // positioning
        Transform3D tr3d = new Transform3D();
        tr3d.setTranslation(new Vector3f(pos.x, pos.y, pos.z));
        TransformGroup tr = new TransformGroup(tr3d);

        tr.addChild(new ColorCube(0.2));

        // positioning directly or by indirectly makes no difference:
        // point.setPosition(pos);
        tr.addChild(point);

        BranchGroup bg = new BranchGroup();
        bg.addChild(tr);
        // bg.addChild(point);
        return bg;
    }

// -----------------------------------------------------------------------------
// MAIN
// -----------------------------------------------------------------------------
    public static void main(String[] args) {
        MainFrame frame = new MainFrame(new Java3DSoundTest(),  args, 600, 600);
    }

} // CLASS
