/// <summary>
        /// Displays a notification.
        /// </summary>
        /// <param name="uid">(Optional)A unique identifier for the notification so the sending application can track events related to it and update it if required. </param>
        /// <param name="classId">(Optional)The identifier of the class to use.</param>
        /// <param name="title">(Optional)Notification title.</param>
        /// <param name="text">(Optional) Notification body text.</param>
        /// <param name="timeout">(Optional)The amount of time, in seconds, the notification should remain on screen.</param>
        /// <param name="icon">(Optional) The icon to use, see the notes below for details of supported formats.</param>
        /// <param name="iconBase64">(Optional) Base64-encoded bytes to be used as the icon.</param>
        /// <param name="sound">(Optional) The path to a sound file to play.</param>
        /// <param name="callback">(Optional) Callback to be invoked when the user clicks on the main body area of the notification.</param>
        /// <param name="priority">(Optional) The urgency of the notification, <see cref="SnarlMessagePriority"/> and Priorities in the Developer Guide for more information on how Snarl deals with different priorities. </param>
        /// <param name="sensitivity">(Optional) The sensitivity of the notification.  See the Sensitivity section in the Developer Guide for more information.</param>
        /// <param name="value-percent">(Optional) A decimal percent value to be included with the notification.  Certain styles can display this value as a meter or other visual representation.  See Custom Values in the Developer Guide for more information.</param>
        /// <param name="action">Optional) Actions to add to the notification - <see cref="ActionCollection"/> and see Action section in the Developer Guide for more information.</param>
        /// <remarks><see cref="https://sites.google.com/site/snarlapp/developers/api-reference#TOC-notify"/></remarks>
        public Int32 Notify(String uId = null, String classId = null, String title = null, String text = null,
                            Int32? timeout = null, String icon = null, String iconBase64 = null,
                            String sound = null, String callback = null, String callbackLabel = null, SnarlMessagePriority? priority = null,
                            String sensitivity = null, decimal? valuePercent = null, SnarlAction[] actions = null)
        {
            if (appSignature == null)
                throw new InvalidOperationException("AppSignature is null - the applications is properly not registered correctly with Snarl.");

            // Build parameter list
            int paramListSize = 15 + (actions != null ? actions.Length : 0);
            SnarlParameterList spl = new SnarlParameterList(paramListSize);
            spl.Add("app-sig", appSignature);
            spl.Add("password", password);

            spl.Add("uid", uId);
            spl.Add("id", classId);
            spl.Add("title", title);
            spl.Add("text", text);
            spl.Add("timeout", timeout);
            spl.Add("icon", icon);
            spl.Add("icon-base64", iconBase64);
            spl.Add("sound", sound);
            spl.Add("callback", callback);
            spl.Add("callback-label", callbackLabel);
            spl.Add("priority", (Int32?)priority);
            spl.Add("sensitivity", sensitivity);
            spl.Add("value-percent", sensitivity);
            spl.Add(actions);

            return DoRequest(SnarlRequests.Notify, spl);
        }
        /// <summary>
        /// Registers an application with Snarl.
        /// </summary>
        /// <param name="appSignatur">The application's signature.</param>
        /// <param name="title">The application's name.</param>
        /// <param name="password">Password used during registration.</param>
        /// <param name="icon">(Optional) The icon to use.</param>
        /// <param name="hWndReply">(Optional) The handle to a window (HWND) which Snarl should post events to. <seealso cref="RegisterWithEvents"/></param>
        /// <param name="msgReply">(Optional) The message Snarl should use to post to the hWndReply Window.</param>
        /// <remarks><see cref="https://sites.google.com/site/snarlapp/developers/api-reference#TOC-register"/></remarks>
        public Int32 Register(String appSignature, String title, String password,
                              String icon = null, IntPtr hWndReplyTo = default(IntPtr), Int32 msgReply = 0)
        {
            if (String.IsNullOrEmpty(appSignature))
                throw new ArgumentNullException("appSignature");
            if (String.IsNullOrEmpty(title))
                throw new ArgumentNullException("title");
            if (String.IsNullOrEmpty(password))
                throw new ArgumentNullException("password");

            SnarlParameterList spl = new SnarlParameterList(7);
            spl.Add("app-sig", appSignature);
            spl.Add("title", title);
            spl.Add("password", password);

            spl.Add("icon", icon);
            spl.Add("reply-to", hWndReplyTo);
            spl.Add("reply", msgReply);
            spl.Add("flags", 0);

            Int32 request = DoRequest(SnarlRequests.Register, spl);
            if (request > 0)
            {
                this.appSignature = appSignature;
                this.password = password;
                this.msgReply = msgReply;
            }

            return request;
        }
        /// <summary>
        /// Removes all classes associated with a particular application.
        /// </summary>
        /// <remarks><see cref="https://sites.google.com/site/snarlapp/developers/api-reference#TOC-clearclasses"/></remarks>
        public Int32 ClearClasses()
        {
            SnarlParameterList spl = new SnarlParameterList(2);
            spl.Add("app-sig", appSignature);
            spl.Add("password", password);

            return DoRequest(SnarlRequests.ClearClasses, spl);
        }
        /// <summary>
        /// Removes the specified notification from the screen or missed list.
        /// </summary>
        /// <remarks><see cref="https://sites.google.com/site/snarlapp/developers/api-reference#TOC-hide"/></remarks>
        public Int32 Hide(String uId)
        {
            SnarlParameterList spl = new SnarlParameterList(2);
            spl.Add("app-sig", appSignature);
            spl.Add("password", password);
            spl.Add("uid", uId);

            return DoRequest(SnarlRequests.Hide, spl);
        }
        /// <summary>
        /// Removes all actions associated with the specified notification.
        /// </summary>
        /// <remarks><see cref="https://sites.google.com/site/snarlapp/developers/api-reference#TOC-clearactions"/></remarks>
        public Int32 ClearActions(String uId)
        {
            SnarlParameterList spl = new SnarlParameterList(3);
            spl.Add("app-sig", appSignature);
            spl.Add("password", password);
            spl.Add("uid ", uId);

            return DoRequest(SnarlRequests.ClearActions, spl);
        }
        /// <summary>
        /// Adds a notification class to a previously registered application.
        /// </summary>
        /// <remarks><see cref="https://sites.google.com/site/snarlapp/developers/api-reference#TOC-addclass"/></remarks>
        public Int32 AddClass(String classId, String className = null,
                              String title = null, String text = null, String icon = null,
                              String sound = null, Int32? duration = null, String callback = null, bool enabled = true)
        {
            SnarlParameterList spl = new SnarlParameterList(11);
            spl.Add("app-sig", appSignature);
            spl.Add("password", password);

            spl.Add("class-id", classId);
            spl.Add("class-name", className);
            spl.Add("enabled", enabled);
            spl.Add("callback", callback);
            spl.Add("title", title);
            spl.Add("text", text);
            spl.Add("icon", icon);
            spl.Add("sound", sound);
            spl.Add("duration", duration);

            return DoRequest(SnarlRequests.AddClass, spl);
        }
        /// <summary>
        /// Constructs a request string from the request parameter and the given parameter list
        /// and sends the action request to Snarl.
        /// </summary>
        /// <param name="action">The Snarl action to perform - ie. notify. <seealso cref="SnarlRequests"/>.</param>
        /// <param name="spl">List of key/value pairs with parameters for the request.</param>
        /// <param name="replyTimeout">(Optional - default = 1000 milliseconds)</param>
        /// <returns>Return zero or positive on success. Negative on error.</returns>
        public static Int32 DoRequest(String action, SnarlParameterList spl, UInt32 replyTimeout = 1000)
        {
            // Creates string of format: <action>[?<data>=<value>[&<data>=<value>]]
            // and sends the String through other DoRequest() overload.

            if (spl.ParamList.Count > 0)
            {
                StringBuilder sb = new StringBuilder(action);
                sb.Append("?");

                foreach (KeyValuePair<String, String> kvp in spl.ParamList)
                {
                    if (kvp.Value != null && kvp.Value.Length > 0)
                    {
                        sb.AppendFormat("{0}={1}&", kvp.Key, Escape(kvp.Value));
                    }
                }

                // Delete last &
                sb.Remove(sb.Length - 1, 1);

                return DoRequest(sb.ToString(), replyTimeout);
            }
            else
            {
                return DoRequest(action, replyTimeout);
            }
        }
        /// <summary>
        /// Unregisters the application.
        /// </summary>
        /// <remarks><see cref="https://sites.google.com/site/snarlapp/developers/api-reference#TOC-unregister"/></remarks>
        public Int32 Unregister()
        {
            SnarlParameterList spl = new SnarlParameterList(2);
            spl.Add("app-sig", appSignature);
            spl.Add("password", password);

            appSignature = null;
            password = null;
            msgReply = 0;

            UnregisterCallbackWindow(); // Will only do work if RegisterWithEvents has been called

            return DoRequest(SnarlRequests.Unregister, spl);
        }
        /// <summary>
        /// Removes a particular notification class from a registered application.
        /// </summary>
        /// <seealso cref="ClearClasses"/>
        /// <remarks><see cref="https://sites.google.com/site/snarlapp/developers/api-reference#TOC-remclass"/></remarks>
        public Int32 RemoveClass(String classId)
        {
            SnarlParameterList spl = new SnarlParameterList(3);
            spl.Add("app-sig", appSignature);
            spl.Add("password", password);
            spl.Add("id", classId);

            return DoRequest(SnarlRequests.RemoveClass, spl);
        }