/**
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 *
 * Copyright (C)
 * <a href="http://www.inab.org">Spanish National Institute of Bioinformatics (INB)</a>
 * <a href="http://www.bsc.es">Barcelona Supercomputing Center (BSC)</a>
 * <a href="http://inb.bsc.es">Computational Node 6</a>
 */

package org.inb.biomoby.client.gui.auxiliary;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import javax.swing.JPanel;

/**
 * @author Dmitry Repchevsky
 */

public class JmolPane extends JPanel
{
    private Object viewer;
    private Method renderScreenImage;
    private Method openStringInline;
    private Method scriptWait;
    private Method evalString;


    public JmolPane() throws Exception
    {
        super(new BorderLayout());

        try
        {
            Class cViewer = Class.forName("org.jmol.api.JmolViewer");
            Class cAdapter = Class.forName("org.jmol.api.JmolAdapter");
            Class cSmarterAdapter = Class.forName("org.jmol.adapter.smarter.SmarterJmolAdapter");

            Class[] params = new Class[2];
            params[0] = Component.class;
            params[1] = cAdapter;

            Method method = cViewer.getMethod("allocateViewer", params);
            Object adapter = cSmarterAdapter.newInstance();

            Object[] input = { this, adapter};
            viewer = method.invoke(null, input);

            renderScreenImage = getRenderScreenImageMethod(viewer);

            //scriptEval("ZAP");
        }
        catch(Exception ex)
        {
            ex.printStackTrace();
            throw new Exception(ex.getMessage());
        }
    }

    public synchronized void load(String pdb) throws Exception
    {
        if (openStringInline == null)
        {
            openStringInline = getOpenStringInlineMethod(viewer);
        }

        Object[] input = {pdb};

        openStringInline.invoke(viewer, input);
    }

    public synchronized void scriptWait(String script) throws Exception
    {
        if (scriptWait == null)
        {
            scriptWait = getScriptWaitMethod(viewer);
        }

        Object[] input = {script};

        scriptWait.invoke(viewer, input);
    }

    public synchronized void scriptEval(String script) throws Exception
    {
        if (evalString == null)
        {
            evalString = getEvalStringMethod(viewer);
        }

        Object[] input = {script};

        evalString.invoke(viewer, input);
    }

    private Method getRenderScreenImageMethod(Object viewer) throws Exception
    {
        Class[] params = {Graphics.class, Dimension.class, Rectangle.class};

        return viewer.getClass().getMethod("renderScreenImage", params);
    }

    private Method getOpenStringInlineMethod(Object viewer) throws Exception
    {
        Class[] params = {String.class};
        return viewer.getClass().getMethod("openStringInline", params);
    }

    private Method getScriptWaitMethod(Object viewer) throws Exception
    {
        Class[] params = {String.class};
        return viewer.getClass().getMethod("scriptWait", params);
    }

    private Method getEvalStringMethod(Object viewer) throws Exception
    {
        Class[] params = {String.class};
        return viewer.getClass().getMethod("evalString", params);
    }

    private Method getSetModeMouseMethod(Object viewer) throws Exception
    {
        Class[] params = {int.class};
        return viewer.getClass().getMethod("setModeMouse", params);
    }

    @Override
    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);

        Object[] input = {g, this.getSize(), g.getClipBounds()};

        try
        {
            renderScreenImage.invoke(viewer, input);
        }
        catch(Exception ex)
        {
            ex.printStackTrace();
        }
    }

    public void dispose()
    {
        try
        {
            Class constants = Class.forName("org.jmol.viewer.JmolConstants");
            Field field = constants.getDeclaredField("MOUSE_NONE");

            int mode = field.getInt(null);

            Method method = getSetModeMouseMethod(viewer);

            Object[] input = {mode};
            method.invoke(viewer, input);
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
        }
    }
}
