/**
 * 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.spark.ui;


import java.awt.*;
import java.awt.event.MouseEvent;

import java.net.MalformedURLException;
import java.net.URL;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JWindow;

import org.jivesoftware.resource.Res;
import org.jivesoftware.resource.SparkRes;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.StanzaError.Condition;
import org.jivesoftware.smackx.vcardtemp.packet.VCard;
import org.jivesoftware.smackx.iqlast.packet.LastActivity;
import org.jivesoftware.smackx.iqlast.LastActivityManager;
import org.jivesoftware.spark.SparkManager;
import org.jivesoftware.spark.util.GraphicUtils;
import org.jivesoftware.spark.util.ModelUtil;
import org.jivesoftware.spark.util.log.Log;
import org.jivesoftware.sparkimpl.plugin.gateways.transports.Transport;
import org.jivesoftware.sparkimpl.plugin.gateways.transports.TransportUtils;
import org.jxmpp.jid.Jid;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * Represents the UI for the "ToolTip" functionallity in the ContactList.
 *
 * @author Derek DeMoro
 */
public class ContactInfoWindow extends JPanel {
	private static final long serialVersionUID = 8409694344721276453L;
	private final JLabel nicknameLabel = new JLabel();
    private final JTextArea statusLabel = new JTextArea();
    private final JLabel fullJIDLabel = new JLabel();
    private final JLabel avatarLabel = new JLabel();
    private final JLabel iconLabel = new JLabel();
    private final JLabel titleLabel = new JLabel();
    private final JLabel phoneLabel = new JLabel();

    private ContactItem contactItem;

    private final JWindow window = new JWindow();

    private static ContactInfoWindow singleton;
    private static final Object LOCK = new Object();

    /**
     * Returns the singleton instance of <CODE>ContactInfoWindow</CODE>,
     * creating it if necessary.
     * <p/>
     *
     * @return the singleton instance of <Code>ContactInfoWindow</CODE>
     */
    public static ContactInfoWindow getInstance() {
        // Synchronize on LOCK to ensure that we don't end up creating
        // two singletons.
        synchronized (LOCK) {
            if (null == singleton) {
                ContactInfoWindow controller = new ContactInfoWindow();
                singleton = controller;
                return controller;
            }
        }
        return singleton;
    }

	protected ContactInfoWindow() {
		this(true);
	}

