/*
 * File:     DetectMediaFrameworks.java
 * Project:  MPI Linguistic Application
 * Date:     03 April 2006
 *
 * Copyright (C) 2001-2006  Max Planck Institute for Psycholinguistics
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package mpi.eudico.client.annotator.player;

import java.io.File;

import java.util.ArrayList;


/**
 * DetechMediaFrameworks: detects JMF Video / Audio - Quicktime
 *  on various platforms
 *
 * notes: this class does not required QT jars or JMF jars be loaded
 *
 * bugs: Quicktime version are not checked - the QuickTimePlayer should
 *     do this check
 *
 * useage:
 *        int a = DetectMediaFrameworks.getSupportedMediaFrameworksBitmap();
 *        if (a & DetectMediaFrameworks.JMF_VIDEO)
 *            // is jmf
 *        if (a & DetectMediaFrameworks.QT_VIDEOAUDIO)
 *            // is qt
 *
 *        PlayerFactory.createPlayer(JMF_VIDEO);
 *    --or--
 *        ArrayList al =  DetectMediaFrameworks.getSupportedMediaFrameworksNames();
 *        JList jl = new JList(al);
 *        ..
 *        ..
 *         ..
 *        PlayerFactory.createPlayer(jl.selectedItemText());
 *
 *
 */
public class DetectMediaFrameworks {
    public static String FRAMEWORK = "mediaframework";
    public static int JMF_AUDIO = 0x01;
    public static int JMF_VIDEO = 0x02;
    public static int QT_VIDEOAUDIO = 0x04;
    public static String STR_JMF_AUDIO = "JMF Audio Only";
    public static String STR_JMF_VIDEO = "JMF Video and Audio";
    public static String STR_QT_VIDEOAUDIO = "Quicktime Video and Audio";

    // default framework
    private static String defaultFramework = STR_JMF_VIDEO;

    // core QuickTime libs
    private static String[] QUICKTIMELIB = {
        "QuickTime.cpl", "QuickTime.qts", 
        // isn't necessary
        //     "QuickTimeVR.qtx",
        "QuickTime\\QuickTimeMPEG.qtx", "QuickTime\\QuickTimeMPEG4.qtx"
    };

    /**
      * returns the framework perferred framework
     *  if JMF Video-Audio is supported it is the default
     *  if QT is supported but NOT JMF qt is the default
     */
    public static String getDefaultFramework() {
        return defaultFramework;
    }

    /**
     *  sets the default frame works
     *  throws an exception if frame work is not supported
      */
    public static void setDefaultFramework(String fw) throws Exception {
        // make sure fw matches supported frameworks
        if (fw.equals(STR_JMF_AUDIO) | fw.equals(STR_JMF_VIDEO) |
                fw.equals(STR_QT_VIDEOAUDIO)) {
            defaultFramework = fw;

            return;
        }

        throw new Exception("Invalid Framework name");
    }

    /**
     * returns alls the frameworks that could be supported
     */
    public static ArrayList getMediaFrameworkNames() {
        ArrayList al = new ArrayList(3);
        al.add(STR_JMF_AUDIO);
        al.add(STR_JMF_VIDEO);
        al.add(STR_QT_VIDEOAUDIO);

        return al;
    }

