/*
 * Copyright (c) 1995, 2003, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code 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
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package sun.awt.motif;

import java.awt.*;
import java.awt.peer.*;
import java.io.*;
import java.awt.datatransfer.*;
import java.util.ArrayList;
import sun.awt.datatransfer.ToolkitThreadBlockedHandler;

public class MFileDialogPeer extends MDialogPeer implements FileDialogPeer {
    private FilenameFilter filter;
    private String[] NativeFilteredFiles;
    native void create(MComponentPeer parent);
    void create(MComponentPeer parent, Object arg) {
        create(parent);
    }
    public MFileDialogPeer(FileDialog target) {
        super(target);
        FileDialog      fdialog = (FileDialog)target;
        String          dir = fdialog.getDirectory();
        String          file = fdialog.getFile();
        FilenameFilter  filter = fdialog.getFilenameFilter();

        insets = new Insets(0, 0, 0, 0);
        setDirectory(dir);
        if (file != null) {
            setFile(file);
        }
            setFilenameFilter(filter);
    }
    native void         pReshape(int x, int y, int width, int height);
    native void         pDispose();
    native void         pShow();
    native void         pHide();
    native void         setFileEntry(String dir, String file, String[] ffiles);
    native void insertReplaceFileDialogText(String l);
    public native void  setFont(Font f);

    String getFilteredFile(String file) {
        if (file == null) {
            file = ((FileDialog)target).getFile();
        }
        String dir = ((FileDialog)target).getDirectory();
        if (dir == null) {
            dir = "./";
        }
        if (file == null) {
            file = "";
        }
        if (filter != null && !filter.accept(new File(dir), file)) {
            file = "";
        }
        return file;
    }
    // NOTE: This method is called by privileged threads.
    //       DO NOT INVOKE CLIENT CODE ON THIS THREAD!
    public void         handleSelected(final String file) {
        final FileDialog fileDialog = (FileDialog)target;
        MToolkit.executeOnEventHandlerThread(fileDialog, new Runnable() {
            public void run() {
                int index = file.lastIndexOf(java.io.File.separatorChar);/*2509*//*ibm*/
                String dir;

                if (index == -1) {
                    dir = "."+java.io.File.separator;
                    fileDialog.setFile(file);
                } else {
                    dir = file.substring(0, index + 1);
                    fileDialog.setFile(file.substring(index + 1));
                }
                fileDialog.setDirectory(dir);
                fileDialog.hide();
            }
        });
    } // handleSelected()

    // NOTE: This method is called by privileged threads.
    //       DO NOT INVOKE CLIENT CODE ON THIS THREAD!
    public void         handleCancel() {
        final FileDialog fileDialog = (FileDialog)target;
        MToolkit.executeOnEventHandlerThread(fileDialog, new Runnable() {
            public void run() {
                fileDialog.setFile(null);
                fileDialog.hide();
            }
        });
    } // handleCancel()

    // NOTE: This method is called by privileged threads.
    //       DO NOT INVOKE CLIENT CODE ON THIS THREAD!
    public void         handleQuit() {
        final FileDialog fileDialog = (FileDialog)target;
        MToolkit.executeOnEventHandlerThread(fileDialog, new Runnable() {
            public void run() {
                fileDialog.hide();
            }
        });
    } // handleQuit()

    public  void setDirectory(String dir) {
        String file = ((FileDialog)target).getFile();
        setFileEntry((dir != null) ? dir : "./", (file != null) ? file
                     : "", null);
    }


    public  void setFile(String file) {
        String dir = ((FileDialog)target).getDirectory();
        if (dir == null) {
            dir = "./";
        }
        setFileEntry((dir != null) ? dir : "./", getFilteredFile(null), null);
    }
    class DirectoryFilter implements FilenameFilter {
        FilenameFilter userFilter;
        DirectoryFilter(FilenameFilter userFilter) {
            this.userFilter = userFilter;
        }
        public boolean accept(File parent, String name) {
            File toTest = new File(parent, name);
            if (toTest.isDirectory()) {
                return false;
            } else if (userFilter != null) {
                return userFilter.accept(parent, name);
            } else {
                return true;
            }
        }
    }
    public void doFilter(FilenameFilter filter, String dir) {
        String d = (dir == null) ? (((FileDialog)target).getDirectory()):(dir);
        String f = getFilteredFile(null);
        File df = new File((d != null) ? d : ".");
        String[] files = df.list(new DirectoryFilter(filter));
        String[] nffiles = NativeFilteredFiles;

        // At this point we have two file lists.
        // The first one is a filtered list of files that we retrieve
        // by using Java code and Java filter.
        // The second one is a filtered list of files that we retrieve
        // by using the native code and native pattern.
        // We should find an intersection of these two lists. The result
        // will be exactly what we expect to see in setFileEntry.
        // For more details please see 4784704.
        if ( files != null ) {
            ArrayList filearr = new ArrayList();
            if (nffiles != null) {
                for (int j = 0; j < files.length; j++) {
                    for (int n = 0; n < nffiles.length; n++) {
                        if (files[j].equals(nffiles[n])) {
                            filearr.add(files[j]);
                            break;
                        }
                    }
                }
            }
            files = new String[filearr.size()];
            for (int i = 0; i < files.length; i++) {
                files[i] = (String)filearr.get(i);
            }
        }
        if (files == null || files.length == 0) {
            files = new String[1];
            files[0] = "";
        }
        setFileEntry((d != null) ? d : ".", (f != null) ? f : "", files);
    }
    private boolean proceedFiltering(final String dir, String[] nffiles,
                                     boolean isPrivileged)
    {
        // Transfer the native filtered file list to the doFilter method.
        NativeFilteredFiles = nffiles;
        // If we are not on the Toolkit thread we can call doFilter() directly.
        // If the filter is null no user code will be invoked
        if (!isPrivileged || filter == null) {
            try {
                doFilter(filter, dir);
                return true;
            } catch(Exception e) {
                e.printStackTrace();
                return false;
            }
        }
        // Otherwise we have to call user code on EvenDispatchThread
        final ToolkitThreadBlockedHandler priveleged_lock =
            MToolkitThreadBlockedHandler.getToolkitThreadBlockedHandler();
        final boolean[] finished = new boolean[1];
        final boolean[] result = new boolean[1];
        finished[0] = false;
        result[0] = false;


        // Use the same Toolkit blocking mechanism as in DnD.
        priveleged_lock.lock();

        MToolkit.executeOnEventHandlerThread((FileDialog)target, new Runnable() {
            public void run() {
                priveleged_lock.lock();
                try {
                    doFilter(filter, dir);
                    result[0] = true;
                } catch (Exception e) {
                    e.printStackTrace();
                    result[0] = false;
                } finally {
                    finished[0] = true;
                    priveleged_lock.exit();
                    priveleged_lock.unlock();
                }
            }
        });

        while (!finished[0]) {
            priveleged_lock.enter();
        }

        priveleged_lock.unlock();

        return result[0];
    }

    public void setFilenameFilter(FilenameFilter filter) {
        this.filter = filter;
        FileDialog      fdialog = (FileDialog)target;
        String          dir = fdialog.getDirectory();
        String          file = fdialog.getFile();
        setFile(file);
        doFilter(filter, null);
    }

    // Called from native widget when paste key is pressed and we
    // already own the selection (prevents Motif from hanging while
    // waiting for the selection)
    //
    public void pasteFromClipboard() {
        Clipboard clipboard = target.getToolkit().getSystemClipboard();

        Transferable content = clipboard.getContents(this);
        if (content != null) {
            try {
                String data = (String)(content.getTransferData(DataFlavor.stringFlavor));
                insertReplaceFileDialogText(data);
            } catch (Exception e) {
            }
        }
    }

// CAVEAT:
// Peer coalescing code turned over the fact that the following functions
// were being inherited from Dialog and were not implemented in awt_FileDialog.c
// Five methods decribed by the peer interface are at fault (setResizable, setTitle,
// toFront, toBack and handleFocusTraversalEvent).  Additionally show has to be overridden
// as it was necessary to add a show function in MDialogPeer for modality flag passing.
// As a result we were winding up in  awt_Dialog.c (now coalesced into awt_TopLevel).
// As Filedialogs are modal and its unclear to me that any of these functions
// can be called while the FD is on-screen let it go.  RJM.
    public void show() {
        // must have our own show or we wind up in pShow for Window. Bad. Very bad.
        setVisible(true);
        setFilenameFilter(filter);
    }

    /**
     * MFileDialogPeer doesn't have native pData so we don't do restack on it
     * @see java.awt.peer.ContainerPeer#restack
     */
    public void restack() {
    }

    /**
     * @see java.awt.peer.ContainerPeer#isRestackSupported
     */
    public boolean isRestackSupported() {
        return false;
    }
}
