/*
 * Created on 2007/03/12
 *
 *
 * Copyright(c) 2007 Yoshimasa Matsumoto
 */
package netjfwatcher.nodemap.gui;

import java.io.IOException;
import java.net.URL;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.logging.Logger;

import netjfwatcher.application.NetJFWatcherPlugin;
import netjfwatcher.common.view.MenuPreference;
import netjfwatcher.database.access.control.DatabaseConnectionException;
import netjfwatcher.database.access.model.DBTableMapLink;
import netjfwatcher.database.access.model.DBTableNodeRegister;
import netjfwatcher.engine.model.action.MediaResource;
import netjfwatcher.engine.nodecontrol.NodeEdit;
import netjfwatcher.engine.nodemaneger.map.NodeMapInfo;
import netjfwatcher.engine.nodemaneger.map.NodeMapMenuNodeAlarm;
import netjfwatcher.engine.nodemaneger.map.NodeMapMenuNodeConfig;
import netjfwatcher.engine.nodemaneger.map.NodeMapMenuNodeOperation;
import netjfwatcher.engine.nodemaneger.map.NodeMapMenuNodeSnmp;
import netjfwatcher.engine.nodemaneger.map.NodeMapMenuNodeSnmpStatisticsSet;
import netjfwatcher.engine.socket.info.NodeInformation;
import netjfwatcher.engine.socket.info.NodeMapLinkInformation;
import netjfwatcher.engine.view.editorpart.ping.NodePingMenu;
import netjfwatcher.engine.view.editorpart.snmp.NodeSnmpStatisticsMenu;

import org.eclipse.jface.action.SubStatusLineManager;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;
import org.osgi.framework.Bundle;


/**
 * ノードMap ViewのCanvas上のPopUpメニューを実装するクラスです。
 *
 * @author Yoshimasa Matsumoto
 * @version 1.0
 */
public class NodeMapDrawViewPopUpMenu {
    /** Loadメニュー */
    protected static String LOAD_MENU = "Load";

    /** Saveメニュー */
    protected static String SAVE_MENU = "Save";

    /** Linkメニュー */
    protected static String LINK_MENU = "Link";

    /* ロギング */
    private static Logger logger;

    /** Display */
    protected Display display;

    /** ノードMap Canvas */
    protected Canvas canvas;

    /** PopUpメニュー */
    protected Menu popUpMenu;

    /** PopUpメニュー ノードViewメニューItem */
    protected MenuItem nodeViewMenuItem;

    /** PopUpメニュー ノードAlarmメニューItem */
    protected MenuItem nodeAlarmMenuItem;

    /** PopUpメニュー ノードSNMPメニューItem */
    protected MenuItem nodeSnmpMenuItem;

    /** PopUpメニュー ノードSNMP統計メニューItem */
    protected MenuItem nodeSnmpStatisticsSetMenuItem;

    /** ノードMap View Draw */
    protected NodeMapDrawViewDraw mapDraw;

    /** ノードMap情報リスト */
    protected ArrayList<NodeMapInfo> nodeMapNodeInfoList = new ArrayList<NodeMapInfo>();

    /** ノードMap Link情報リスト */
    protected NodeMapLinkInformation nodMapLinkInformationList;

    /** 画像を入手するためのPluginのResource bundle */
    protected Bundle bundle = NetJFWatcherPlugin.getInstance().getBundle();

    /** ノード種別に対応したノードIcon Imageを格納するMap */
    protected HashMap nodeIconImageMap = new HashMap();

    /** リソース情報から生成したノードIcon Imageを格納する配列 */
    protected Image[] nodeImage = null;

    /** ステータスラインマネージャ */
    protected SubStatusLineManager statusLineManager;

    /** ノードMap Viewマウスリスナー */
    protected NodeMapDrawViewMouseListener mouseListener;

    /**
     * ノードMap ViewのCanvas上のPopUpメニューを実装するクラスインスタンスを
     * 生成します、
     *
     * @param display Display
     * @param canvas Canvas
     * @param mapDraw ノードMap描画クラスインスタンス
     * @param mouseListener マウスリスナークラスインスタンス
     * @param statusLineManager ステータスラインマネージャ
     */
    public NodeMapDrawViewPopUpMenu(
        Display display, Canvas canvas, NodeMapDrawViewDraw mapDraw,
        NodeMapDrawViewMouseListener mouseListener,
        SubStatusLineManager statusLineManager) {
        logger = Logger.getLogger(this.getClass().getName());
        this.display = display;
        this.canvas = canvas;
        this.mapDraw = mapDraw;
        this.statusLineManager = statusLineManager;
        this.mouseListener = mouseListener;
    }

