/*
 * Copyright (c) 2000-2009 TeamDev Ltd. All rights reserved.
 * TeamDev PROPRIETARY and CONFIDENTIAL.
 * Use is subject to license terms.
 */
package com.jniwrapper.win32.ui.dialogs;

import com.jniwrapper.Function;
import com.jniwrapper.Parameter;
import com.jniwrapper.util.Logger;
import com.jniwrapper.win32.Msg;
import com.jniwrapper.win32.ui.WindowMessage;
import com.jniwrapper.win32.ui.WindowMessageListener;
import com.jniwrapper.win32.ui.WindowProc;
import com.jniwrapper.win32.ui.Wnd;

import javax.swing.*;
import java.awt.Frame;
import java.awt.Window;
import java.util.*;

/**
 * This class provides functionality that allows to display dialog boxes
 *
 * @author Serge Piletsky
 */
public class DialogHelper
{
    private static final Logger LOG = Logger.getInstance(DialogHelper.class);

    // Vadim.Ridosh: frame painter fix is required only for Java 1.3 and 1.4
    private static boolean EnableFramePainterFix;
    static {
        try {
            String version = System.getProperty("java.runtime.version");
            // Use do not support versions below 1.3
            EnableFramePainterFix = (version == null) ||
                version.startsWith("1.4") || version.startsWith("1.3");
        } catch (Exception e) {
        }
    }

    private DialogHelper()
    {
    }

    private static class FramePainter implements WindowMessageListener
    {
        private Window _window;

        public FramePainter(Window window)
        {
            _window = window;
        }

        /**
         * Tests if the listener can handle a specified message.
         *
         * @param message
         * @param beforeWindowProc the flag specifies that the event occurred before
         * or after window procedure.
         * @return
         */
        public boolean canHandle(WindowMessage message, boolean beforeWindowProc)
        {
            return !beforeWindowProc && message.getMsg() == Msg.WM_PAINT;
        }

        /**
         * Handles window message.
         * @param message
         * @return The result of the message processing.
         */
        public int handle(WindowMessage message)
        {
            _window.paint(_window.getGraphics());
            return 0;
        }
    }

    /**
     * Invokes specified dialog box
     *
     * @param owner Parent window for the dialog
     * @param function Function that displays dialog box
     * @param returnValue Result of the dialog execution
     * @param parameters Arguments of the function specified by the <code>function</code> parameter
     */
    public static void invokeDialog(final Window owner,
                                    final Function function,
                                    final Parameter returnValue,
                                    final Parameter[] parameters)
    {
        List windowProcedures = Collections.EMPTY_LIST;
        if (EnableFramePainterFix)
        {
            List frames = new ArrayList(Arrays.asList(Frame.getFrames()));
            if (!frames.contains(owner))
            {
                frames.add(owner);
            }
            windowProcedures = new ArrayList(frames.size());

            for (Iterator i = frames.iterator(); i.hasNext();)
            {
                Window window = (Window)i.next();
                Wnd wnd = new Wnd(window);
                if (wnd.getValue() != 0)
                {
                    WindowProc windowProc = new WindowProc(wnd);
                    FramePainter framePainter = new FramePainter(window);
                    windowProc.addMessageListener(framePainter);
                    windowProc.substitute();
                    windowProcedures.add(windowProc);
                }
            }
        }
        try
        {
            function.invoke(returnValue, parameters);
        }
        finally
        {
            if (EnableFramePainterFix)
            {
                for (Iterator i = windowProcedures.iterator(); i.hasNext();)
                {
                    WindowProc windowProcedure = (WindowProc)i.next();
                    windowProcedure.restoreNative();
                }
            }
        }
    }
}