package com.marinilli.b2.c7.launcher;
import java.awt.event.*;
import java.util.Properties;
import java.util.ArrayList;
import java.util.StringTokenizer;
import java.io.IOException;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.File;
import javax.swing.*;
import java.awt.*;
import javax.swing.border.*;
import javax.swing.event.*;

/**
 * Chapter 7 - the main class for the CD-ROM installer
 *
 * @author Mauro Marinilli
 * @version 1.0
 */
public class CDLauncher extends JFrame implements Runnable {
  private final static String PROPS_FILENAME = "install.properties";
  public final static String SETUP_DIR = "setup/";
  public final static String SETUP_RES_DIR = SETUP_DIR + "res/";
  private String currentDir;
  private Properties installationSettings;
  private String appName;
  private String appIconName;
  private String appLargeIconName;
  private int alreadyInstalledFiles;
  private String destinationDir;
  private String applDesc;
  public static ImageIcon installIcon;

  private String[] minInstallationFiles;
  private String[] fullInstallationFiles;
  private String[] fullInstallationDesc;
  private String[] typicalInstallationFiles;
  private boolean installJre = true;
  private boolean showReadme = true;
  private String[] resources;

  //GUI stuff
  JPanel jPanel1 = new JPanel();
  JPanel jPanel2 = new JPanel();
  JRadioButton jRadioMinimal = new JRadioButton();
  JRadioButton jRadioCustom = new JRadioButton();
  JRadioButton jRadioTypical = new JRadioButton();
  JButton installButton = new JButton();
  JLabel imageLabel = new JLabel();
  JTextArea msgTextArea = new JTextArea();

