import com.jniwrapper.win32.automation.*;
import com.jniwrapper.win32.automation.impl.IDispatchImpl;
import com.jniwrapper.win32.ole.types.OleVerbs;
import operations.OfficeFileOperationsHandler;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;

/**
 *
 * This sample demonstrates the technique of embedding Word application into java application
 * using OleContainer and Automation.
 *
 */
public class WordAutomationSample extends JFrame
{
    private static final String DOCUMENT_PROGID = "Word.Document";
    private static final Dimension WINDOW_SIZE = new Dimension(720, 520);

    private OleContainer _container;
    private IDispatchImpl document;
    private Automation documentAutomation;
    private final FileOperationsHandler fileOperationsHandler;

    public WordAutomationSample()
    {
        super("Word Automation Sample");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setupMenuBar();

        _container = new OfficeContainer();

        fileOperationsHandler = new OfficeFileOperationsHandler(OfficeFileOperationsHandler.TYPE_WORD);
        _container.setFileOperationsHandler(fileOperationsHandler);

        createDocument();

        getContentPane().add(_container, BorderLayout.CENTER);
        addWindowListener(new WindowAdapter()
        {
            public void windowOpened(WindowEvent e)
            {
                _container.doVerb(OleVerbs.SHOW);
            }

            public void windowClosing(WindowEvent e)
            {
                releaseResources();
                _container.destroyObject();
            }
        });

    }

    private void setupMenuBar() {
        JPopupMenu.setDefaultLightWeightPopupEnabled(false);

        JMenuBar menuBar = new JMenuBar();

        JMenu menu = new JMenu("File");
        JMenuItem createItem = new JMenuItem("New");
        JMenuItem openItem = new JMenuItem("Open...");
        JMenuItem saveAsItem = new JMenuItem("Save as...");
        JMenuItem versionItem = new JMenuItem("Show Word version");

        menu.add(createItem);
        menu.add(openItem);
        menu.add(saveAsItem);
        menu.addSeparator();
        menu.add(versionItem);

        createItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                try {
                    createDocument();
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        });

        openItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                File file = fileOperationsHandler.getOpenFile();
                if (file != null) {
                    try {
                        openDocument(file);
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                }
            }
        });


        saveAsItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                File file = fileOperationsHandler.getSaveFile();
                if (file != null) {
                    saveDocumentAs(file);
                }
            }
        });

        versionItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                String version = getVersion();
                if (version != null) {
                    JOptionPane.showMessageDialog(WordAutomationSample.this,"Version number:" + version, "Microsoft Word version", JOptionPane.INFORMATION_MESSAGE);
                }else{
                    JOptionPane.showMessageDialog(WordAutomationSample.this,"Unable to determine version number", "Microsoft Word version", JOptionPane.ERROR_MESSAGE);
                }

            }
        });

        menuBar.add(menu);
        setJMenuBar(menuBar);
    }

    private void initResources() {
        try {
            _container.getOleMessageLoop().doInvokeAndWait(new Runnable() {
                public void run() {
                    document = new IDispatchImpl(_container.getOleObject());
                    document.setAutoDelete(false);
                    documentAutomation = new Automation(document);
                }
            });
        } catch (Exception e) {
            throw new RuntimeException("Failed to initialize document automation", e);
        }
    }

    private void releaseResources() {
        try {
            _container.getOleMessageLoop().doInvokeAndWait(new Runnable() {
                public void run() {
                    if (documentAutomation != null) {
                        documentAutomation.release();
                    }
                    if (document != null && !document.isNull()) {
                        document.setAutoDelete(false);
                        document.release();
                    }
                }
            });
        } catch (Exception e) {
            throw new RuntimeException("Failed to release resources",e);
        }
    }

    private void createDocument(){
        releaseResources();
        _container.createObject(DOCUMENT_PROGID);
        initResources();
    }

    private void openDocument(File docPath){
        releaseResources();
        _container.open(docPath);
        initResources();
    }

    private void saveDocumentAs(final File savePath){
        try {
            _container.getOleMessageLoop().doInvokeAndWait(new Runnable() {
                public void run() {
                    documentAutomation.invoke("SaveAs",new Object[]{savePath.getAbsolutePath()});
                }
            });
        } catch (Exception e) {
            System.err.println("Failed to save document");
            e.printStackTrace();
        }

    }

    private String getVersion() {
        final String[] version = {null};
        try {
            _container.getOleMessageLoop().doInvokeAndWait(new Runnable() {
                public void run() {
                    IDispatchImpl application = null;
                    Automation appAutomation = null;

                    try
                    {
                        application = (IDispatchImpl) documentAutomation.getProperty("Application").getPdispVal();
                        appAutomation = new Automation(application);
                        version[0] = appAutomation.getProperty("Version").getBstrVal().getValue();
                    }
                    finally
                    {
                        if (appAutomation != null) {
                            appAutomation.release();
                        }
                        if (application != null) {
                            application.setAutoDelete(false);
                            application.release();
                        }
                    }
                }
            });
        } catch (Exception e) {
            System.err.println("Failed to get Word version");
            e.printStackTrace();
        }
        return version[0];
    }

    public static void main(String[] args) {
        final WordAutomationSample app = new WordAutomationSample();
        app.setSize(WINDOW_SIZE);
        app.setLocationRelativeTo(null);

        app.setVisible(true);
    }

}