    protected ContactInfoWindow(boolean populate) {

        setLayout(new GridBagLayout());

        setBackground(Color.white);
        if (populate) {
		add(avatarLabel, new GridBagConstraints(0, 1, 1, 4, 0.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(2, 2, 2, 2), 0, 0));
		add(iconLabel, new GridBagConstraints(1, 1, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(2, 2, 0, 2), 0, 0));
		add(nicknameLabel, new GridBagConstraints(2, 1, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(2, 0, 0, 2), 0, 0));
		add(statusLabel, new GridBagConstraints(2, 2, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 2), 0, 0));
		add(titleLabel, new GridBagConstraints(2, 3, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 2, 2), 0, 0));
		add(phoneLabel, new GridBagConstraints(2, 4, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 2, 2), 0, 0));
		add(fullJIDLabel, new GridBagConstraints(0, 5, 4, 1, 1.0, 1.0, GridBagConstraints.SOUTHWEST, GridBagConstraints.HORIZONTAL, new Insets(0, 2, 2, 2), 0, 0));


		nicknameLabel.setFont(new Font("Dialog", Font.BOLD, 12));
		statusLabel.setFont(new Font("Dialog", Font.PLAIN, 12));
		statusLabel.setForeground(Color.gray);
		statusLabel.setLineWrap(true);
		statusLabel.setWrapStyleWord(true);
		statusLabel.setEditable(false);
		statusLabel.setBorder(null);
		fullJIDLabel.setFont(new Font("Dialog", Font.PLAIN, 12));
		fullJIDLabel.setForeground(Color.gray);
		titleLabel.setFont(new Font("Dialog", Font.PLAIN, 12));
		titleLabel.setForeground(Color.gray);
		phoneLabel.setFont(new Font("Dialog", Font.PLAIN, 12));
		phoneLabel.setForeground(Color.gray);


		fullJIDLabel.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, Color.gray));
        }

        setBorder(BorderFactory.createLineBorder(Color.gray, 1));

        window.getContentPane().add(this);

        final ContactList contactList = SparkManager.getWorkspace().getContactList();
        contactList.addContactListListener(new ContactListListener() {
            @Override
			public void contactItemAdded(ContactItem item) {
            }

            @Override
			public void contactItemRemoved(ContactItem item) {
            }

            @Override
			public void contactGroupAdded(ContactGroup group) {
            }

            @Override
			public void contactGroupRemoved(ContactGroup group) {
            }

            @Override
			public void contactItemClicked(ContactItem item) {
                if (window != null) {
                    window.dispose();
                }
            }

            @Override
			public void contactItemDoubleClicked(ContactItem item) {
                if (window != null) {
                    window.dispose();
                }
            }
        });
    }

    public void display(ContactGroup group, MouseEvent e) {
        int loc = group.getList().locationToIndex(e.getPoint());


        ContactItem item = group.getList().getModel().getElementAt(loc);
        if (item == null || item.getJid() == null || item.getJid().toString().equals("dummy@dummy.example")) {
            return;
        }

        if (getContactItem() != null && getContactItem() == item) {
            return;
        }

        iconLabel.setIcon(item.getIcon());

        Point point = group.getList().indexToLocation(loc);

        window.setFocusableWindowState(false);
        setContactItem(item);
        window.pack();


        Point mainWindowLocation = SparkManager.getMainWindow().getLocationOnScreen();
        Point listLocation = group.getList().getLocationOnScreen();

        int x = (int)mainWindowLocation.getX() + SparkManager.getMainWindow().getWidth();
        int y = (int) listLocation.getY() + (int) point.getY();
        setWindowLocation(x, y);
        if (!window.isVisible()) {
            window.setVisible(true);
        }
    }

    public void setWindowLocation(int x, int y) {
        Point mainWindowLocation = SparkManager.getMainWindow().getLocationOnScreen();
        final Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        int actualX = x;
        int actualY = y - 5;
        if ((int) screenSize.getWidth() - getPreferredSize().getWidth() < x) {
            actualX = (int) mainWindowLocation.getX() - (int) getPreferredSize().getWidth();
        }

        // keep this away from bottom edge
        if (actualY + getHeight() > screenSize.height - 64) {
            actualY -= actualY + getHeight() - screenSize.height + 64;
        }
        // if width Spark Main Windows > width 0.9*screenSize we should put a window inside
        if(SparkManager.getMainWindow().getWidth() > screenSize.getWidth()*0.9){
            actualX = x-310;
        }
        window.setLocation(actualX, actualY);
    }

    public void customizeUI(ContactItem contactItem) {
        if (contactItem == null) {
            return;
        }

        nicknameLabel.setText(contactItem.getDisplayName());

        String status = contactItem.getStatus();
        if (!ModelUtil.hasLength(status)) {
            if (contactItem.getPresence() == null || contactItem.getPresence().getType() == Presence.Type.unavailable) {
                status = Res.getString("offline");
            }
            else {
                status = Res.getString("online");
            }
        }
        if (status.equals(Res.getString("offline")) || contactItem.getPresence().isAway()) {
        	//If user is offline or away, try to see last activity

	        try {
                //If user is away (not offline), last activity request is sent to client
				Jid client = status.equals(Res.getString("offline")) ? contactItem.getJid() : contactItem.getPresence().getFrom();
	            LastActivity activity = LastActivityManager.getInstanceFor( SparkManager.getConnection() ).getLastActivity(client);
	
	            long idleTime = (activity.getIdleTime() * 1000);
	
	            if (idleTime > 0) {
	                if (status.equals(Res.getString("offline"))) {
		                SimpleDateFormat format = new SimpleDateFormat("M/d/yy");
		                Date l = new Date();
		                String curDay = format.format(l);
		                l.setTime(l.getTime() - idleTime);
		                //If idleTime is within today show the time, otherwise, show the day, date, and time
		                if (curDay.equals(format.format(l))) {
		                    format = new SimpleDateFormat("h:mm a");
		                } else {
		                    format = new SimpleDateFormat("EEE M/d/yy h:mm a");
		                }
	                	status += (" " + Res.getString("time.since")+ " " + format.format(l));
	                } else if (contactItem.getPresence().isAway()) {
	                    status += "\n";
	                    String time = ModelUtil.getTimeFromLong(idleTime);
	                    status += Res.getString("message.idle.for", time);
	                }
	            }
            } catch (XMPPException.XMPPErrorException e) {
                Condition condition = e.getStanzaError().getCondition();
                if (condition != Condition.feature_not_implemented) {
                    Log.warning("Unable to get Last Activity from: " + contactItem, e);
                }
            } catch (Exception e) {
                Log.warning("Unable to get Last Activity from: " + contactItem, e);
            }
        }
        statusLabel.setText(status);

        Transport transport = TransportUtils.getTransport(contactItem.getJid().asDomainBareJid());
        if (transport != null) {
            fullJIDLabel.setIcon(transport.getIcon());
            fullJIDLabel.setText(transport.getName() + " - " + contactItem.getJid().getLocalpartOrThrow().asUnescapedString());
        }
        else {
            fullJIDLabel.setText(contactItem.getJid().getLocalpartOrThrow().asUnescapedString());
            fullJIDLabel.setIcon(null);
        }

        avatarLabel.setBorder(null);

        try {
            URL avatarURL = contactItem.getAvatarURL();
            ImageIcon icon = null;
            if (avatarURL != null) {
                icon = new ImageIcon(avatarURL);
            }

            if (icon != null && icon.getIconHeight() > 1) {
                icon = GraphicUtils.scaleImageIcon(icon, 96, 96);
                avatarLabel.setIcon(icon);
            }
            else {
                icon = SparkRes.getImageIcon(SparkRes.DEFAULT_AVATAR_64x64_IMAGE);
                avatarLabel.setIcon(icon);
            }
            avatarLabel.setBorder(BorderFactory.createLineBorder(Color.lightGray, 1, true));
        }
        catch (MalformedURLException e) {
            Log.error(e);
        }

        // Get VCard from memory (if available)
        String title = "";
        String phone = "";
        VCard vcard = SparkManager.getVCardManager().getVCardFromMemory(contactItem.getJid().asBareJid());
        if (vcard != null) {
            title = vcard.getField("TITLE");
            phone = vcard.getPhoneWork("VOICE");
            if (!ModelUtil.hasLength(title)) {
                title = "";
            }
            if (!ModelUtil.hasLength(phone)) {
                phone = "";
            }
        }

        titleLabel.setText(title);
        phoneLabel.setText(phone);

    }

    public void setContactItem(ContactItem contactItem) {
        this.contactItem = contactItem;
        customizeUI(this.contactItem);
    }

    public ContactItem getContactItem() {
        return contactItem;
    }

    public void dispose() {
        window.setVisible(false);
        contactItem = null;
        window.dispose();
    }


    @Override
	public Dimension getPreferredSize() {
        final Dimension size = super.getPreferredSize();
        size.width = 300;
        size.height = 125;
        return size;
    }

    public void mouseExited(MouseEvent e) {
        Point point = e.getPoint();

        Dimension dim = window.getSize();

        int x = (int)point.getX();
        int y = (int)point.getY();

        boolean close = false;

        if (x < 0 || x >= dim.getWidth()) {
            close = true;
        }

        if (y < 0 || y >= dim.getHeight()) {
            close = true;
        }

        if (close) {
            window.setVisible(false);
            contactItem = null;
            hideWindow();
        }
    }

    protected void hideWindow() {
        window.setVisible(false);
        contactItem = null;
    }

    protected JWindow getWindow() {
        return window;
    }

    protected static Object getLock() {
        return LOCK;
    }



}
