/*
 *  Copyright (C) 2006-2013  Ronald Blankendaal
 *
 *  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 org.dbgl.gui;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.dbgl.model.conf.Settings;
import org.dbgl.swtdesigner.SWTImageManager;
import org.dbgl.util.FileUtils;
import org.dbgl.util.PlatformUtils;
import org.dbgl.util.StringRelatedUtils;


public final class BrowseButton {

    public static final String DFEND_PATH = "C:\\Program Files\\D-Fend\\";
    public static final String DFEND_PROFILES = "Profiles.dat";

    public enum BrowseType { DIR, FILE };
    public enum CanonicalType { DOSROOT, DFEND, CDIMAGE, ZIP, DBGLZIP, DOSBOX, DOSBOXCONF, DOC, BOOTER, EXE, INSTALLER, NATIVE_EXE, NONE };

    private final Button button;
    private Settings settings;


    private class Sa extends SelectionAdapter {

        private final Text field;
        private final Text alt;
        private final BrowseType browse;
        private final CanonicalType canon;
        private final boolean save;
        private final Combo combo;
        private final Shell shell;
        

        public Sa(final Shell shell, final Text control, final Text altControl, final BrowseType browse,
                final CanonicalType canon, final boolean save, final Combo combo) {
            this.shell = shell;
            this.field = control;
            this.alt = altControl;
            this.browse = browse;
            this.canon = canon;
            this.save = save;
            this.combo = combo;
        }

        private String filterPath() {
            String path = field.getText();
            CanonicalType fileType = canon;
            if (path.equals("") && (alt != null)) {
                path = alt.getText();
                if (fileType == CanonicalType.DOC)
                	fileType = CanonicalType.DOSROOT;
            } else if (browse == BrowseType.DIR && fileType == CanonicalType.NONE) {
            	fileType = CanonicalType.DOSROOT;
            }
            switch (fileType) {
                case DOC:
                case DBGLZIP:
                case NATIVE_EXE:
                    return FileUtils.canonicalToData(path).getPath();
                case EXE:
                case INSTALLER:
                case ZIP:
                case BOOTER:
                case DOSROOT:
                    return FileUtils.canonicalToDosroot(path).getPath();
                case DOSBOX:
                case DOSBOXCONF:
                    return FileUtils.canonicalToDosbox(path).getPath();
                case DFEND:
                    return DFEND_PATH;
                case CDIMAGE:
                    String[] fPaths = StringRelatedUtils.textAreaToStringArray(field.getText(), field.getLineDelimiter());
                    if (fPaths.length > 0) {
                        return FileUtils.canonicalToDosroot(fPaths[0]).getPath();
                    } else {
                    	return FileUtils.getDosRoot();
                    }
                default:
                    return "";
            }
        }

        private String getResult(final String result, final File filterPath, final String[] filenames) {
            switch (canon) {
                case DOC:
                case DBGLZIP:
                case NATIVE_EXE:
                    return FileUtils.makeRelativeToData(new File(result)).getPath();
                case EXE:
                case INSTALLER:
                    if (FileUtils.isArchive(result) || FileUtils.isIsoFile(result) || FileUtils.isFatImage(result)) {
                        BrowseArchiveDialog dialog = new BrowseArchiveDialog(shell, SWT.OPEN);
                        dialog.setFileToBrowse(result);
                        String choice = (String)dialog.open();
                        return (choice == null)? null: FileUtils.makeRelativeToDosroot(new File(choice)).getPath();
                    }
                case ZIP:
                case BOOTER:
                case DOSROOT:
                    return FileUtils.makeRelativeToDosroot(new File(result)).getPath();
                case DOSBOX:
                case DOSBOXCONF:
                    return FileUtils.makeRelativeToDosbox(new File(result)).getPath();
                case CDIMAGE:
                    File path = FileUtils.makeRelativeToDosroot(filterPath);
                    StringBuffer images = new StringBuffer();
                    for (String file: filenames) {
                        images.append(new File(path, file)).append(field.getLineDelimiter());
                    }
                    return images.toString();
                default:
                    return result;
            }
        }

        public void widgetSelected(final SelectionEvent event) {
            String result = null;
            File filterPath = null;
            String[] filenames = null;

            shell.setEnabled(false);

            String rawFilterPath = filterPath();
            File fpath = new File(rawFilterPath);
            if (fpath != null && !fpath.isDirectory())
                fpath = fpath.getParentFile();
            
            if (browse == BrowseType.DIR) {
                DirectoryDialog dialog = new DirectoryDialog(shell);
                if (fpath != null)
                	dialog.setFilterPath(fpath.getPath());
                result = dialog.open();
            } else if (browse == BrowseType.FILE && ((canon == CanonicalType.EXE) || (canon == CanonicalType.INSTALLER)) && 
                    (FileUtils.isArchive(rawFilterPath) || FileUtils.isIsoFile(rawFilterPath) || FileUtils.isFatImage(rawFilterPath))) {
                result = rawFilterPath;
            } else if (browse == BrowseType.FILE) {
                int style = (canon == CanonicalType.CDIMAGE) ? SWT.OPEN | SWT.MULTI: SWT.OPEN;
                if (save) style = SWT.SAVE;
                FileDialog dialog = new FileDialog(shell, style);
                if (fpath != null)
                	dialog.setFilterPath(fpath.getPath());

                String[] filterNames = null;
                String[] filterExts = null;
                switch (canon) {
                    case DOC:
                        filterNames = new String[] { FileUtils.ALL_FILTER };
                        filterExts = new String[] { FileUtils.ALL_FILTER };
                        break;
                    case EXE:
                    case INSTALLER:
                    	boolean supportsPhysFS = ((combo != null) && (combo.isEnabled()));
                    	java.util.List<String> fNames = new ArrayList<String>();
                    	java.util.List<String> fExts = new ArrayList<String>();
                    	fNames.add(settings.msg("filetype.applicable"));
                    	fExts.add(FileUtils.EXE_FILTER + ";" + FileUtils.CDI_FILTER + ';' + FileUtils.FATI_FILTER + (supportsPhysFS ? ';' + FileUtils.ARC_FILTER: ""));
                    	Collections.addAll(fNames, settings.msg("filetype.exe"), settings.msg("filetype.cdimage"), settings.msg("filetype.floppyimage"), settings.msg("filetype.archive"), FileUtils.ALL_FILTER);
                    	Collections.addAll(fExts, FileUtils.EXE_FILTER, FileUtils.CDI_FILTER, FileUtils.FATI_FILTER, FileUtils.ARC_FILTER, FileUtils.ALL_FILTER);
                        filterNames = fNames.toArray(new String[0]);
                        filterExts = fExts.toArray(new String[0]);
                        break;
                    case NATIVE_EXE:
                        String defFilterTitleNative = settings.msg("filetype.native_exe");
                        String defaultFilterNative = PlatformUtils.NATIVE_EXE_FILTER;
                        filterNames = new String[] { defFilterTitleNative, FileUtils.ALL_FILTER };
                        filterExts = new String[] { defaultFilterNative, FileUtils.ALL_FILTER };
                        break;
                    case ZIP:
                        filterNames = new String[] { settings.msg("filetype.archive"), FileUtils.ALL_FILTER };
                        filterExts = new String[] { FileUtils.ARC_FILTER, FileUtils.ALL_FILTER };
                        break;
                    case DBGLZIP:
                        filterNames = new String[] { settings.msg("filetype.gamepack"), FileUtils.ALL_FILTER };
                        filterExts = new String[] { FileUtils.DBGLZIP_FILTER, FileUtils.ALL_FILTER };
                        break;
                    case BOOTER:
                        filterNames = new String[] { settings.msg("filetype.booterimage"), FileUtils.ALL_FILTER };
                        filterExts = new String[] { FileUtils.BTR_FILTER, FileUtils.ALL_FILTER };
                        break;
                    case DFEND:
                        filterNames = new String[] { settings.msg("filetype.dfendprofile") };
                        filterExts = new String[] { DFEND_PROFILES };
                        break;
                    case CDIMAGE:
                        filterNames = new String[] { settings.msg("filetype.applicable"), settings.msg("filetype.cdimage"), settings.msg("filetype.floppyimage"), FileUtils.ALL_FILTER };
                        filterExts = new String[] { FileUtils.CDI_FILTER + ';' + FileUtils.FATI_FILTER, FileUtils.CDI_FILTER, FileUtils.FATI_FILTER, FileUtils.ALL_FILTER };
                        break;
                    case DOSBOXCONF:
                        filterNames = new String[] { settings.msg("filetype.conf"), FileUtils.ALL_FILTER };
                        filterExts = new String[] { FileUtils.CNF_FILTER, FileUtils.ALL_FILTER };
                        break;
                    default:
                }
                if (filterNames != null) {
                    dialog.setFilterNames(filterNames);
                }
                if (filterExts != null) {
                    dialog.setFilterExtensions(filterExts);
                }
                if (canon == CanonicalType.DFEND) {
                    dialog.setFileName(DFEND_PROFILES);
                }
                result = dialog.open();
                if (canon == CanonicalType.CDIMAGE) {
                    filterPath = new File(dialog.getFilterPath());
                    filenames = dialog.getFileNames();
                }
            }
            if (result != null) {
                result = getResult(result, filterPath, filenames);
                if (result != null) {
                    field.setText(result);
                    if ((canon == CanonicalType.DOSBOX) && (alt != null)) {
                    	alt.setText(FileUtils.constructRelativeDBConfLocation(result).getPath());
                    } else if ((canon == CanonicalType.CDIMAGE) && (combo != null)) {
                    	if (FileUtils.isIsoFile(filenames[0])) {
                    		combo.setText("iso"); 
                    	} else if (FileUtils.isFatImage(filenames[0])) {
                    		combo.setText("floppy");
                    	}
                    } else if ((canon == CanonicalType.NATIVE_EXE) && (alt != null)) {
                    	String dir = FileUtils.makeRelativeToData((FileUtils.canonicalToData(result)).getParentFile()).getPath();
                    	if (dir != null) alt.setText(dir);
                    }
                }
            }
 
            try { Thread.sleep(100); } catch (InterruptedException e) {}
            while (shell.getDisplay().readAndDispatch());
            shell.setEnabled(true);
        }
    }

    public BrowseButton(final Composite composite, final int style) {
        settings = Settings.getInstance();
        button = GeneralPurposeGUI.createIconButton(composite, style, settings, settings.msg("button.browse"), SWTImageManager.IMG_FOLDER);
    }

    public void connect(final Shell shell, final Text control, final Text altControl, final BrowseType browse, final CanonicalType canon, final boolean save, final Combo combo) {
        button.addSelectionListener(new Sa(shell, control, altControl, browse, canon, save, combo));
    }

    public void setLayoutData(final Object arg0) {
        button.setLayoutData(arg0);
    }

    public void setEnabled(final boolean enabled) {
        button.setEnabled(enabled);
    }
}
