/**
* @file llnotificationtemplate.h
* @brief Description of notification contents
* @author Q (with assistance from Richard and Coco)
*
* $LicenseInfo:firstyear=2008&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
* $/LicenseInfo$
*/

#ifndef LL_LLNOTIFICATION_TEMPLATE_H
#define LL_LLNOTIFICATION_TEMPLATE_H

#include "llinitparam.h"
#include "llnotifications.h"

typedef std::shared_ptr<LLNotificationForm> LLNotificationFormPtr;

// This is the class of object read from the XML file (notifications.xml,
// from the appropriate local language directory).
struct LLNotificationTemplate
{
    struct CombineBehaviorNames
        :   public LLInitParam::TypeValuesHelper<LLNotification::ECombineBehavior, CombineBehaviorNames>
    {
        static void declareValues()
        {
            declare("replace_with_new", LLNotification::REPLACE_WITH_NEW);
            declare("combine_with_new", LLNotification::COMBINE_WITH_NEW);
            declare("keep_old", LLNotification::KEEP_OLD);
            declare("cancel_old", LLNotification::CANCEL_OLD);
        }
    };


    struct GlobalString : public LLInitParam::Block<GlobalString>
    {
        Mandatory<std::string>  name,
                                value;

        GlobalString()
        :   name("name"),
            value("value")
        {}
    };

    struct UniquenessContext : public LLInitParam::Block<UniquenessContext>
    {
        Mandatory<std::string>  value;

        UniquenessContext()
        :   value("value")
        {
            addSynonym(value, "key");
        }

    };

    struct UniquenessConstraint : public LLInitParam::Block<UniquenessConstraint>
    {
    private:
        // this idiom allows
        // <notification> <unique/> </notification>
        // as well as
        // <notification> <unique> <context></context> </unique>...
        Optional<LLInitParam::Flag> dummy_val;
    public:
        Multiple<UniquenessContext> contexts;
        Optional<LLNotification::ECombineBehavior, CombineBehaviorNames> combine;

        UniquenessConstraint()
        :   contexts("context"),
            combine("combine", LLNotification::REPLACE_WITH_NEW),
            dummy_val("")
        {}
    };

    // Templates are used to define common form types, such as OK/Cancel dialogs, etc.

    struct Template : public LLInitParam::Block<Template>
    {
        Mandatory<std::string>                  name;
        Mandatory<LLNotificationForm::Params>   form;

        Template()
        :   name("name"),
            form("form")
        {}
    };

    // Reference a template to use its form elements
    struct TemplateRef : public LLInitParam::Block<TemplateRef>
    {
        Mandatory<std::string>  name;
        Optional<std::string>   yes_text,
                                no_text,
                                cancel_text,
                                help_text,
                                ignore_text;

        TemplateRef()
        :   name("name"),
            yes_text("yestext"),
            no_text("notext"),
            cancel_text("canceltext"),
            help_text("helptext"),
            ignore_text("ignoretext")
        {}
    };

    struct URL : public LLInitParam::Block<URL>
    {
        Mandatory<S32>          option;
        Mandatory<std::string>  value;
        Optional<std::string>   target;
        Ignored                 name;

        URL()
        :   option("option", -1),
            value("value"),
            target("target", "_blank"),
            name("name")
        {}
    };

    struct FormRef : public LLInitParam::ChoiceBlock<FormRef>
    {
        Alternative<LLNotificationForm::Params>     form;
        Alternative<TemplateRef>                    form_template;

        FormRef()
        :   form("form"),
            form_template("usetemplate")
        {}
    };

    struct Tag : public LLInitParam::Block<Tag>
    {
        Mandatory<std::string>  value;

        Tag()
        :   value("value")
        {}
    };

    struct Footer : public LLInitParam::Block<Footer>
    {
        Mandatory<std::string> value;

        Footer()
        :   value("value")
        {
            addSynonym(value, "");
        }
    };

    struct Params : public LLInitParam::Block<Params>
    {
        Mandatory<std::string>          name;
        Optional<bool>                  persist,
                                        log_to_im,
                                        show_toast,
                                        fade_toast,
                                        log_to_chat,
                                        force_urls_external;
        Optional<std::string>           functor,
                                        icon,
                                        label,
                                        sound,
                                        type,
                                        value;
        Optional<U32>                   duration;
        Optional<S32>                   expire_option;
        Optional<URL>                   url;
        Optional<UniquenessConstraint>  unique;
        Optional<FormRef>               form_ref;
        Optional<ENotificationPriority,
            NotificationPriorityValues> priority;
        Multiple<Tag>                   tags;
        Optional<Footer>                footer;