    /**
     * PopUpメニューをセットします。
     *
     * @param parent Composite
     */
    public void setPopUpMenu(Composite parent) {
        /* popUpメニューセット */
        popUpMenu = new Menu(parent.getShell(), SWT.POP_UP);
        canvas.setMenu(popUpMenu);

        /* Load処理 */
        MenuItem menuItemLoad = new MenuItem(popUpMenu, SWT.PUSH);
        menuItemLoad.setText(LOAD_MENU);
        menuItemLoad.addSelectionListener(
            new SelectionAdapter() {
                public void widgetSelected(SelectionEvent e) {
                    loadNodeMap();
                }
            });

        /*
         * ノードMap Save処理
         */
        MenuItem menuItemSave = new MenuItem(popUpMenu, SWT.PUSH);
        menuItemSave.setText(SAVE_MENU);

        /*
         * ノードMap popupメニューでのSave選択
         */
        menuItemSave.addSelectionListener(
            new SelectionAdapter() {
                public void widgetSelected(SelectionEvent e) {
                    saveNodeMap();
                }
            });

        /*
         * Linkメニュー生成
         */
        MenuItem menuItemLink = new MenuItem(popUpMenu, SWT.CHECK);
        menuItemLink.setText(LINK_MENU);

        if (mouseListener.isLineSelected()) {
            menuItemLink.setSelection(true);
        } else {
            menuItemLink.setSelection(false);
        }

        /*
         * Linkメニュー選択処理
         */
        menuItemLink.addSelectionListener(
            new SelectionAdapter() {
                public void widgetSelected(SelectionEvent e) {
                    /*
                            * Linkフラグ(Link描画モードかノードIcon移動
                            * モード)を反転
                            */
                    if (mouseListener.isLineSelected()) {
                        mouseListener.setLineSelected(false);
                    } else {
                        mouseListener.setLineSelected(true);
                    }
                }
            });
    }

    /**
     * ノードMap View情報をロードして描画します。
     *
     */
    public void loadNodeMap() {
        getNodeMapLink(true);

        ArrayList nodeList = getNodeInfoListMapView(true);
        createNodeMapInfo(nodeList);

        mapDraw.redraw(nodeMapNodeInfoList, nodMapLinkInformationList);

        setStatusLine();
    }

    /*
     * ノードMap View情報をセーブします。
     *
     */
    private void saveNodeMap() {
        for (int i = 0; i < nodeMapNodeInfoList.size(); i++) {
            NodeMapInfo nodeMapInfo = (NodeMapInfo) nodeMapNodeInfoList.get(i);
            NodeInformation nodeInfo = nodeMapInfo.getNodeInfo();

            if(nodeInfo == null || nodeInfo.getIpaddress().equals("")) {
            	Shell shell = new Shell();
                MessageDialog.openError(
                    shell, "Abort Node Map save error", "Illegal IP Address");
                
                shell.dispose();

                return;
            }
            NodeEdit editNodeInstance = NodeEdit.getInstance();

            try {
                editNodeInstance.editNodeInfo(nodeInfo);
            } catch (DatabaseConnectionException e1) {
                Shell shell = new Shell();
                MessageDialog.openError(
                    shell, "Abort Node Map save error", e1.getMessage());
                logger.warning("Abort Node Map save error " + e1.getMessage());
                shell.dispose();

                return;
            } catch (SQLException e1) {
                Shell shell = new Shell();
                MessageDialog.openError(
                    shell, "Node List import error", e1.getMessage());
                logger.warning("Node List import error " + e1.getMessage());
                shell.dispose();

                return;
            }
        }

        if (nodMapLinkInformationList == null) {
            return;
        }

        DBTableMapLink nodeMapLinkDBTable = new DBTableMapLink();

        try {
            nodeMapLinkDBTable.updateNodeMapLink(
                nodMapLinkInformationList, true);
        } catch (SQLException e1) {
            logger.warning(e1.getMessage());
            e1.printStackTrace();
        } catch (DatabaseConnectionException e1) {
            logger.warning(e1.getMessage());
            e1.printStackTrace();
        }
    }

