/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.statcato.file;

import org.statcato.*;
import org.statcato.spreadsheet.*;
import org.statcato.utils.HelperFunctions;
import org.statcato.utils.SetProjectAutoSaveTimer;

import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.util.zip.GZIPOutputStream;
import java.util.zip.GZIPInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.IOException;
import java.io.File;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;


/**
 * A project file that stores  the LogWindow instance and DatasheetTabbedPane
 * instance of this application.
 * 
 * @author Margaret Yau
 * @version %I%, %G%
 * @since 1.0
 */
public class Project {
    private LogWindow Log;
    private DatasheetTabbedPane DatasheetPane;
    private Statcato app;
    private File savedFile;
    public static String extension = "stc";
    private File tempFile;
    private int AUTOSAVEINTERVAL = 300;
    private boolean DELETEAUTOSAVEFILE = true;
    SetProjectAutoSaveTimer timer;

    /**
     * Constructor.
     * 
     * @param app Parent Statcato application
     */
    public Project(Statcato app) {
        this.Log = app.getLogTextPane();
        this.DatasheetPane = app.getDatasheetTabbedPane();
        this.app = app;
        tempFile = new File("~statcato.tmp." +
                HelperFunctions.getCurrentTimeString() + ".stc");
        // start timer to auto save project periodically
        timer = new SetProjectAutoSaveTimer(this, AUTOSAVEINTERVAL);
    }

    /**
     * Sets the auto save interval variable to the given value.
     * 
     * @param seconds number of seconds
     */
    public void setAutoSaveInterval(int seconds) {
        AUTOSAVEINTERVAL = seconds;
        timer.setInterval(seconds);
    }

    /**
     * Sets the delete auto save file boolean to the given value.
     *
     * @param delete boolean indicating whether to delete auto save file 
     */
    public void setDeleteAutoSaveFile(boolean delete) {
        DELETEAUTOSAVEFILE = delete;
    }

    /**
     * Returns whether this project exists (is valid).
     *
     * @return whether this project exists (is valid)
     */
    public boolean exists() {
        return !getName().equals("");
    }
    
    /**
     * Returns true if the project is modified since the last save.
     * 
     * @return true if the project is modified since the last save or 
     * false otherwise
     */
    public boolean isModified() {
        return (Log.getChangedStatus() || DatasheetPane.getChangedStatus());            
    }
    
    /**
     * Writes this project to a file.  Opens a file chooser for the user 
     * to select file for save as or if the project has not been saved before.
     *   
     * @param saveAs whether it is an save as operation
     * @return true if the project is saved successfully or false otherwise.
     */
    public boolean writeToFile(boolean saveAs) {
        String path = "";
        
        if (savedFile != null && !saveAs) { // previously saved in a file
            path = savedFile.getPath();
            writeFileHelper(path);
            return true;
        }
        else {
            // create a file chooser
            JFileChooser fc = new JFileChooser();   
            ExtensionFileFilter filter = new ExtensionFileFilter(
                    "Statcato project file (*.stc)", extension);
            fc.addChoosableFileFilter(filter);
            fc.setAcceptAllFileFilterUsed(false);

            int returnValue = fc.showSaveDialog(app);

            if (returnValue == JFileChooser.APPROVE_OPTION) {
                File file = fc.getSelectedFile();
                path = file.getPath();

                if (!path.toLowerCase().endsWith("." + extension))  {
                    path += "." + extension;
                    file = new File(path);
                }

                System.out.println("opened file:" + file.getPath());

                if (file.exists()) { // file exists already
                    System.out.println("file exists already");
                    Object[] options = {"Overwrite file", "Cancel"};
                    int choice = JOptionPane.showOptionDialog(app, 
                                "The specified file already exists.  Overwrite existing file?",
                                "Overwrite file?", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE,
                                null, options, options[1]);
                    if (choice != 0)   // don't overwrite
                        return false;
                }

                writeFileHelper(path);
                savedFile = file;
     
                return true;
            }
            return false;
        }        
    }        


