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

import com.jniwrapper.samples.shell.components.HTMLText;
import com.jniwrapper.samples.shell.components.LazyPanel;
import com.jniwrapper.win32.Handle;
import com.jniwrapper.win32.process.CurrentProcess;
import com.jniwrapper.win32.process.Process;
import com.jniwrapper.win32.process.Psapi;
import com.jniwrapper.win32.process.monitoring.ModuleEntry;
import com.jniwrapper.win32.process.monitoring.ProcessEntry;
import com.jniwrapper.win32.process.monitoring.Snapshot;
import com.jniwrapper.win32.system.VersionInfo;

import javax.swing.*;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;

public class ProcessMonitoringSample extends LazyPanel
{
    private JLabel lblAdvisoryText;
    private JLabel lblRunningModules;
    private JTable _runningModules;
    private JLabel lblRunningProcesses;
    private JTable _runningProcesses;
    private JButton _updateInfo;
    private ModulesTableModel _modulesTableModel;
    private ProcessesTableModel _processesTableModel;
    private JLabel lblNotSupported;

    private Snapshot _snapshot;
    private boolean _isWinNT;
    private boolean _disabled;

    public ProcessMonitoringSample(Window parent)
    {
        super(parent);
    }

    public void initialize() throws Exception
    {
        VersionInfo versionInfo = new VersionInfo();
        _isWinNT = false;
        _disabled = false;
        if (versionInfo.isNT() && versionInfo.getMajor() <= 4)
        {
            _isWinNT = true;
        }
        try
        {
            Psapi.getInstance().getFunction("EnumProcesses");
        }
        catch (Throwable e)
        {
             _disabled = true;
        }

        lblAdvisoryText = new HTMLText("The page demonstrates the WinPack ability to monitor running modules and processes, using the Processes API." +
                " Press the \"Update\" button to update the snapshot.");
        lblNotSupported = new HTMLText("<b><FONT color = red>NOTE:</FONT> This functionality " +
                "is not supported by current version of operation system.</b>");

        if (!_isWinNT)
        {
            Snapshot.Options options = new Snapshot.Options(true);
            _snapshot = new Snapshot(options);
        }

        if (!_disabled)
        {
            lblRunningModules = new JLabel("Running Modules of the Current Process:");
            lblRunningProcesses = new JLabel("Running Processes:");
            _modulesTableModel = new ModulesTableModel();
            _runningModules = new JTable(_modulesTableModel)
            {
                public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend)
                {
                }
            };
            _runningModules.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
            _runningModules.setRowSelectionAllowed(true);
            _runningModules.setShowHorizontalLines(false);
            _runningModules.setShowVerticalLines(false);
            final TableColumnModel columnModel = _runningModules.getColumnModel();
            columnModel.getColumn(0).setPreferredWidth(30);
            columnModel.getColumn(1).setPreferredWidth(200);
            final TableColumn emptyColumn1 = columnModel.getColumn(2);
            emptyColumn1.setPreferredWidth(5);
            emptyColumn1.setMaxWidth(5);
            emptyColumn1.setMinWidth(5);

            JScrollPane runningModules = new JScrollPane(_runningModules);

            _processesTableModel = new ProcessesTableModel();
            _runningProcesses = new JTable(_processesTableModel)
            {
                public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend)
                {
                }
            };
            _runningProcesses.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
            _runningProcesses.setRowSelectionAllowed(true);
            _runningProcesses.setShowHorizontalLines(false);
            _runningProcesses.setShowVerticalLines(false);

            final TableColumnModel columnModel2 = _runningProcesses.getColumnModel();
            columnModel2.getColumn(0).setPreferredWidth(200);
            columnModel2.getColumn(1).setPreferredWidth(50);
            final TableColumn emptyColumn2 = columnModel2.getColumn(2);
            emptyColumn2.setPreferredWidth(5);
            emptyColumn2.setMaxWidth(5);
            emptyColumn2.setMinWidth(5);

            JScrollPane runningProcesses = new JScrollPane(_runningProcesses);

            _updateInfo = new JButton("Update");

            _updateInfo.addActionListener(new ActionListener()
            {
                public void actionPerformed(ActionEvent e)
                {
                    update();
                }
            });

            setLayout(new GridBagLayout());

            add(lblAdvisoryText, new GridBagConstraints(00110.00.0
                    , GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(10101010)00));

            add(lblRunningProcesses, new GridBagConstraints(01110.00.0
                    , GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(010010)00));

            add(runningProcesses, new GridBagConstraints(02111.01.0
                    , GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(0101010)00));

