/*  Copyright (c) 2000, 2001, 2003, Oracle Corporation. All Rights Reserved. */

package oracle.portal.provider.v2.personalize;

import java.util.*;
import oracle.portal.provider.v2.*;
import oracle.webdb.utils.SimpleStringBuffer;

/**
 *  A <code>PortletReference</code> is the 'key' with which items of
 *  customization data are accessed by a {@link
 *  PortletPersonalizationManager}. It is built on top of a {@link
 *  PortletInstance}, and adds the additional properties of the 'level' at
 *  which the customization applies (e.g. system default, locale default, or
 *  user specific), the locale to which the data applies (for locale default
 *  and user level customizations) and the user to which the data applies (for
 *  user level customizations).
 *
 */
public class PortletReference
{
    /**
     * The constant representing the system (least specific) level of customization.
     */
    public static final int TYPE_SYSTEM_DEFAULT = 0;

    /**
     * The constant representing the locale default level of customization.
     */
    public static final int TYPE_LOCALE_DEFAULT = 1;

    /**
     * The constant representing the user (most specific) level of customization.
     */
    public static final int TYPE_USER = 2;

    protected PortletInstance mPortletInstance;
    protected ProviderUser mUser; // particular user customization (if null then identified default instance)
    protected int mType; // type of instance - affects where the instance inherits default values from
    protected Locale mLocale; // locale that should be used when operating on behalf of this reference

    private String mLanguagePath;

    /**
     * Constructor.
     *
     * @param portletInstance The referenced portlet instance
     * @param user user of this <code>PortletReference</code> (if
     * applicable). Should be <code>null</code> for a system default or locale
     * default level <code>PortletReference</code>.
     * @param l locale of this <code>PortletReference</code> (if
     * applicable). Should be <code>null</code> or equal to the instance's
     * default locale, returned by {@link PortletInstance#getDefaultLocale} for
     * a locale default or system default level <code>PortletReference</code>.
     */
    public PortletReference(PortletInstance portletInstance,
                            ProviderUser user,
                            Locale l)
    {
        mPortletInstance = portletInstance;
        mUser = user;

        Locale defaultLocale = portletInstance.getDefaultLocale();
        if (l != null)
        {
            mLocale = l;
        }
        else
        {
            mLocale = defaultLocale;
        }

        if(mUser == null)
        {
            boolean possibleMatch = true;
            switch (portletInstance.getPortletDefinition()
                    .getLocalePersonalizationLevel())
            {
                case PortletConstants.PERSONALIZATION_LEVEL_LOCALE:
                    possibleMatch = mLocale.getCountry().equals(
                        defaultLocale.getCountry());
                    // Intentionally fall through
                case PortletConstants.PERSONALIZATION_LEVEL_LANGUAGE:
                    if (possibleMatch)
                    {
                        possibleMatch = mLocale.getLanguage().equals(
                            defaultLocale.getLanguage());
                    }
                    break;
                case PortletConstants.PERSONALIZATION_LEVEL_NONE:
                    // Consider any locale to match in this case.
                    break;
                default:
                    possibleMatch = false;
            }
            // Only consider this a system default if we got a match with the
            // default locale.
            mType = possibleMatch ? TYPE_SYSTEM_DEFAULT : TYPE_LOCALE_DEFAULT;
        }
        else
        {
            mType = TYPE_USER;
        }
    }

    /**
     * Gets the <code>ProviderInstance</code> referenced by this
     * <code>PortletReference</code>.
     * @return the <code>ProviderInstance</code> referenced by this
     * <code>PortletReference</code>.
     */
    public ProviderInstance getProviderInstance()
    {
        return mPortletInstance.getProviderInstance();
    }

    /**
     * Gets the ID of the <code>ProviderInstance</code> referenced by this
     * <code>PortletReference</code>. This is a convenience method for calling
     * {@link ProviderInstance#getProviderId
     * getProviderInstance().getProviderId()}.
     * @return the ID of the <code>ProviderInstance</code> referenced by this
     * <code>PortletReference</code>.
     */
    public String getProviderId()
    {
        return getProviderInstance().getProviderId();
    }


    /**
     * Gets the referenced <code>PortletInstance</code>.
     * @return the referenced <code>PortletInstance</code>.
     */
    public PortletInstance getPortletInstance()
    {
        return mPortletInstance;
    }

    /**
     * Gets the name of the <code>PortletInstance</code> referenced by this
     * <code>PortletReference</code>. This is a convenience method for calling
     * {@link PortletInstance#getInstanceName
     * getPortletInstance().getInstanceName()}.
     * @return the name of the <code>PortletInstance</code> referenced by this
     * <code>PortletReference</code>.
     */
    public String getInstanceName()
    {
        return mPortletInstance.getInstanceName();
    }

