package CH.ifa.draw.standard;

import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;

import bibliothek.gui.dock.common.DefaultMultipleCDockable;
import bibliothek.gui.dock.common.MultipleCDockableFactory;


public class StandardDrawingViewContainer extends DefaultMultipleCDockable {

    private final JScrollPane _scrollPane;
    private StandardDrawingView _view;
    private static final int VERTICAL_SCROLL_INCREMENT = 75;
    private static final int HORIZONTAL_SCROLL_INCREMENT = 75;

    public StandardDrawingViewContainer(
        MultipleCDockableFactory<?, ?> factory, StandardDrawingView view)
    {
        super(factory);

        this.setCloseable(true);
        this.setRemoveOnClose(true);
        _view = view;

        InputEventForwarder forwarder = new InputEventForwarder();
        view.addMouseListener(forwarder);
        view.addMouseMotionListener(forwarder);
        view.addKeyListener(forwarder);

        _scrollPane = new JScrollPane(
            view, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
            ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
        _scrollPane.getViewport().setScrollMode(javax.swing.JViewport.BLIT_SCROLL_MODE);

        //Let the user scroll by dragging to outside the window.
        _scrollPane.setAutoscrolls(true); //enable synthetic drag events
        _scrollPane.getVerticalScrollBar().setUnitIncrement(VERTICAL_SCROLL_INCREMENT);
        _scrollPane.getHorizontalScrollBar().setUnitIncrement(HORIZONTAL_SCROLL_INCREMENT);
        _scrollPane.addMouseWheelListener(forwarder);

        this.add(_scrollPane);
    }

    public StandardDrawingView getView() {
        return _view;
    }

    public JScrollPane getScrollPane() {
        return _scrollPane;
    }

    /**
     * Performs a cleanup of this container.
     * This will also remove the view reference.
     */
    public void clean() {

        getView().getParent().remove(getView());
        _view = null;

    }

    /**
     * An instance of this class is used to catch all input (mouse and
     * keyboard) events and forward them to the StandardDrawingView.
     **/
    private class InputEventForwarder
        implements KeyListener, MouseMotionListener, MouseListener, MouseWheelListener
    {
        private boolean _active;

        public InputEventForwarder() {
            this._active = true;
        }

        // implementation of java.awt.event.MouseListener interface
        public void mouseClicked(MouseEvent e) {
            if (_active) {
                _view.mouseClicked(e);
            }
        }

        public void mousePressed(MouseEvent e) {
            if (_active) {
                _view.mousePressed(e);
            }
        }

        public void mouseReleased(MouseEvent e) {
            if (_active) {
                _view.mouseReleased(e);
            }
        }

        public void mouseEntered(MouseEvent e) {
            if (_active) {
                _view.mouseEntered(e);
            }
        }

        public void mouseExited(MouseEvent e) {
            if (_active) {
                _view.mouseExited(e);
            }
        }

        // implementation of java.awt.event.MouseMotionListener interface
        public void mouseDragged(MouseEvent e) {
            if (_active) {
                Rectangle r = new Rectangle(e.getX(), e.getY(), 1, 1);
                ((JPanel) e.getSource()).scrollRectToVisible(r);
                _view.mouseDragged(e);
            }
        }

        public void mouseMoved(MouseEvent e) {
            if (_active) {
                _view.mouseMoved(e);
            }
        }

        // implementation of java.awt.event.KeyListener interface
        public void keyTyped(KeyEvent e) {
            if (_active) {
                _view.keyTyped(e);
            }
        }

        public void keyPressed(KeyEvent e) {
            if (_active) {
                _view.keyPressed(e);
            }
            if (_active) {

                if (e.getKeyCode() == KeyEvent.VK_CONTROL || e.getKeyCode() == KeyEvent.VK_META
                    || e.getKeyCode() == Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()) {
                    _scrollPane.setWheelScrollingEnabled(false);
                }
            }

        }

        public void keyReleased(KeyEvent e) {
            if (_active) {
                _view.keyReleased(e);
            }
            if (_active) {

                if (e.getKeyCode() == KeyEvent.VK_CONTROL || e.getKeyCode() == KeyEvent.VK_META
                    || e.getKeyCode() == Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()) {
                    _scrollPane.setWheelScrollingEnabled(true);
                }
            }

        }

        public void discard() {
            _active = false;
        }

        @Override
        public void mouseWheelMoved(MouseWheelEvent e) {
            if (e.getModifiersEx() == Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()) {
                _view.mouseWheelMoved(e);

                // After zooming need to repaint, because the DrawingView might be smaller than the scroll pane
                _scrollPane.repaint();

            }
        }
    }
}
