/*
 * File:     SystemInstallationSecurity.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.util;

import mpi.library.util.StringUtil;

import java.io.File;
import java.io.FileWriter;

import java.net.URL;

import java.util.HashSet;
import java.util.logging.Logger;

import javax.swing.JOptionPane;


/**
 * This class verifies the JRE System
 *
 * <ul>
 * <li>
 * The JRE/lib/ext directory is tested
 * </li>
 * </ul>
 *
 * Failure of this class means Non-predictable behaviour of a program.
 */
public final class SystemInstallationSecurity {
    private static SystemInstallationSecurity _singleton = null;
    private static boolean _done = false;
    private static boolean restartIsNecessary = false;
    private static final Logger LOG = Logger.getLogger(SystemInstallationSecurity.class.getName());

    /**
     * Constructor private because Singleton. Singleton because a tool, that
     * starts up another one, will have executed SIS for it.
     */
    private SystemInstallationSecurity() {
    }

    /**
     * verify lib/ext
     *
     * @throws Exception DOCUMENT ME!
     */
    private final void verifyLibExt() throws Exception {
        if (SystemInstallationSecurity._done) {
            return;
        }

        File extDir = SystemReporting.getLibExtDir();

        if ((extDir == null) || !extDir.exists()) {
            System.out.println("Extension directory does not exist");

            return;
        }

        String thelibextString = extDir.toString().toUpperCase();
        LOG.info("verifying lib/ext " + thelibextString);

        /*
        if (SystemInstallationSecurity._done) {
            return;
        }
        */
        //MK:02/08/02 unsetting the SecurityManager serves two reasons:
        // - http://developer.java.sun.com/developer/bugParade/bugs/4387437.html
        // - speed
        System.setSecurityManager(null);

        // Required extensions
        String[] snoopString = new String[40];

        // Accepted extensions
        String[] acceptString = new String[40];

        int NOFsnoop = 0;
        int NOFaccept = 0;

        for (int ii = 0; ii < 10; ii++) {
            snoopString[ii] = System.getProperty("SIS.snoop." + ii);
            acceptString[ii] = System.getProperty("SIS.accept." + ii);

            if (snoopString[ii] != null) {
                NOFsnoop = ii + 1;
            }

            if (acceptString[ii] != null) {
                NOFaccept = ii + 1;
            }
        }

        if (NOFsnoop == 0) {
            return;
        }

        File[] potext = SystemReporting.getLibExt();
        int NOFfiles = (potext == null) ? 0 : potext.length;

        HashSet goodFiles = new HashSet();

        if (System.getProperty("java.version").startsWith("1.4") &&
                SystemReporting.OS_NAME.startsWith("Windows")) {
            System.out.println("\taccepting Java 1.4 Win32 files");
            goodFiles.add("dnsns.jar");
            goodFiles.add("ldapsec.jar");
            goodFiles.add("localedata.jar");
            goodFiles.add("sunjce_provider.jar");
        } else if (SystemReporting.OS_NAME.startsWith("Mac")) {
            // when a file is copied in Mac OS X a .DS_Store file is created 
            // in that directory. This doesn't hurt, so accept it.
            goodFiles.add(".DS_Store");
        }

        for (int ii = 0; ii < NOFaccept; ii++) {
            goodFiles.add(acceptString[ii]);
            LOG.info("\taccepting (" + acceptString[ii] + ")");
        }

        for (int ii = 0; ii < NOFsnoop; ii++) {
            boolean found = false;
            LOG.info("snooping " + snoopString[ii] + " ...");

            URL url = this.getClass().getResource(snoopString[ii]);

            if (url == null) {
                LOG.warning("cannot snoop " + snoopString[ii]);
            } else {
                //	System.out.println("say hello to (" + url + ")");
                String filename = url.getFile();

                //	System.out.println("filename:" + filename);
                filename = StringUtil.replace(filename, "!" + snoopString[ii],
                        "");
                filename = StringUtil.replace(filename, "file:", "");

                filename = StringUtil.replace(filename, "%20", " ");

                //	System.out.println("  source (" + filename + ")");
                File source = new File(filename);
                String parentOfSource = source.getParent();
                parentOfSource = StringUtil.replace(parentOfSource, "%20", " ");
                parentOfSource = parentOfSource.toUpperCase();

                /*
                   Is the source in lib/ext?
                 */

                //	System.out.println(" parent of source = " + parentOfSource);
                boolean fromlibext = parentOfSource.equals(thelibextString);

                if (fromlibext) {
                    goodFiles.add(source.getName());
                    LOG.info("...found");
                } else {
                    // assume: from JNLP-cache
                    // do a test
                    if (source.getName().startsWith("RM")) {
                        restartIsNecessary = true;

                        try {
                            // remove RM from filename in cache
                            File destFile = new File(extDir,
                                    source.getName().substring(2));
                            FileUtility.copyToFile(source, destFile);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }

                        File copy = new File(extDir,
                                source.getName().substring(2));

                        if (copy.exists()) {
                            goodFiles.add(copy.getName());
                            LOG.info("...copied (" + copy + ")");
                        } else {
                            LOG.warning("  FAILURE to copy (" + copy + ")");

                            /*
                            JOptionPane.showMessageDialog(null,
                                ("  FAILURE to write (" + copy +
                                ")\nContact your administrator"), "",
                                JOptionPane.ERROR_MESSAGE);
                                */
                        }
                    } else {
                        LOG.warning(source + " does not start with RM !!!!");
                    }
                }
            }
        }

        String badfiles = "";

        for (int i = 0; i < NOFfiles; i++) {
            String fn = potext[i].getName();
            LOG.info("\t verify (" + fn + ")");

            if (goodFiles.contains(fn)) {
                continue;
            }

            if (fn.startsWith("nl.mpi.")) {
                File deleteme = new File(extDir, fn);
                FileWriter out = new FileWriter(deleteme);

                if (deleteme.canWrite()) {
                    LOG.info("can write to " + deleteme);
                } else {
                    LOG.info("CAN'T write to " + deleteme);
                }

                try {
                    out.write('x');
                } catch (Exception ioe) {
                    /*
                    JOptionPane.showMessageDialog(null,
                        ("  FAILURE to access (" + deleteme +
                        ")\nContact your administrator"), "",
                        JOptionPane.ERROR_MESSAGE);
                        */
                    LOG.warning("FAILURE to access (" + deleteme +
                        ")\nContact your administrator");
                }

                out.flush();
                out.close();
            } else {
                badfiles = badfiles + "\n  " + fn;
            }
        }

        if (badfiles.length() != 0) {
            /*
            JOptionPane.showMessageDialog(null,
                "WARNING: your java environment contains unknown files " +
                "that can effect proper functioning of the MPI-tools.\n" +
                "Directory is: " + SystemReporting.getLibExtDir() +
                "\nfiles are: " + badfiles, "", JOptionPane.ERROR_MESSAGE);
                */
            LOG.warning(
                "WARNING: your java environment contains unknown files " +
                "that can effect proper functioning of the MPI-tools.\n" +
                "Directory is: " + SystemReporting.getLibExtDir() +
                "\nfiles are: " + badfiles);
        }

        if (restartIsNecessary) {
            JOptionPane.showMessageDialog(null,
                ("Start the tool again to enable Unicode input methods"), "",
                JOptionPane.ERROR_MESSAGE);

            restartIsNecessary = false;
        }

        _done = true;
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public static final SystemInstallationSecurity Instance() {
        if (_singleton == null) {
            _singleton = new SystemInstallationSecurity();
        }

        return _singleton;
    }

    /**
     * The only public method
     */
    public final void go() {
        try {
            verifyLibExt();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * DOCUMENT ME!
     *
     * @param a DOCUMENT ME!
     */
    public static void main(String[] a) {
        SystemInstallationSecurity sis = SystemInstallationSecurity.Instance();
    }
}