            add(lblRunningModules, new GridBagConstraints(03110.00.0
                    , GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(010010)00));

            add(runningModules, new GridBagConstraints(04111.01.0
                    , GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(0101510)00));

            add(_updateInfo, new GridBagConstraints(05110.00.0
                    , GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(010510)00));
        }
        else
        {
            setLayout(new GridBagLayout());

            add(lblAdvisoryText, new GridBagConstraints(00110.00.0
                    , GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(10101010)00));

            add(lblNotSupported, new GridBagConstraints(01110.00.0
                    , GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(1510010)00));

            add(new JPanel()new GridBagConstraints(02111.01.0
                , GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(0000)00));
        }

        super.initialize();
    }

    private void update()
    {
        if (!_isWinNT)
        {
            _snapshot.run();
        }
        _modulesTableModel.fireTableDataChanged();
        _processesTableModel.fireTableDataChanged();
    }

    public void activate() throws Exception
    {
        super.activate();
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                update();
            }
        });
    }

    private class ProcessesTableModel extends AbstractTableModel
    {
        List _entries = null;

        public ProcessesTableModel()
        {
            fireTableDataChanged();
        }

        public void fireTableDataChanged()
        {
            if (_entries != null)
            {
                _entries.clear();
                _entries = null;
            }
            if (!_isWinNT)
            {
                _entries = _snapshot.getProcesses();
            }
            else
            {
                _entries = Process.getProcesses();
            }
            super.fireTableDataChanged();
        }

        public int getRowCount()
        {
            return _entries.size();
        }

        public int getColumnCount()
        {
            return 3;
        }

        public String getColumnName(int column)
        {
            switch (column)
            {
                case 0:
                    return "Executable File";
                case 1:
                    return "Process ID";
                case 2:
                    return "";
            }
            return null;
        }

        public Class getColumnClass(int columnIndex)
        {
            switch (columnIndex)
            {
                case 0:
                    return String.class;
                case 1:
                    return Long.class;
                case 2:
                    return String.class;
            }
            return null;
        }

        public Object getValueAt(int rowIndex, int columnIndex)
        {
            if (!_isWinNT)
            {
                ProcessEntry processEntry = (ProcessEntry)_entries.get(rowIndex);
                switch (columnIndex)
                {
                    case 0:
                        return processEntry.getExeFile();
                    case 1:
                        return new Long(processEntry.getProcessID());
                    case 2:
                        return "";
                }
            }
            else
            {
                Process process = (Process)_entries.get(rowIndex);
                switch (columnIndex)
                {
                    case 0:
                        String fileName = process.getProcessFileName();
                        if (fileName != null)
                        {
                            return fileName.substring(fileName.lastIndexOf("\\")+1, fileName.length());
                        }
                        else
                        {
                            return "";
                        }
                    case 1:
                        return new Long(process.getProcessID());
                    case 2:
                        return "";
                }
            }
            return null;
        }
    }

    private class ModulesTableModel extends AbstractTableModel
    {
        List _entries = null;

        public ModulesTableModel()
        {
            fireTableDataChanged();
        }

        public void fireTableDataChanged()
        {
            if (_entries != null)
            {
                _entries.clear();
                _entries = null;
            }
            if (!_isWinNT)
            {
                _entries = _snapshot.getModules();
            }
            else
            {
                CurrentProcess process = new CurrentProcess();
                _entries = process.getModules();
            }
            super.fireTableDataChanged();
        }

        public int getRowCount()
        {
            return _entries.size();
        }

        public int getColumnCount()
        {
            return 3;
        }

        public String getColumnName(int column)
        {
            switch (column)
            {
                case 0:
                    return "Module Name";
                case 1:
                    return "Executable Path";
                case 2:
                    return "";
            }
            return null;
        }

        public Object getValueAt(int rowIndex, int columnIndex)
        {
            if (!_isWinNT)
            {
                ModuleEntry moduleEntry = (ModuleEntry)_entries.get(rowIndex);
                switch (columnIndex)
                {
                    case 0:
                        return moduleEntry.getModuleName();
                    case 1:
                        return moduleEntry.getExePath();
                    case 2:
                        return "";
                }
            }
            else
            {
                CurrentProcess process = new CurrentProcess();
                String module = process.getModuleFileName((Handle)_entries.get(rowIndex));
                switch (columnIndex)
                {
                    case 0:
                        return module.substring(module.lastIndexOf("\\")+1, module.length());
                    case 1:
                        return module;
                    case 2:
                        return "";
                }
            }
            return null;
        }
    }
}