    /**
     * Gets the <code>PortletDefinition</code> which defines the referenced
     * <code>PortletInstance</code>.
     * @return the <code>PortletDefinition</code> which defines the referenced
     * <code>PortletInstance</code>.
     */
    public PortletDefinition getPortletDefinition()
    {
        return mPortletInstance.getPortletDefinition();
    }

    /**
     * Gets the ID of the <code>PortletDefinition</code> which defines the
     * referenced <code>PortletInstance</code>. This is a convenience method
     * for calling {@link PortletDefinition#getId
     * getPortletDefinition().getId()}.
     * @return the ID of the <code>PortletDefinition</code> which defines the
     * referenced <code>PortletInstance</code>.
     */
    public long getPortletId()
    {
        return getPortletDefinition().getId();
    }


    /**
     * Gets the user whose customization is requested with this instance.
     * @return the user whose customization is requested with this instance.
     * If <b>null</b> then this reference indicates a locale default or system
     * default level reference.
     */
    public ProviderUser getUser()
    {
        return mUser;
    }

    /**
     * Gets the Locale that should be used on behalf of this reference.
     * @return the Locale that should be used on behalf of this reference.
     */
    public Locale getLocale()
    {
        return mLocale;
    }

    /**
     * Determines whether this is a system default or locale default level
     * reference rather than a user level reference.
     * @return <code>true</code> if this is a system default or locale default
     * level reference, <code>false</code> otherwise.
     */
    public boolean isDefault()
    {
        return mType == TYPE_SYSTEM_DEFAULT || mType == TYPE_LOCALE_DEFAULT;
    }

    /**
     * Determines whether this is a locale default level reference.
     * @return <code>true</code> if this is a locale default level reference,
     * <code>false</code> otherwise.
     */
    public boolean isLanguageDefault()
    {
        return mType == TYPE_LOCALE_DEFAULT;
    }

    /**
     * Gets a constant representing the 'type' of this
     * <code>PortletReference</code>: system default, locale default or user
     * level.
     * @return a constant representing the 'type' of this
     * <code>PortletReference</code>. Will be one of the constants defined in
     * this class.
     */
    public int getType()
    {
        return mType;
    }

    /**
     * Assembles the appropriate language path to be used when reading/writing
     * this {@link PortletReference} from/to a persistent store based on the
     * portlet's locale personalization level. For more information on the 
     * locale personalization level, see {@link
     * PortletDefinition#setLocalePersonalizationLevel(int)}.
     * 
     * @return the appropriate language path.
     */
    public String getLanguagePath()
    {
        if (mLanguagePath == null)
        {
            int type = getPortletDefinition().getLocalePersonalizationLevel();
            if (type == PortletConstants.PERSONALIZATION_LEVEL_NONE)
            {
                return "";
            }
            SimpleStringBuffer path = new SimpleStringBuffer(10);
            path.append(getLocale().getLanguage());
            if (type == PortletConstants.PERSONALIZATION_LEVEL_LOCALE)
            {
                String country = getLocale().getCountry();
                if (country != null && country.length() > 0)
                {
                    path.append("_").append(country);
                }
            }
            mLanguagePath = path.toString();
        }
        return mLanguagePath;
    }

    /**
     * Returns a String representation of this reference in the form
     * <code>ProviderId.PortletId.PortletInstanceName.UserName</code>.
     *
     * If this is a system default level reference then the
     * <code>.Username</code> is ommitted.
     *
     * @return a String representation of this reference.  
     */
    public String toString()
    {
        return toString(getType());
    }

    /**
     *  Returns a String representation of this reference modified according to
     *  the <code>refType</code> parameter.
     *
     *  For example, if the <code>PortletReference</code> is for a user level
     *  customization but the user customization does not exist so we are
     *  falling back to one of the defaults, then we need to adjust how the
     *  reference is displayed.
     *
     *  The reference is returned in the form: <p>
     *  <code>ProviderId.PortletId.PortletInstanceName.UserName</code><p>
     *
     *  If <code>refType</code> denotes the locale default or system default
     *  level, then the <code>.Username</code> is omitted.
     *
     *  @return a String representation of this reference
     */
    public String toString(int refType)
    {
        SimpleStringBuffer buf = new SimpleStringBuffer(100);
        buf.append(getProviderId());
        buf.append(".");
        buf.append(getPortletId());
        buf.append(".");
        buf.append(getInstanceName());
        if (refType == TYPE_USER && mUser != null)
        {
            buf.append(".");
            buf.append(getUser().getName());
        }
        return buf.toString();
    }
}
