﻿/*
 * Cuza Framework
 * Copyright (C) 2015, Maximilian Bauer
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program 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 for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

using System;
using System.Text.RegularExpressions;

namespace Cuza.Plugins
{
    /// <summary>
    /// Defines the reaction to a change of conditions within a value container.
    /// </summary>
    /// <param name="sender">The object which caused the event.</param>
    /// <param name="args">Informations about the log event.</param>
    public delegate void ValueContainerAction(object sender, EventArgs args);

    /// <summary>
    /// Defines a specialized extension which contains values (fields), which can be modified by
    /// the user/script during execution and need to be "synced" back after script execution.
    /// </summary>
    public interface IExtensionValueContainer : IExtension, IValueContainer
    {
        /// <summary>
        /// Defines an event which occurs after one or more values have been changed
        /// within or imported into the container.
        /// </summary>
        event ValueContainerAction ValueChanged;

        /// <summary>
        /// Updates the current extension and its values by importing the available data/field values from the specified namespace.
        /// </summary>
        /// <param name="sourceNamespace">The namespace to import the values from.</param>
        /// <exception cref="System.ArgumentNullException">Is thrown when the parameter is null.</exception>
        /// <exception cref="System.ArgumentException">
        /// Is thrown when the namespace contained values which couldn't be added or updated to the current extension
        /// (e.g. invalid variable identifiers, unsupported value types).
        /// </exception>
        /// <remarks>
        /// This method will be invoked by the framework after the execution of a script.
        /// Any changes made to the script namespace by the script (e.g. added or updated values)
        /// can be "updated back" into the extension context by this method.
        /// A possible use case would be the synchronization of the values from a non-shared 
        /// input/output parameter namespace after a successful execution.
        /// </remarks>
        void ImportValues(IScriptNamespace sourceNamespace); 
    }

    /// <summary>
    /// An utility class, which defines uniform methods to extend IExtensionValueContainer implementions.
    /// </summary>
    public static class ValueContainerExtension
    {
        private static Regex ValidIdentifier = new Regex("[A-Za-z_][A-Za-z_0-9]*");

        /// <summary>
        /// Checks if the specified identifier can be used as variable name in the current value container.
        /// The variable name has to match the regular expression "[A-Za-z][A-Za-z_0-9]*" to be valid.
        /// See the examples for more details.
        /// </summary>
        /// <param name="instance">The instance of the value container.</param>
        /// <returns>A boolean.</returns>
        /// <remarks>
        /// The "this" modifier on the first parameter has been used to include this method into every
        /// value container implementation automatically - it's not used during the identifier validation.
        /// </remarks>
        /// <example>
        /// The following examples define valid identifiers (according to the RegEx):
        /// "testValue", "Value42", "SOME_VALUE_420", "_bleh"
        /// The following examples define invalid identifiers (according to the RegEx):
        /// "2values" (first char is a number), "some value" (whitespace), "länge-box" (special characters), "" (empty identifier)
        /// </example>
        public static bool IsValidIdentifier(this IExtensionValueContainer instance, string identifier)
        {
            if (!string.IsNullOrWhiteSpace(identifier))
            {
                return ValidIdentifier.IsMatch(identifier);
            }
            else return false;
        }
    }
}
