/*
 * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * 
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 * 
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 * 
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 * 
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.tools.visualvm.application;

import com.sun.tools.visualvm.application.jvm.Jvm;
import com.sun.tools.visualvm.application.jvm.JvmFactory;
import com.sun.tools.visualvm.application.type.ApplicationType;
import com.sun.tools.visualvm.application.type.ApplicationTypeFactory;
import com.sun.tools.visualvm.core.datasource.descriptor.DataSourceDescriptor;
import java.awt.Image;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;

/**
 * DataSourceDescriptor for Application.
 *
 * @author Jiri Sedlacek
 */
public class ApplicationDescriptor extends DataSourceDescriptor<Application> {
    
    private static final String DISPLAY_NAME_PROPERTY = "-Dvisualvm.display.name="; // NOI18N
     
    private String name;

    /**
     * Creates new instance of Application Descriptor.
     *
     * @param application Application described by the descriptor
     */
    protected ApplicationDescriptor(Application application) {
        this(application, ApplicationTypeFactory.getApplicationTypeFor(
             application), POSITION_AT_THE_END);
    }

    /**
     * Creates new instance of Application Descriptor.
     *
     * @param application Application described by the descriptor
     * @param preferredPosition preferred position of the Application
     *
     * @since VisualVM 1.3
     */
    protected ApplicationDescriptor(Application application, int preferredPosition) {
        this(application, ApplicationTypeFactory.getApplicationTypeFor(application),
             preferredPosition);
    }

    private ApplicationDescriptor(final Application application, final ApplicationType type,
                                  int preferredPosition) {
        super(application, resolveApplicationName(application, type), type.getDescription(),
              type.getIcon(), preferredPosition, EXPAND_ON_FIRST_CHILD);
        name = super.getName();
        type.addPropertyChangeListener(new PropertyChangeListener() {
            public void propertyChange(PropertyChangeEvent evt) {
                String propertyName = evt.getPropertyName();
                if (ApplicationType.PROPERTY_NAME.equals(propertyName)) {
                    // Name already customized by the user, do not change it
                    if (resolveName(application, null) != null) return;
                    
                    if (supportsRename()) {
                        // Descriptor supports renaming, use setName(), sync name
                        setName((String)evt.getNewValue());
                        name = ApplicationDescriptor.super.getName();
                    } else {
                        // Descriptor doesn't support renaming, set name for overriden getName()
                        String oldName = name;
                        name = createGenericName(application, type.getName());
                        PropertyChangeSupport pcs = ApplicationDescriptor.this.getChangeSupport();
                        pcs.firePropertyChange(PROPERTY_NAME, oldName, name);
                    }
                } else if (ApplicationType.PROPERTY_ICON.equals(propertyName)) {
                    setIcon((Image)evt.getNewValue());
                } else if (ApplicationType.PROPERTY_DESCRIPTION.equals(propertyName)) {
                    setDescription((String)evt.getNewValue());
                } else if (ApplicationType.PROPERTY_VERSION.equals(propertyName)) {
                    // Not supported by ApplicationDescriptor
                }
            }
        });
    }
    
    public String getName() {
        if (supportsRename()) return super.getName();
        else return name;
    }

    public boolean providesProperties() {
        return true;
    }

    /**
     * Returns Application name if available in Snapshot Storage as PROPERTY_NAME
     * or user-provided display name defined by JVM argument <code>-Dvisualvm.display.name</code>
     * (since VisualVM 1.3.4) or generates new name using the provided ApplicationType.
     *
     * @param application Application for which to resolve the name
     * @param type ApplicationType to be used for generating Application name
     * @return persisted Application name if available or new generated name
     *
     * @since VisualVM 1.3
     */
    protected static String resolveApplicationName(Application application, ApplicationType type) {
        // Check for persisted displayname (currently only for JmxApplications)
        String persistedName = resolveName(application, null);
        if (persistedName != null) return persistedName;
        
        // Check for custom name defined by -Dvisualvm.display.name
        String customName = resolveCustomName(application);
        if (customName != null) return customName;

        // Provide generic displayname
        return createGenericName(application, type.getName());
    }
    
    private static String resolveCustomName(Application application) {
        Jvm jvm = JvmFactory.getJVMFor(application);
        if (jvm.isBasicInfoSupported()) {
            String args = jvm.getJvmArgs();
            int propIndex = args.indexOf(DISPLAY_NAME_PROPERTY);

            if (propIndex != -1) {  // display name propery detected on commandline
                propIndex += DISPLAY_NAME_PROPERTY.length();
                int endIndex = args.indexOf(" ", propIndex); // NOI18N
                if (endIndex == -1) return args.substring(propIndex);
                else return args.substring(propIndex, endIndex);
            }
        }
        return null;
    }
    
    private static String createGenericName(Application application, String nameBase) {
        int pid = application.getPid();
        String id = Application.CURRENT_APPLICATION.getPid() == pid ||
        pid == Application.UNKNOWN_PID ? "" : " (pid " + pid + ")"; // NOI18N
        return nameBase + id;
    }
    
}