    /**
     * Called by writeToFile function to perform writing of the project file
     * to the given file path.
     * 
     * @param path file path
     */
    private void writeFileHelper(String path) {
            // write to file
            try {
                // write log contents
                String htmlSource = Log.getText();
                String htmlSource2 = "";

                if (htmlSource.indexOf("<body>") != -1) {
                    int start = htmlSource.indexOf("<body>") + 6;
                    htmlSource = htmlSource.substring(start);

                    while (htmlSource.contains("<body>")) {
                        start = htmlSource.indexOf("<body>") + 6;
                        htmlSource = htmlSource.substring(start);
                    }

                    int end = htmlSource.indexOf("</body>");
                    if (end == -1)
                        end = htmlSource.length();
                    
                    htmlSource = htmlSource.substring(0, end);
                }

                String [] lines = htmlSource.split("\n");
                for (int i = 0; i < lines.length; ++i) {
                    htmlSource2 += lines[i];
                }

                htmlSource = "\n<html>\n<head>\n</head>\n<body>\n" + htmlSource2 +
                        "\n</body>\n</html>\n";

                FileOutputStream fos = new FileOutputStream(path);
                GZIPOutputStream gz = new GZIPOutputStream(fos);
                ObjectOutputStream oos = new ObjectOutputStream(gz);
                oos.writeObject(htmlSource2);
                // reset modified status of log 
                Log.setUnchangedStatus();
                
                // write the number of datasheets
                int count = DatasheetPane.getTabCount();
                oos.writeObject(new Integer(count));
                
                // write datasheets
                for (int i = 0; i < count; ++i) {
                    Spreadsheet s = ((SpreadsheetScrollPane)
                            DatasheetPane.getComponentAt(i)).getSpreadsheet();
                    s.setUnchangedStatus();
                    s.closeFile();
                    oos.writeObject(
                            ((SpreadsheetModel)s.getModel()).getTabDelimitedValues());
                }
                
                DatasheetPane.resetTabTitles();
                
                oos.flush();
                oos.close();
                gz.close();
                fos.close();
            }
            catch (IOException e) {
                
            }                               
    }
    
    /**
     * Writes project file to the temporary file path.
     *
     */
    public void autoSaveWrite() {
            // write to file
            try {
                // write log contents
                String htmlSource = Log.getText();
                FileOutputStream fos = new FileOutputStream(tempFile.getPath());
                GZIPOutputStream gz = new GZIPOutputStream(fos);
                ObjectOutputStream oos = new ObjectOutputStream(gz);
                oos.writeObject(htmlSource);

                // write the number of datasheets
                int count = DatasheetPane.getTabCount();
                oos.writeObject(new Integer(count));

                // write datasheets
                for (int i = 0; i < count; ++i) {
                    Spreadsheet s = ((SpreadsheetScrollPane)
                            DatasheetPane.getComponentAt(i)).getSpreadsheet();
                    oos.writeObject(
                            ((SpreadsheetModel)s.getModel()).getTabDelimitedValues());
                }

                oos.flush();
                oos.close();
                gz.close();
                fos.close();

                app.restoreStatusTimer(1);
                app.setStatus("Auto save completed.");
                
            }
            catch (IOException e) {

            }
    }

    /**
     * Returns the name of this project.
     *
     * @return name, or empty string if this project has no name
     */
    public String getName() {
        if (savedFile == null)
            return "";
        return savedFile.getName();
    }
    
    /**
     * Read a project file from the given path.  The read log is appended
     * to the existing log, and the datasheets are added to the existing
     * datasheet pane.
     * 
     * @param path  project file path
     * @return  true if a project file is read successfully, or false otherwise
     */
    public boolean readFile(String path) {
        try {
            FileInputStream fis = new FileInputStream(path);
            GZIPInputStream gs = new GZIPInputStream(fis);
            ObjectInputStream ois = new ObjectInputStream(gs);
            Object o = ois.readObject();
            String htmlSource;
            if (o instanceof String) {
                htmlSource = (String)o;                
            }
            else
                return false;
            
            int count;
            o = ois.readObject();
            if (o instanceof Integer) {
                count = ((Integer)o).intValue();
            }
            else
                return false;
            
            String[] sheets = new String[count];
            for (int i = 0; i < count; ++i) {
                o = ois.readObject();
                if (o instanceof String) {
                    String s = (String) o;
                    sheets[i] = s;                   
                }
                else
                    return false;
            }
            
            ois.close();
            gs.close();
            fis.close();
            
            // close current project
            if (close()) {
                // write to log and datasheet pane
                Log.overwrite(htmlSource);
                Log.setUnchangedStatus();
                for (int i = 0; i < count; ++i) {
                    DatasheetPane.addDatasheet(sheets[i], null);
                }
                savedFile = new File(path);

                return true;
            }
            return false;
        }
        catch (Exception e) {
            return false;
        }
    }
    
    /**
     * If the project is not yet saved, prompts the user to save.
     * Closes the open project (log and datasheets).
     * 
     * @return whether the project can be closed.
     */
    public boolean close() {
        Object[] options = {"Save Project", "Close Without Saving"};
        int choice;
        // prompt for unsaved files
        if (Log.getChangedStatus() || DatasheetPane.getChangedStatus()) {
            choice = JOptionPane.showOptionDialog(app,
                    "This project is not yet saved.",
                    "Unsaved project...",
                    JOptionPane.YES_NO_OPTION,
                    JOptionPane.QUESTION_MESSAGE, null,
                    options, options[0]);
            if (choice == JOptionPane.CLOSED_OPTION) {
                return false;
            }
            if (choice == 0) {
                // save and clear log
                writeToFile(false);
            }           
        }
        
        Log.clear();
        Log.setUnchangedStatus();
        DatasheetPane.removeAll();
        savedFile = null;

        return true;
    }

    public void exit() {
        if (DELETEAUTOSAVEFILE)
            tempFile.delete();
    }
}