    /**
     * ノード監視情報リストからノードIcon image、Iconサイズ、
     * ノード座標をセットします。
     *
     * @param nodeList ノード監視情報リスト
     */
    protected void createNodeMapInfo(ArrayList nodeList) {
        nodeImage = new Image[nodeList.size()];

        nodeMapNodeInfoList.clear();

        for (int i = 0; i < nodeList.size(); i++) {
            NodeInformation nodeInfo = (NodeInformation) nodeList.get(i);
            nodeImage[i] = createNodeIconImage(nodeInfo.getNodeKind());

            /* ノードMap描画におけるノード情報 */
            NodeMapInfo nodeMapinfo = new NodeMapInfo();
            int x = 0;
            int y = 0;
            x = (int) Float.parseFloat(nodeInfo.getNodeX());
            y = (int) Float.parseFloat(nodeInfo.getNodeY());
            nodeMapinfo.setNodeIconImage(nodeImage[i]);
            nodeMapinfo.setX(x);
            nodeMapinfo.setY(y);
            nodeMapinfo.setNodeInfo(nodeInfo);
            nodeMapinfo.setHeight(nodeImage[i].getBounds().height);
            nodeMapinfo.setWidth(nodeImage[i].getBounds().width);

            /* ノードMap描画におけるノード情報をリストに格納 */
            nodeMapNodeInfoList.add(nodeMapinfo);
        }
    }

    /**
     * ノード種別からノードIcon imageを生成して返します。
     *
     * @param nodeKind ノード種別
     * @return nodeIconImage ノードIcon image
     */
    protected Image createNodeIconImage(String nodeKind) {
        /* ノード種別に対応したノードIconイメージファイルを
         * 記述したXMLファイルからListを生成し、ノードIcon
         * イメージファイル名を取得
         */
        String nodeIconFileName =
            MediaResource.getInstance().getNodeIconFullFileName(nodeKind);
        Image nodeIconImage = null;

        if (!nodeIconImageMap.containsKey(nodeIconFileName)) {
            URL url = null;
            url = bundle.getEntry(nodeIconFileName);

            if (url == null) {
                /* Iconリソースファイルが見つからない場合ロギング採取 */
                logger.severe("Not found icon file : " + nodeIconFileName);
            } else {
                try {
                    /* ノードIconイメージ生成 */
                    nodeIconImage = new Image(display, url.openStream());

                    /* ノードIconイメージをMapに格納 */
                    nodeIconImageMap.put(nodeIconFileName, nodeIconImage);
                } catch (IOException e) {
                    logger.warning(
                        "Abort create image " + e.getMessage() + " for "
                        + nodeIconFileName);
                    e.printStackTrace();
                }
            }
        } else {
            nodeIconImage = (Image) nodeIconImageMap.get(nodeIconFileName);
        }

        return nodeIconImage;
    }

    /**
     * ノード個別メニューとして、ノード選択時にPopUpメニューに
     * ノード選択メニューを追加します。
     *
     * @param nodeInfo ノード監視情報
     */
    protected void setNodeMenu(final NodeInformation nodeInfo,
			boolean isNodeMenu) {
    	if(isNodeMenu) {
        /* ノード構成定義情報表示メニュー */
        nodeViewMenuItem = new MenuItem(popUpMenu, SWT.PUSH);
        nodeViewMenuItem.setText(MenuPreference.NODE_CONFIG_VIEW);

        NodeMapMenuNodeConfig nodeConfig =
            new NodeMapMenuNodeConfig(nodeInfo, false);
        nodeViewMenuItem.addSelectionListener(nodeConfig);

        /* ノードAlarm表示メニュー */
        nodeAlarmMenuItem = new MenuItem(popUpMenu, SWT.PUSH);
        nodeAlarmMenuItem.setText(MenuPreference.NODE_ALARM_VIEW);

        NodeMapMenuNodeAlarm nodeAlarm = new NodeMapMenuNodeAlarm(nodeInfo, false);
        nodeAlarmMenuItem.addSelectionListener(nodeAlarm);

        /* ノードSNMP情報表示メニュー */
        nodeSnmpMenuItem = new MenuItem(popUpMenu, SWT.PUSH);
        nodeSnmpMenuItem.setText(MenuPreference.NODE_SNMP_VIEW);

        NodeMapMenuNodeSnmp nodeSnmp = new NodeMapMenuNodeSnmp(nodeInfo, false);
        nodeSnmpMenuItem.addSelectionListener(nodeSnmp);

        /* ノードPing応答データ表示メニュー */
        NodePingMenu menuPing = new NodePingMenu();
        menuPing.createPingMenu(popUpMenu, nodeInfo, false);

        NodeSnmpStatisticsMenu menuSnmpStatistics =
            new NodeSnmpStatisticsMenu();
        menuSnmpStatistics.createSnmpStatisticsMenu(popUpMenu, nodeInfo, false);

        /* ノードSNMP統計情報採取設定メニュー */
        nodeSnmpStatisticsSetMenuItem = new MenuItem(popUpMenu, SWT.PUSH);
        nodeSnmpStatisticsSetMenuItem.setText(
            MenuPreference.NODE_SNMP_STATISTICS_SET);

        NodeMapMenuNodeSnmpStatisticsSet nodeSnmpStatisticsSet =
            new NodeMapMenuNodeSnmpStatisticsSet(nodeInfo, false);
        nodeSnmpStatisticsSetMenuItem.addSelectionListener(
            nodeSnmpStatisticsSet);
    	}
        /* ノード構成定義メニュー */
        nodeViewMenuItem = new MenuItem(popUpMenu, SWT.PUSH);
        nodeViewMenuItem.setText(MenuPreference.NODE_OPERATION_VIEW);

        NodeMapMenuNodeOperation nodeOperaqtion =
            new NodeMapMenuNodeOperation(nodeInfo, false);
        nodeViewMenuItem.addSelectionListener(nodeOperaqtion);
    }

