/*
 * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 *
 * File based on:
 * @(#)JMFInit.java 1.14 03/04/30
 * Copyright (c) 1996-2002 Sun Microsystems, Inc.  All rights reserved.
 */
package net.java.sip.communicator.impl.media.configuration;

import java.io.File;
import java.io.IOException;
import java.util.Vector;

import javax.media.Format;
import javax.media.PlugInManager;
import javax.media.Renderer;
import javax.media.format.AudioFormat;

import net.java.sip.communicator.util.Logger;

import com.sun.media.ExclusiveUse;


public class JMFInit
    implements Runnable {

    private static final Logger logger = Logger.getLogger(JMFInit.class);

    public JMFInit() {

//        try {
//            Registry.commit();
//        }
//        catch (Exception e) {
//            logger.error("Failed to commit to JMFRegistry!", e );
//        }


        Thread detectThread = new Thread(this);
        detectThread.run();

/*
        int slept = 0;
        while (!done && slept < 60 * 1000 * 2) {
            try {
                Thread.currentThread().sleep(500);
            }
            catch (InterruptedException ie) {
            }
            slept += 500;
        }

        if (!done) {
            console.error("Detection is taking too long! Aborting!");
            message("Detection is taking too long! Aborting!");
        }

        try {
            Thread.currentThread().sleep(2000);
        }
        catch (InterruptedException ie) {
        }
*/
    }

    /**
     * Detect all capture devices
     */
    public void run() {
        detectDirectAudio();
        detectS8DirectAudio();
        detectCaptureDevices();
    }

    private void detectCaptureDevices() {
        // check if JavaSound capture is available
        logger.info("Looking for Audio capturer");
        Class dsauto = null;
        try {
            dsauto = Class.forName(
                    "net.java.sip.communicator.impl.media.configuration.DirectSoundAuto");
            dsauto.newInstance();
            logger.info("Finished detecting DirectSound capturer");
        }
        catch (ThreadDeath td) {
            throw td;
        }
        catch (Throwable t) {
            logger.warn("DirectSound capturer detection failed!", t);
        }

        Class jsauto = null;
        try {
            jsauto = Class.forName(
                    "net.java.sip.communicator.impl.media.configuration.JavaSoundAuto");
            jsauto.newInstance();
            logger.info("Finished detecting JavaSound capturer");
        }
        catch (ThreadDeath td) {
            throw td;
        }
        catch (Throwable t) {
            logger.warn("JavaSound capturer detection failed!", t);
        }

        // Check if VFWAuto or SunVideoAuto is available
        logger.info("Looking for video capture devices");
        Class auto = null;
        Class autoPlus = null;
//        try {
//            auto = Class.forName(
//                    "net.java.sip.communicator.impl.media.configuration.VFWAuto");
//        }
//        catch (Exception e) {
//            logger.warn("VFWAuto capturer detection failed!", e);
//        }
//        if (auto == null) {
//            try {
//                auto = Class.forName(
//                        "net.java.sip.communicator.impl.media.configuration.SunVideoAuto");
//            }
//            catch (Exception ee) {
//              logger.warn("SunVideoAuto capturer detection failed!", ee);
//            }
//            try {
//                autoPlus = Class.forName(
//                        "net.java.sip.communicator.impl.media.configuration.SunVideoPlusAuto");
//            }
//            catch (Exception ee) {
//              logger.warn("SunVideoPlusAuto capturer detection failed!", ee);
//            }
//        }
        if (auto == null) {
            try {
                auto = Class.forName(
                        "net.java.sip.communicator.impl.media.configuration.V4LAuto");
            }
            catch (Exception ee) {
                logger.warn("V4lAuto capturer detection failed!", ee);
            }
        }
        try {
            Object instance = auto.newInstance();
            if (autoPlus != null) {
                Object instancePlus = autoPlus.newInstance();
            }
            logger.info("Finished detecting video capture devices");
        }
        catch (ThreadDeath td) {
            throw td;
        }
        catch (Throwable t) {
            logger.error("Capture device detection failed!", t);
        }
    }

    private void detectDirectAudio() {
        Class cls;
        int plType = PlugInManager.RENDERER;
        String dar = "com.sun.media.renderer.audio.DirectAudioRenderer";
        try {
            // Check if this is the Windows Performance Pack - hack
            cls = Class.forName(
                    "net.java.sip.communicator.impl.media.configuration.VFWAuto");
            // Check if DS capture is supported, otherwise fail DS renderer
            // since NT doesn't have capture
            cls = Class.forName("com.sun.media.protocol.dsound.DSound");
            // Find the renderer class and instantiate it.
            cls = Class.forName(dar);

            Renderer rend = (Renderer) cls.newInstance();
            try {
                // Set the format and open the device
                AudioFormat af = new AudioFormat(AudioFormat.LINEAR,
                                                 44100, 16, 2);
                rend.setInputFormat(af);
                rend.open();
                Format[] inputFormats = rend.getSupportedInputFormats();
                // Register the device
                PlugInManager.addPlugIn(dar, inputFormats, new Format[0],
                                        plType);
                // Move it to the top of the list
                Vector rendList =
                    PlugInManager.getPlugInList(null, null, plType);
                int listSize = rendList.size();
                if (rendList.elementAt(listSize - 1).equals(dar)) {
                    rendList.removeElementAt(listSize - 1);
                    rendList.insertElementAt(dar, 0);
                    PlugInManager.setPlugInList(rendList, plType);
                    PlugInManager.commit();
                    //System.err.println("registered");
                }
                rend.close();
            }
            catch (Throwable t) {
                //System.err.println("Error " + t);
            }
        }
        catch (Throwable tt) {
        }
    }

    private void detectS8DirectAudio() {
        Class cls;
        int plType = PlugInManager.RENDERER;
        String dar = "com.sun.media.renderer.audio.DirectAudioRenderer";
        try {
            // Check if this is the solaris Performance Pack - hack
            cls = Class.forName(
                    "net.java.sip.communicator.impl.media.configuration.SunVideoAuto");

            // Find the renderer class and instantiate it.
            cls = Class.forName(dar);

            Renderer rend = (Renderer) cls.newInstance();

            if (rend instanceof ExclusiveUse &&
                ! ( (ExclusiveUse) rend).isExclusive()) {
                // sol8+, DAR supports mixing
                Vector rendList = PlugInManager.getPlugInList(null, null,
                    plType);
                int listSize = rendList.size();
                boolean found = false;
                String rname = null;

                for (int i = 0; i < listSize; i++) {
                    rname = (String) (rendList.elementAt(i));
                    if (rname.equals(dar)) { // DAR is in the registry
                        found = true;
                        rendList.removeElementAt(i);
                        break;
                    }
                }

                if (found) {
                    rendList.insertElementAt(dar, 0);
                    PlugInManager.setPlugInList(rendList, plType);
                    PlugInManager.commit();
                }
            }
        }
        catch (Throwable tt) {
        }
    }

    /**
     * Runs JMFInit the first time the application is started so that capture
     * devices are properly detected and initialized by JMF.
     */
    public static void setupJMF()
    {
        try
        {
            logger.logEntry();

            // .jmf is the place where we store the jmf.properties file used
            // by JMF. if the directory does not exist or it does not contain
            // a jmf.properties file, or if the jmf.properties file has 0 length
            // then this is the first time we're running and should detect capture
            // devices
            String homeDir = System.getProperty("user.home");
            File jmfDir = new File(homeDir, ".jmf");
            String classpath = System.getProperty("java.class.path");
            classpath += System.getProperty("path.separator") +
                jmfDir.getAbsolutePath();
            System.setProperty("java.class.path", classpath);

            if (!jmfDir.exists())
                jmfDir.mkdir();

            File jmfProperties = new File(jmfDir, "jmf.properties");

            if (!jmfProperties.exists()) {
                try {
                    jmfProperties.createNewFile();
                }
                catch (IOException ex) {
                    logger.error(
                        "Failed to create jmf.properties - " +
                        jmfProperties.getAbsolutePath());
                }
            }

            //if we're running on linux checkout that libjmutil.so is where it
            //should be and put it there.
//            runLinuxPreInstall();

            if (jmfProperties.length() == 0) {
                JMFInit init = new JMFInit();
            }
        }
        finally
        {
            logger.logExit();
        }

    }


//    private static void runLinuxPreInstall()
//    {
//        try {
//            logger.logEntry();
//
//            if (Utils.getProperty("os.name") == null
//               || !Utils.getProperty("os.name").equalsIgnoreCase("Linux"))
//                 return;
//
//            try {
//                System.loadLibrary("jmv4l");
//                console.debug("Successfully loaded libjmv4l.so");
//            }
//            catch (UnsatisfiedLinkError err) {
//                console.debug("Failed to load libjmv4l.so. Will try and copy libjmutil.so", err);
//
//                String destinationPathStr = Utils.getProperty("java.home")
//                                              + File.separator + "lib"
//                                              + File.separator + "i386";
//                String libjmutilFileStr   = "libjmutil.so";
//
//                try {
//                    InputStream libIS =
//                        MediaManager.class.getClassLoader().
//                                          getResourceAsStream(libjmutilFileStr);
//                     File outFile = new File(destinationPathStr
//                                             +File.separator + libjmutilFileStr);
//
//                     //Check if file is already there - Ben Asselstine
//                     if (outFile.exists()) {
//                         //if we're here then libjmutil is already where it should be
//                         // but yet we failed to load libjmv4l.
//                         //so notify log and bail out
//                         console.error(
//                             "An error occurred while trying to load JMF. This "
//                             +"error is probably due to a JMF installation problem. "
//                             +"Please copy libjmutil.so to a location contained by "
//                             + "$LD_LIBRARY_PATH and try again!",
//                             err);
//                         return;
//
//                     }
//
//                     outFile.createNewFile();
//
//                     console.debug("jmutil");
//
//                    FileOutputStream fileOS = new FileOutputStream(outFile);
//                    int available = libIS.available();
//                    byte[] bytes = new byte[libIS.available()];
//                    int read = 0;
//                    int i = 0;
//                    for (i = 0; i<available ; i++)
//                    {
//                        bytes[i] = (byte)libIS.read();
//                    }
//
//                    console.debug("Read " + i + " bytes out of " + available );
//
//                    fileOS.write(bytes, 0, bytes.length);
//                    console.debug("Wrote " + available + " bytes.");
//                    bytes = null;
//                    libIS.close();
//                    fileOS.close();
//                }
//                catch (IOException exc) {
//                    if(   exc.getMessage() != null
//                       && exc.getMessage().toLowerCase().indexOf("permission denied") != -1)
//                         console.showError("Permission denied!",
//                                         "Because of insufficient permissions SIP Communicator has failed "
//                                         + "to copy a required library to\n\n\t"
//                                         + destinationPathStr + "!\n\nPlease run the application as root or "
//                                         + "manually copy the " +libjmutilFileStr
//                                         + " file to the above location!\n");
//                    exc.printStackTrace();
//                }
//            }
//                /** @todo check whether we have a permissions problem and alert the
//             * user that they should be running as root */
//            catch(Throwable t)
//            {
//                console.debug("Error while loading");
//            }
//        }
//        finally {
//            console.logExit();
//        }
//    }

    public static void start() {
        setupJMF();
    }
}
