package org.limewire.ui.swing;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.net.*;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

import org.limewire.ui.support.FatalBugManager;
import org.limewire.ui.swing.util.GuiUtils;

import com.limegroup.gnutella.util.LimeWireUtils;

import org.limewire.util.Version;
import org.limewire.util.VersionFormatException;

final class GuiLoader {

    /** 
     * Creates an {@link Initializer} instance that constructs the 
     * necessary classes for the application.
     *
     * <p>Invoked by {@link Main} by reflection.
     *
     * @param args the array of command line arguments
     * @param frame the splash screen; null, if no splash is displayed
     */
    public void load(String args[], Frame splashFrame, Image splashImage) {
        try { 
            //sanityCheck();
            Initializer initializer = new Initializer();
            initializer.initialize(args, splashFrame, splashImage);
            Version currversion = null;
            try {
            	currversion = new Version(getVersion("http://wireshare.sourceforge.net/version"));
            } catch (VersionFormatException impossible){};
            if ( currversion != null ) {
            	if (currversion.compareTo( new Version(LimeWireUtils.getLimeWireVersion())) > 0 && !LimeWireUtils.isBetaRelease()) {
            		int reply = JOptionPane.showConfirmDialog (null,  
            			"WireShare version " + currversion.toString() + " is now available. Would you like to open the download page?", 
            			"Updated version available",
            			JOptionPane.YES_NO_OPTION,
            			JOptionPane.INFORMATION_MESSAGE );
            		if (reply == JOptionPane.YES_OPTION) openUrl("http://sourceforge.net/projects/wireshare/files/");
            	}
            }
        }
//        catch(StartupFailedException sfe) {
//            GuiUtils.hideAndDisposeAllWindows();
//            showCorruptionError(sfe);
//            System.exit(1);
//        }
        catch(Throwable err) {
            GuiUtils.hideAndDisposeAllWindows();
            try {
                FatalBugManager.handleFatalBug(err);
            } catch(Throwable t) {
                Throwable error = err;
                try {
                    t.initCause(err);
                    error = t;
                } catch(Throwable ignored) {}
                showCorruptionError(error);
                System.exit(1);
            }
        }
    }

    /**
     * Display a standardly formatted internal error message
     * coming from the backend.
     *
     * @param err the <tt>Throwable</tt> object containing information 
     *  about the error
     */ 
    private static final void showCorruptionError(Throwable err) {
        err.printStackTrace();
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        pw.println("WireShare version " + LimeWireUtils.getLimeWireVersion());
        pw.print("Java version ");
        pw.print(System.getProperty("java.version", "?"));
        pw.print(" from ");
        pw.println(System.getProperty("java.vendor", "?"));
        pw.print(System.getProperty("os.name", "?"));
        pw.print(" v. ");
        pw.print(System.getProperty("os.version", "?"));
        pw.print(" on ");
        pw.println(System.getProperty("os.arch", "?"));
        Runtime runtime = Runtime.getRuntime();
        pw.println("Free/total memory: "
                   +runtime.freeMemory()+"/"+runtime.totalMemory());
        pw.println();
        
        err.printStackTrace(pw);
        
        pw.println();
        
        pw.println("STARTUP ERROR!");
        pw.println();
        
        pw.flush();
        
        displayError(sw.toString());
    }
    
    /**
     * Displays an internal error with specialized formatting.
     */
    private static final void displayError(String error) {
        System.out.println("Error: " + error);
        final JDialog DIALOG = new JDialog();
        DIALOG.setModal(true);
        final Dimension DIALOG_DIMENSION = new Dimension(350, 200);
        final Dimension INNER_SIZE = new Dimension(300, 150);
        DIALOG.setSize(DIALOG_DIMENSION);

        JPanel mainPanel = new JPanel();
        mainPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
        mainPanel.setLayout(new BorderLayout());


        String instr0;
        String instr1;
        String instr2;
        String instr3;
        String instr4;
        String instr5;
        
        instr0 = "One or more necessary files appear to be invalid.";
        instr1 = "This is generally caused by a corrupted installation.";
        instr2 = "Please try downloading and installing WireShare again.";
        instr3 = " ";
        instr4 = " ";
        instr5 = "Thank you.";

        JLabel label0 = new JLabel(instr0);
        JLabel label1 = new JLabel(instr1);
        JLabel label2 = new JLabel(instr2);
        JLabel label3 = new JLabel(instr3);
        JLabel label4 = new JLabel(instr4);
        JLabel label5 = new JLabel(instr5);
        
        JPanel labelPanel = new JPanel();
        JPanel innerLabelPanel = new JPanel();
        labelPanel.setLayout(new BoxLayout(labelPanel, BoxLayout.X_AXIS));
        innerLabelPanel.setLayout(new BoxLayout(innerLabelPanel, BoxLayout.Y_AXIS));
        innerLabelPanel.add(label0);
        innerLabelPanel.add(label1);
        innerLabelPanel.add(label2);
        innerLabelPanel.add(label3);
        innerLabelPanel.add(label4);
        innerLabelPanel.add(label5);
        innerLabelPanel.add(Box.createVerticalStrut(6));
        labelPanel.add(innerLabelPanel);
        labelPanel.add(Box.createHorizontalGlue());


        final JTextArea textArea = new JTextArea(error);
        textArea.selectAll();
        textArea.copy();
        textArea.setColumns(50);
        textArea.setEditable(false);
        JScrollPane scroller = new JScrollPane(textArea);
        scroller.setBorder(BorderFactory.createEtchedBorder());
        scroller.setPreferredSize(INNER_SIZE);


        JPanel buttonPanel = new JPanel();
        JButton copyButton = new JButton("Copy Report");
        copyButton.addActionListener(new ActionListener() {
            @Override
			public void actionPerformed(ActionEvent e) {
                textArea.selectAll();
                textArea.copy();
            }
        });
        JButton quitButton = new JButton("Ok");
        quitButton.addActionListener(new ActionListener() {
            @Override
			public void actionPerformed(ActionEvent e){
                DIALOG.dispose();
            }
        });
        buttonPanel.add(copyButton);
        buttonPanel.add(quitButton);

        mainPanel.add(labelPanel, BorderLayout.NORTH);
        mainPanel.add(scroller, BorderLayout.CENTER);
        mainPanel.add(buttonPanel, BorderLayout.SOUTH);

        DIALOG.getContentPane().add(mainPanel);
        DIALOG.pack();        

        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        Dimension dialogSize = DIALOG.getSize();
        DIALOG.setLocation((screenSize.width - dialogSize.width)/2,
                           (screenSize.height - dialogSize.height)/2);
        DIALOG.setVisible(true);
    }   
    
