package org.limewire.ui.swing.options.actions;

import java.awt.Container;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Random;

import javax.swing.Action;
import javax.swing.JOptionPane;

import org.limewire.i18n.I18nMarker;
import org.limewire.ui.swing.action.AbstractAction;
import org.limewire.ui.swing.components.FocusJOptionPane;
import org.limewire.ui.swing.components.LabelTextField;
import org.limewire.ui.swing.util.FileChooser;
import org.limewire.ui.swing.util.I18n;
import org.limewire.util.FileUtils;

public class BrowseDirectoryAction extends AbstractAction {

    private enum FolderErrors {
        NOT_A_FOLDER (I18nMarker.marktr("{0} is not a folder")),
        CANNOT_WRITE (I18nMarker.marktr("Cannot write to {0}")),
        CANT_FIND (I18nMarker.marktr("Cannot find {0}")), 
        SUCCESS ("");
        
        private String errorMessage;
        
        FolderErrors(String errorMessage) {
            this.errorMessage = errorMessage;
        }
        
        public String getErrorMessage() {
            return errorMessage;
        }
    };
    
    private Container parent;

    private LabelTextField currentDirectoryTextField;

    public BrowseDirectoryAction(Container parent, LabelTextField currentDirectoryTextField) {
        this.parent = parent;
        this.currentDirectoryTextField = currentDirectoryTextField;

        putValue(Action.NAME, I18n.tr("Browse..."));
        putValue(Action.SHORT_DESCRIPTION, I18n.tr("Choose a Different Save Location"));
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        String oldDirectory = currentDirectoryTextField.getText();

        Window window = FocusJOptionPane.getWindowForComponent(parent);
        File directory = FileChooser.getInputDirectory(window, new File(oldDirectory));

        // no directory was selected
        if (directory == null) {
            return;
        }

        FolderErrors error = isSaveDirectoryValid(directory);
        if (error == FolderErrors.SUCCESS) {
            try {
                String newDirectory = directory.getCanonicalPath();
                currentDirectoryTextField.setText(newDirectory);
            } catch (IOException ioe) {
                FocusJOptionPane.showMessageDialog(window, 
                        I18n.tr(error.getErrorMessage(), directory),
                        I18n.tr("Save Folder Error"),
                        JOptionPane.ERROR_MESSAGE);
            }
        } else {
            FocusJOptionPane.showMessageDialog(window, 
                    I18n.tr(error.getErrorMessage(), directory),
                    I18n.tr("Save Folder Error"),
                    JOptionPane.ERROR_MESSAGE);
        }
    }

    /**
     * Utility method for checking whether or not the save directory is valid.
     * 
     * @param saveDir the save directory to check for validity
     * @return <tt>true</tt> if the save directory is valid, otherwise
     *         <tt>false</tt>
     */
    private static FolderErrors isSaveDirectoryValid(File saveDir) {
        if (saveDir == null) 
            return FolderErrors.CANT_FIND;
        if(saveDir.isFile())
            return FolderErrors.NOT_A_FOLDER;
        
        
        if (!saveDir.exists())
            saveDir.mkdirs();

        if (!saveDir.isDirectory())
            return FolderErrors.NOT_A_FOLDER;

        FileUtils.setWriteable(saveDir);

        Random generator = new Random();
        File testFile = null;
        for (int i = 0; i < 10 && testFile == null; i++) {
            StringBuilder name = new StringBuilder();
            for (int j = 0; j < 8; j++) {
                name.append((char) ('a' + generator.nextInt('z' - 'a')));
            }
            name.append(".tmp");

            testFile = new File(saveDir, name.toString());
            if (testFile.exists()) {
                testFile = null; // try again!
            }
        }

        if (testFile == null) {
            return FolderErrors.CANNOT_WRITE;
        }

        RandomAccessFile testRAFile = null;
        try {
            testRAFile = new RandomAccessFile(testFile, "rw");

            // Try to write something just to make extra sure we're OK.
            testRAFile.write(7);
            testRAFile.close();
        } catch (FileNotFoundException e) {
            // If we could not open the file, then we can't write to that
            // directory.
            return FolderErrors.CANNOT_WRITE;
        } catch (IOException e) {
            // The directory is invalid if there was an error writing to it.
            return FolderErrors.CANNOT_WRITE;
        } finally {
            // Delete our test file.
            testFile.delete();
            try {
                if (testRAFile != null)
                    testRAFile.close();
            } catch (IOException ignored) {
            }
        }

        if(FileUtils.canWrite(saveDir))
            return FolderErrors.SUCCESS;
        else
            return FolderErrors.CANNOT_WRITE;
    }
}