    /**
     * ノード監視情報リストをデータベースから取得して返します。
     *
     * @param isNodeInfo データベースからノード監視情報リストを
     * 取得するか否かフラグ
     * @return ノード監視情報リスト
     */
    protected ArrayList getNodeInfoListMapView(boolean isNodeInfo) {
        if (!isNodeInfo) {
            return new ArrayList();
        }

        DBTableNodeRegister nodeRegisterDBTable =
            DBTableNodeRegister.getInstance();
        ArrayList nodeList = null;

        try {
            nodeList = nodeRegisterDBTable.getNodeInfoList(null, null);
        } catch (SQLException e1) {
            Shell shell = new Shell();
            MessageDialog.openError(
                shell, "Node List import error", e1.getMessage());
            logger.warning("Node List import error" + e1.getMessage());
            shell.dispose();
            e1.printStackTrace();

            return null;
        } catch (Exception e1) {
            Shell shell = new Shell();
            MessageDialog.openError(
                shell, "Node List import error", e1.getMessage());
            logger.warning("Node List import error" + e1.getMessage());
            shell.dispose();
            e1.printStackTrace();

            return null;
        } finally {
            nodeRegisterDBTable = null;
        }

        return nodeList;
    }

    /*
     * ノードMap Link情報をデータベースから取得します。
     *
     * @param isGetDatabase データベースからノードMap Link情報を取得するか否か
     * フラグ
     */
    private void getNodeMapLink(boolean isGetDatabase) {
        if (isGetDatabase) {
            DBTableMapLink nodeMapLinkDBTable = new DBTableMapLink();

            try {
                nodMapLinkInformationList = nodeMapLinkDBTable.findAll();
            } catch (SQLException e) {
                logger.warning(e.getMessage());
                e.printStackTrace();
            } catch (DatabaseConnectionException e) {
                logger.warning(e.getMessage());
                e.printStackTrace();
            }
        }
    }

    /**
     * ステータスライン表示をセットします。
     *
     */
    protected void setStatusLine() {
        if (nodeMapNodeInfoList != null) {
            statusLineManager.setVisible(true);
            statusLineManager.setMessage(
                "Node Map View Node count = " + nodeMapNodeInfoList.size());
        } else {
            statusLineManager.setVisible(false);
        }
    }

    /**
     * ノードMap情報リストを返します。
     *
     * @return nodeMapNodeInfoList ノードMap情報リスト
     */
    public ArrayList getNodeMapNodeInfoList() {
        return nodeMapNodeInfoList;
    }

    /**
     * ノードMap Link情報リストを返します。
     *
     * @return nodMapLinkInformationList ノードMap Link情報リスト
     */
    public NodeMapLinkInformation getNodMapLinkInformationList() {
        return nodMapLinkInformationList;
    }

    /*
     *  (non-Javadoc)
     * @see java.lang.Object#finalize()
     */
    protected void finalize() throws Throwable {
        super.finalize();

        /* 生成したノードIcon imageを破棄 */
        Map list = nodeIconImageMap;
        Iterator it = null;

        for (it = list.keySet().iterator(); it.hasNext();) {
            String key = (String) it.next();
            Image nodeIconImage = (Image) list.get(key);

            if (nodeIconImage != null) {
                nodeIconImage.dispose();
            }
        }

        if (popUpMenu != null) {
            popUpMenu.dispose();
        }

        if (nodeImage != null) {
            for (int i = 0; i < nodeImage.length; i++) {
                if (nodeImage[i] != null) {
                    nodeImage[i].dispose();
                }
            }
        }
    }
}