    private String getVersion(String urlToRead) {
    	String result = null;
    	try {
           URL url = new URL(urlToRead);
           HttpURLConnection conn = (HttpURLConnection) url.openConnection();
           BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
           result = rd.readLine();
           rd.close();
        } catch (IOException e) {
        } catch (Exception e) {
        }
        return result;
    }
    
    public void openUrl(String url) throws IOException, URISyntaxException {
    	  if(java.awt.Desktop.isDesktopSupported() ) {
    	        java.awt.Desktop desktop = java.awt.Desktop.getDesktop();

    	        if(desktop.isSupported(java.awt.Desktop.Action.BROWSE) ) {
    	          java.net.URI uri = new java.net.URI(url);
    	              desktop.browse(uri);
    	        }
    	  } 
     }
    
    /**
     * Determines whether or not specific files exist and are the correct size.
     * If they do not exist or are the incorrect size, 
     * throws MissingResourceException.
     */         
//    private static void sanityCheck() throws StartupFailedException {
//        File test = new File("gpl.txt");
//        boolean isCVS = false;
//        
//        // If the gpl.txt exists, then we're running off of CVS.
//        if( test.exists() && test.isFile() ) {
//            isCVS = true;
//        }
//        // If it doesn't, we're a production version.
//        else {
//            isCVS = false;
//        }
//        
//        String root = isCVS ? "../lib/jars" : (isWindows() ? "./lib" : ".");        
//        File themesJar = new File(root, "themes.jar");
//        
//        if( !isCVS && (!themesJar.exists() || !themesJar.isFile()) )
//            throw new StartupFailedException("invalid themes.jar");
//            
//        // Then do more advanced hash checks.
//        try {
//            verifyHashes(root);
//        } catch(IOException e) {
//            throw new StartupFailedException(e.getMessage());
//        }
//    }
//    
//    /**
//     * Loads up a file 'hashes' and verifies that all the files/hashes
//     * in it match the hashes we have.
//     */
//    private static void verifyHashes(String root) throws IOException, StartupFailedException {
//        // Load up the file with the hashes.
//        Properties props = new Properties();
//        FileInputStream fis = null;
//        try {
//            fis = new FileInputStream(new File(root, "hashes"));
//            props.load(fis);
//        } finally {
//            if( fis != null ) {
//                try {
//                    fis.close();
//                    fis = null;
//                } catch(IOException ignored) {}
//            }
//        }
//        
//        //Iterate through each expected hash to verify that
//        //the files on disk are not corrupted.
//        Enumeration names = props.propertyNames();
//        while(names.hasMoreElements()) {
//            String name = (String)names.nextElement();
//            String storedHash = props.getProperty(name);
//            String realHash = hash(new File(root, name));
//            if(!realHash.equals(storedHash)) {
//                throw new StartupFailedException(
//                    "file [" + name + "] has hash of [" + realHash +
//                    "] instead of expected [" + storedHash + "]");
//            }
//        }
//    }
//    
//    /**
//     * Determines the MD5 hash of the specified file.
//     */
//    private static String hash(File f) throws IOException {        
//        FileInputStream fis = null;     
//        try {
//            fis = new FileInputStream(f);
//            MessageDigest md = null;
//            try {
//                md = MessageDigest.getInstance("MD5");
//            } catch(NoSuchAlgorithmException e) {
//                throw new IOException("Unknown algorithm: MD5");
//            }
//            
//            byte[] buffer = new byte[16384];
//            int read;
//            while ((read=fis.read(buffer)) != -1) {
//                md.update(buffer, 0, read);
//            }
//            
//            return toHexString(md.digest());
//        } finally {
//            if( fis != null ) {
//                try {
//                    fis.close();
//                } catch(IOException ignored) {}
//            }
//        }
//    }
//    
//    /**
//     * Converts a 16-byte array of unsigned bytes
//     * to a 32 character hex string.
//     */
//    private static String toHexString(byte[] data) {
//        StringBuilder sb = new StringBuilder(32);
//        for(int i = 0; i < data.length; i++) {
//            int asInt = data[i] & 0x000000FF;
//            String x = Integer.toHexString(asInt);
//            if(x.length() == 1)
//                sb.append("0");
//            sb.append(x);
//        }
//        return sb.toString().toUpperCase();
//    }
//    
//    /**
//     * @return if we're running on windows without using OSUtils.
//     */
//    private static boolean isWindows() {
//        String os = System.getProperty("os.name").toLowerCase(Locale.US);
//        return os.contains("windows");
//    }

//    private static class StartupFailedException extends Exception {
//        StartupFailedException(String msg) {
//            super(msg);
//        } 
//        
//        StartupFailedException() {
//            super();
//        }
//    }
    
}