        Params()
        :   name("name"),
            persist("persist", false),
            fade_toast("fade_toast", true),
            log_to_im("log_to_im", false),
            show_toast("show_toast", true),
            log_to_chat("log_to_chat", true),
            force_urls_external("force_urls_external", false),
            functor("functor"),
            icon("icon"),
            label("label"),
            priority("priority"),
            sound("sound"),
            type("type"),
            value("value"),
            duration("duration"),
            expire_option("expireOption", -1),
            url("url"),
            unique("unique"),
            form_ref(""),
            tags("tag"),
            footer("footer")
        {}

    };

    struct Notifications : public LLInitParam::Block<Notifications>
    {
        Multiple<GlobalString>  strings;
        Multiple<Template>      templates;
        Multiple<Params>        notifications;

        Notifications()
        :   strings("global"),
            notifications("notification"),
            templates("template")
        {}
    };

    LLNotificationTemplate(const Params& p);
    // the name of the notification -- the key used to identify it
    // Ideally, the key should follow variable naming rules
    // (no spaces or punctuation).
    std::string mName;
    // The type of the notification
    // used to control which queue it's stored in
    std::string mType;
    // The text used to display the notification. Replaceable parameters
    // are enclosed in square brackets like this [].
    std::string mMessage;
    // The text used to display the notification, but under the form.
    std::string mFooter;
    // The label for the notification; used for
    // certain classes of notification (those with a window and a window title).
    // Also used when a notification pops up underneath the current one.
    // Replaceable parameters can be used in the label.
    std::string mLabel;
    // The name of the icon image. This should include an extension.
    std::string mIcon;
    // This is the Highlander bit -- "There Can Be Only One"
    // An outstanding notification with this bit set
    // is updated by an incoming notification with the same name,
    // rather than creating a new entry in the queue.
    // (used for things like progress indications, or repeating warnings
    // like "the grid is going down in N minutes")
    bool mUnique;
    LLNotification::ECombineBehavior mCombineBehavior;
    // if we want to be unique only if a certain part of the payload or substitutions args
    // are constant specify the field names for the payload. The notification will only be
    // combined if all of the fields named in the context are identical in the
    // new and the old notification; otherwise, the notification will be
    // duplicated. This is to support suppressing duplicate offers from the same
    // sender but still differentiating different offers. Example: Invitation to
    // conference chat.
    std::vector<std::string> mUniqueContext;
    // If this notification expires automatically, this value will be
    // nonzero, and indicates the number of seconds for which the notification
    // will be valid (a teleport offer, for example, might be valid for
    // 300 seconds).
    U32 mExpireSeconds;
    // if the offer expires, one of the options is chosen automatically
    // based on its "value" parameter. This controls which one.
    // If expireSeconds is specified, expireOption should also be specified.
    U32 mExpireOption;
    // if the notification contains a url, it's stored here (and replaced
    // into the message where [_URL] is found)
    std::string mURL;
    // if there's a URL in the message, this controls which option visits
    // that URL. Obsolete this and eliminate the buttons for affected
    // messages when we allow clickable URLs in the UI
    U32 mURLOption;

    //This is a flag that tells if option url needs to open externally dispite
    //what the user setting is.
    std::string mURLTarget;

    // All links clicked inside notification will be opened in external browser
    // Note: Some notifications block and exit viewer, yet they provide a link
    // to click, we should be able to open such links in external browser.
    bool mForceUrlsExternal;

    // does this notification persist across sessions? if so, it will be
    // serialized to disk on first receipt and read on startup
    bool mPersist;
    // This is the name of the default functor, if present, to be
    // used for the notification's callback. It is optional, and used only if
    // the notification is constructed without an identified functor.
    std::string mDefaultFunctor;
    // The form data associated with a given notification (buttons, text boxes, etc)
    LLNotificationFormPtr mForm;
    // default priority for notifications of this type
    ENotificationPriority mPriority;
    // Stores the sound name which can then be used to play the sound using make_ui_sound
    std::string mSoundName;
    // List of tags that rules can match against.
    std::list<std::string> mTags;

    // inject these notifications into chat/IM streams
    bool mLogToChat;
    bool mLogToIM;
    bool mShowToast;
    bool mFadeToast;
};

#endif //LL_LLNOTIFICATION_TEMPLATE_H