    /**
    * returns an ArrayList of names that label the upported media frameworks
    */
    public static int getSupportedMediaFrameworksBitmap() {
        // All platforms will support PCM audio with JMF X-Platform
        int detected = JMF_AUDIO;

        // JMF Platform Checks
        try {
            System.loadLibrary("jmutil"); //lin/sol mpeg decoder
            detected = detected | JMF_VIDEO;
        } catch (java.lang.UnsatisfiedLinkError e) {
            //System.out.println(e);
        } catch (java.lang.SecurityException e) {
            //System.out.println(e);
        }

        try {
            System.loadLibrary("jmvfw"); //vid for windows jni
            System.loadLibrary("jmam"); //active movie
            detected = detected | JMF_VIDEO;
        } catch (java.lang.UnsatisfiedLinkError e) {
        } catch (java.lang.SecurityException e) {
        }

        // Quicktime for OS X and Win32
        try {
            String s = System.getProperty("os.name");

            if (s.regionMatches(false, 0, "Darwin", 0, 6) ||
                    s.regionMatches(false, 0, "Mac OS X", 0, 8)) {
                /*
                 * OS X includeds QT/QT4Java with the distro
                 * we can do a simple sanity check that QTJava.zip is
                 * visible from JNLP
                 */
                ClassLoader cl = ClassLoader.getSystemClassLoader();
                cl.loadClass("quicktime.QTSession");
                detected = detected | QT_VIDEOAUDIO;
            } else if (s.regionMatches(false, 0, "Win", 0, 3)) {
                // Check for specific file in <SYSTEMROOT>/System32
                //  because QT uses custom extentions that are
                //  really dlls but can not be loaded via
                //  LoadLibrary
                if (verifySystem32Libs(QUICKTIMELIB) == false) {
                    throw new Exception("Invalid QT Libs");
                }

                detected = detected | QT_VIDEOAUDIO;
            }
        } catch (java.lang.UnsatisfiedLinkError e) {
        } catch (java.lang.SecurityException e) {
        } catch (java.lang.Exception e) {
            e.printStackTrace();
        }

        return detected;
    }

    public static ArrayList getSupportedMediaFrameworksNames() {
        int detected = 0;
        detected = getSupportedMediaFrameworksBitmap();

        ArrayList al = new ArrayList(1);
        int ct = 0;

        // build the array if support types
        if ((detected & JMF_AUDIO) != 0) {
            al.add(STR_JMF_AUDIO);
        }

        if ((detected & JMF_VIDEO) != 0) {
            al.add(STR_JMF_VIDEO);
        }

        if ((detected & QT_VIDEOAUDIO) != 0) {
            al.add(STR_QT_VIDEOAUDIO);
        }

        return (al);
    }

    /**
     *  purpose: verifys existance of a list of files in <SYSTEMROOT>/System32
     *  params: String array of lib names
     *   returns: bool on successfull match of all libs
     */
    public static boolean verifySystem32Libs(String[] arylibs) {
        String windir = "";

        // first verify valid lib array
        if (null == arylibs) {
            return false;
        }

        if (0 == arylibs.length) {
            return false;
        }

        if ((windir = getEnv("SYSTEMROOT")) == null) {
            System.err.println("NO SYSTEM ROOT");

            return false; // no system root...
        }

        // sanity check that <SYSTEMROOT>/System32 exists
        if (!(new File(windir + "\\system32")).isDirectory()) {
            if (!(new File(windir + "\\system")).isDirectory()) //Win95/98
             {
                System.err.println("Failed to locate " + windir +
                    "/System dir");

                return false;
            } else {
                windir += "\\system\\";
            }
        } else {
            windir += "\\system32\\";
        }

        // loop tru the arylibs and verfity that each file exists
        for (int i = 0; i < arylibs.length; i++) {
            if (!(new File(windir + arylibs[i])).exists()) {
                return false;
            }
        }

        return true;
    }

    /**
     * win32 only - opens a shell and askes CMD for an ENV variable
     */
    public static String getEnv(String name) {
        String cmd = "cmd /c echo";
        int b;

        // if not win32 bail out
        String s = System.getProperty("os.name");

        if (!s.regionMatches(false, 0, "Win", 0, 3)) {
            return null;
        }

        s = "";

        try {
            Runtime rt = Runtime.getRuntime();
            cmd += (" %" + name + "%");

            Process p = rt.exec(cmd);

            java.io.InputStream is = p.getInputStream();

            while ((b = is.read()) >= 0) {
                if (b > 13) // check of <lf> <cr>
                 {
                    s += (char) b;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        s.trim();

        if (s.length() == 0) {
            return null;
        }

        return s;
    }
}
