/**
 * Copyright (C) 2004-2011 Jive Software. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.jivesoftware.sparkimpl.plugin.gateways;

import java.awt.Component;
import java.awt.GridBagLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JCheckBoxMenuItem;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.UIManager;

import org.jivesoftware.resource.Res;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.StanzaBuilder;
import org.jivesoftware.spark.PresenceManager;
import org.jivesoftware.spark.SparkManager;
import org.jivesoftware.spark.component.RolloverButton;
import org.jivesoftware.spark.ui.status.StatusBar;
import org.jivesoftware.spark.util.TaskEngine;
import org.jivesoftware.spark.util.log.Log;
import org.jivesoftware.sparkimpl.plugin.gateways.transports.Transport;
import org.jivesoftware.sparkimpl.plugin.gateways.transports.TransportUtils;

/**
 */
public class GatewayButton extends JPanel implements GatewayItem {
	private final RolloverButton button = new RolloverButton();
    private final Transport transport;
    private boolean signedIn;

    public GatewayButton(final Transport transport) {
        setLayout(new GridBagLayout());
        setOpaque(false);
        this.transport = transport;

        final StatusBar statusBar = SparkManager.getWorkspace().getStatusBar();
        final JPanel commandPanel = SparkManager.getWorkspace().getCommandPanel();

        boolean online = PresenceManager.isOnline(transport.getXMPPServiceDomain());
        button.setIcon(online ? transport.getIcon() : transport.getInactiveIcon());
        button.setText(transport.getCaption());
        button.setToolTipText(transport.getXMPPServiceDomain().asUnescapedString());

        commandPanel.add(button);

        button.addMouseListener(new MouseAdapter() {
            @Override
			public void mousePressed(MouseEvent mouseEvent) {
                handlePopup(mouseEvent);
            }
        });
        commandPanel.updateUI();
        final Runnable registerThread = () -> {
            // Send directed presence if registered with this transport.
            final boolean isRegistered = TransportUtils.isRegistered(transport);
            if (isRegistered) {
                // Check if auto login is set.
                boolean autoJoin = TransportUtils.autoJoinService(transport.getXMPPServiceDomain());
                if (autoJoin) {
                    Presence oldPresence = statusBar.getPresence();
                    Presence presence = StanzaBuilder.buildPresence()
                        .ofType(oldPresence.getType())
                        .setStatus(oldPresence.getStatus())
                        .setPriority(oldPresence.getPriority())
                        .setMode(oldPresence.getMode())
                        .to(transport.getXMPPServiceDomain())
                        .build();
                    try
                    {
                        SparkManager.getConnection().sendStanza(presence);
                    }
                    catch ( SmackException.NotConnectedException | InterruptedException e )
                    {
                        Log.error( "Unable to register.", e );
                    }
                }
            }
        };

        TaskEngine.getInstance().submit(registerThread);
    }

    /**
     * Handles the display of a popup menu when a transport button is clicked.
     */
    private void handlePopup(MouseEvent event) {
        final JPopupMenu popupMenu = new JPopupMenu();

        // Create action to sign off of transport.
        final JMenuItem signOutMenu = new JMenuItem(Res.getString("menuitem.sign.out"));
        signOutMenu.addActionListener( actionEvent -> {
            final Presence offlinePresence = StanzaBuilder.buildPresence()
                .ofType(Presence.Type.unavailable)
                .to(transport.getXMPPServiceDomain())
                .build();
            try
            {
                SparkManager.getConnection().sendStanza(offlinePresence);
            }
            catch ( SmackException.NotConnectedException | InterruptedException e )
            {
                Log.warning( "Unable to send sign-off.", e );
            }
        } );

        // Create menu to sign in.
        final JMenuItem signInMenu = new JMenuItem(Res.getString("menuitem.sign.in"));
        signInMenu.addActionListener( actionEvent -> {
            final Presence onlinePresence = StanzaBuilder.buildPresence()
                .ofType(Presence.Type.available)
                .to(transport.getXMPPServiceDomain())
                .build();
            try
            {
                SparkManager.getConnection().sendStanza(onlinePresence);
            }
            catch ( SmackException.NotConnectedException | InterruptedException e )
            {
                Log.error( "Unable sign-in.", e );
            }
        } );

        // Create menu item to  toggle signing in at startup.
        final JCheckBoxMenuItem signInAtLoginMenu = new JCheckBoxMenuItem();
        signInAtLoginMenu.setText(Res.getString("menuitem.sign.in.at.login"));
        signInAtLoginMenu.addActionListener( actionEvent -> TransportUtils.setAutoJoin(transport.getXMPPServiceDomain(), signInAtLoginMenu.isSelected()) );

        final JMenuItem registerMenu = new JMenuItem(Res.getString("menuitem.enter.login.information"));
        registerMenu.addActionListener( actionEvent -> {
            TransportRegistrationDialog registrationDialog = new TransportRegistrationDialog(transport.getXMPPServiceDomain());
            registrationDialog.invoke();
        } );

        // Create action to delete login information
        final JMenuItem unregisterMenu = new JMenuItem(Res.getString("menuitem.delete.login.information"));
        unregisterMenu.addActionListener( actionEvent -> {
            int confirm = JOptionPane.showConfirmDialog(SparkManager.getMainWindow(), Res.getString("message.disable.transport", transport.getName()), Res.getString("title.disable.transport"), JOptionPane.YES_NO_OPTION);
            if (confirm == JOptionPane.YES_OPTION) {
                try {
                    TransportUtils.unregister(transport.getXMPPServiceDomain());
                }
                catch (SmackException | InterruptedException e1) {
                    Log.error(e1);
                }
            }
        } );

        // If user is not registered with the gateway
        boolean reg = TransportUtils.isRegistered(transport);
        if (!reg) {
            popupMenu.add(registerMenu);
            popupMenu.addSeparator();
            signInMenu.setEnabled(false);
            popupMenu.add(signInMenu);
            signInAtLoginMenu.setEnabled(false);
            popupMenu.add(signInAtLoginMenu);
            popupMenu.show((Component)event.getSource(), event.getX(), event.getY());
            return;
        }

        popupMenu.add(signedIn ? signOutMenu : signInMenu);

        boolean autoJoin = TransportUtils.autoJoinService(transport.getXMPPServiceDomain());
        signInAtLoginMenu.setSelected(autoJoin);

        popupMenu.add(signInAtLoginMenu);
        popupMenu.addSeparator();
        popupMenu.add(unregisterMenu);
        popupMenu.show((Component)event.getSource(), event.getX(), event.getY());
    }

    @Override
	public void signedIn(boolean signedIn) {
        button.setIcon(signedIn ? transport.getIcon() : transport.getInactiveIcon());
        this.signedIn = signedIn;
    }

    @Override
	public boolean isLoggedIn() {
        return signedIn;
    }
}