  /**
   *  Constructor
   */
  public CDLauncher() {
    currentDir = System.getProperty("user.dir") + System.getProperty("file.separator");
    loadProperties();

    // GUI setup
    setIconImage(new ImageIcon(appIconName).getImage());
    installIcon = new ImageIcon(SETUP_DIR + "icon.gif");
    Box box1 = Box.createVerticalBox();
    TitledBorder titledBorder1 =
        new TitledBorder(BorderFactory.createLineBorder(Color.lightGray,2),"Installation Options");
    setTitle("Installer");
    setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
    addWindowListener(new java.awt.event.WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        quitInstallation();
      }
    });
    // radio buttons setting
    jRadioMinimal.setText("minimal");
    jRadioCustom.setText("custom");
    jRadioTypical.setText("typical");
    jRadioTypical.setSelected(true);//the default one
    ButtonGroup group = new ButtonGroup();
    installButton.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        install();
      }
    });
    group.add(jRadioMinimal);
    group.add(jRadioTypical);
    group.add(jRadioCustom);

    installButton.setText("Install");
    installButton.setIcon(installIcon);
    jPanel2.setBorder(titledBorder1);
    jPanel2.setLayout(new BorderLayout());
    imageLabel.setIcon(new ImageIcon(appLargeIconName));
    jPanel1.setLayout(new BorderLayout());
    msgTextArea.setPreferredSize(new Dimension(180,80));
    msgTextArea.setBorder(BorderFactory.createEmptyBorder(4,6,4,6));
    msgTextArea.setText(applDesc);
    msgTextArea.setLineWrap(true);
    msgTextArea.setEditable(false);
    msgTextArea.setWrapStyleWord(true);

    getContentPane().add(jPanel1, BorderLayout.CENTER);
    jPanel1.add(imageLabel, BorderLayout.CENTER);
    jPanel1.add(msgTextArea, BorderLayout.EAST);
    jPanel1.setBackground(Color.white);
    getContentPane().add(jPanel2, BorderLayout.SOUTH);
    jPanel2.add(box1, BorderLayout.CENTER);
    box1.add(jRadioMinimal, null);
    box1.add(jRadioTypical, null);
    box1.add(jRadioCustom, null);
    jPanel2.add(installButton, BorderLayout.EAST);

    //shows up
    pack();
    if (getSize().width < 256)
      setSize(400, 256);
    setVisible(true);
  }

  /**
   * Loads properties file
   */
  private void loadProperties(){
    try {
      installationSettings = new Properties();
      FileInputStream in = new FileInputStream(SETUP_DIR+PROPS_FILENAME);
      installationSettings.load(in);
      //now reads in all variables
      appName = installationSettings.getProperty("application-name", "Application");
      appIconName = SETUP_DIR + installationSettings.getProperty("application-icon", "");
      appLargeIconName = SETUP_DIR + installationSettings.getProperty("application-large-icon", "");
      applDesc = installationSettings.getProperty("application-desc", "");

      minInstallationFiles =
          getItems(installationSettings.getProperty("application-minimal-set", ""));
      fullInstallationFiles =
          getItems(installationSettings.getProperty("application-full-set", "m.jar"));
      typicalInstallationFiles =
          getItems(installationSettings.getProperty("application-typical-set", ""));
      destinationDir = installationSettings.getProperty("destination-dir", "c:\\app\\");
      fullInstallationDesc =
          getItems(installationSettings.getProperty("application-full-desc", "basic"));

      in.close();
    }
    catch (IOException ex) {
      System.out.println("ApplicationHelper- loadProperties(): " + ex);
    }
  }

  /**
   * It obtains tokens from a string
   */
  private String[] getItems(String s){
    ArrayList result = new ArrayList();
    StringTokenizer st = new StringTokenizer(s,";:");
    while (st.hasMoreTokens()) {
      String w = st.nextToken();
      result.add(w);
    }
    String[] a = new String[result.size()];
    result.toArray(a);
    return a;
  }

  /**
   * Install the application
   */
  public void install() {
    if (jRadioCustom.isSelected()) {
      // the custom option has been chosen
      CustomInstallDialog cid = new CustomInstallDialog(this);
      cid.setVisible(true);
      install(cid.getChosenResources());
    } else if (jRadioTypical.isSelected()) {
      //
      install(typicalInstallationFiles);
    } else if (jRadioMinimal.isSelected()) {
      //
      install(minInstallationFiles);
    }
  }

  /**
   * Install the specified set of files
   */
  private void install(String[] res) {
    if (res == null)
      return;
    resources = res;
    SummaryDialog sd = new SummaryDialog(this);
    sd.setVisible(true);
    if (!sd.isInstallChoice())
      return;

    alreadyInstalledFiles = 0;
    Thread t = new Thread(this);
    t.start();

    new InstallationProgressDialog(this);
  }


  /**
   * launch the installer thread
   */
  public void run() {
    if (isInstallJre())
      installJre();
    // install chosen files
    File f = new File(destinationDir);
    f.mkdirs();

    File file;
    for (int i = 0; i < resources.length; i++) {
      alreadyInstalledFiles++;
      try {
        copy(resources[i]);
        Thread.currentThread().sleep(1000);//XXX only cosmetics: remove it!
      } catch (Exception ex) {
        System.out.println("During Installation: "+ex);
      }
    }
    installCustom();
    // installation finished
    alreadyInstalledFiles = -1;
    if (isShowReadme()) {
      ReadDialog rd = new ReadDialog(this);
    }
    installationFinished();
  }

  /**
   * performs the actual files copy
   */
  private void copy (String from){
    try {
      File inputFile = new File(currentDir + SETUP_RES_DIR + from);
      File outputFile = new File(destinationDir + from);
      System.out.println("from="+inputFile+" to="+outputFile);

      FileInputStream in = new FileInputStream(inputFile);
      FileOutputStream out = new FileOutputStream(outputFile);
      int c;

      while ((c = in.read()) != -1)
         out.write(c);
      in.close();
      out.close();
    }
    catch (Exception ex) {
      System.out.println("during file copy: "+ex);
    }
  }

  /**
   * installs the proper JRE depending the current OS
   */
  private void installJre(){
    System.out.println("installJre()"+System.getProperty("os.name"));
    final String WIN_PATH = "jre\\win\\";
    if (System.getProperty("os.name").indexOf("Win")!=-1) {
      File f = new File(currentDir + WIN_PATH);
      String jres[] = f.list();
      System.out.println("Installing WIN JRE:" + jres[0]);
      try {
        Runtime.getRuntime().exec(currentDir + WIN_PATH + jres[0]);
      } catch (Exception ex) {
        System.out.println("Installing JRE: "+ex);
      }
      alreadyInstalledFiles ++;
    }
  }

  /**
   * performs some special-purpose code
   */
  private void installCustom(){
    // add your code here, if needed
    // ...
    alreadyInstalledFiles ++;
  }

  /**
   * ask before leaving the installation
   */
  public void quitInstallation() {
    int choice = JOptionPane.showConfirmDialog(this,
                                "Are You Sure?",
                                "Quit Installation",
                                JOptionPane.OK_CANCEL_OPTION,
                                JOptionPane.WARNING_MESSAGE);
    if (choice == JOptionPane.CANCEL_OPTION) {
      setVisible(true);
      return;
    }
    installationFinished();
  }

  /**
   * obtain the readme file
   */
  public String getReadme(){
    StringBuffer s = new StringBuffer();
    try {
      FileReader fr = new FileReader(currentDir + SETUP_RES_DIR + "readme");

      char buffer[] = new char[512];
      int i;
      while((i = fr.read(buffer)) != -1)
        s.append(buffer,0,i);
    } catch (Exception ex) {
      System.out.println("during readme file read: "+ex);
    }
    return s.toString();
  }

  /**
   * invoked at the end of the installation
   */
  public void installationFinished(){
    System.out.println("Installation Finished.");
    System.exit(0);
  }


  // accessory methods

  public int getAlreadyInstalled(){
    return alreadyInstalledFiles;
  }

  public int getTotalItemsToInstall(){
    return resources.length;
  }

  public String getDestinationDir(){
    return destinationDir;
  }

  public void setDestinationDir(String dir){
    destinationDir = dir;
  }

  public void setInstallJre(boolean newInstallJre) {
    installJre = newInstallJre;
  }

  public boolean isInstallJre() {
    return installJre;
  }

  public void setShowReadme(boolean newShowReadme) {
    showReadme = newShowReadme;
  }

  public boolean isShowReadme() {
    return showReadme;
  }

  public String[] getFullInstallationFiles() {
    return fullInstallationFiles;
  }

  public String[] getFullInstallationDesc() {
    return fullInstallationDesc;
  }

  /**
   * main method
   */
  public static void main(String[] args) {
    CDLauncher CDLauncher1 = new CDLauncher();
  }
}