using System;

namespace Unosquare.Swan.Attributes {
  /// <summary>
  /// Models an option specification.
  /// Based on CommandLine (Copyright 2005-2015 Giacomo Stelluti Scala and Contributors.).
  /// </summary>
  [AttributeUsage(AttributeTargets.Property)]
  public sealed class ArgumentOptionAttribute
      : Attribute {
    /// <summary>
    /// Initializes a new instance of the <see cref="ArgumentOptionAttribute"/> class.
    /// The default long name will be inferred from target property.
    /// </summary>
    public ArgumentOptionAttribute()
        : this(String.Empty, String.Empty) {
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="ArgumentOptionAttribute"/> class.
    /// </summary>
    /// <param name="longName">The long name of the option.</param>
    public ArgumentOptionAttribute(String longName)
        : this(String.Empty, longName) {
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="ArgumentOptionAttribute"/> class.
    /// </summary>
    /// <param name="shortName">The short name of the option.</param>
    /// <param name="longName">The long name of the option or null if not used.</param>
    public ArgumentOptionAttribute(Char shortName, String longName)
        : this(new String(shortName, 1), longName) {
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="ArgumentOptionAttribute"/> class.
    /// </summary>
    /// <param name="shortName">The short name of the option..</param>
    public ArgumentOptionAttribute(Char shortName)
        : this(new String(shortName, 1), String.Empty) {
    }

    private ArgumentOptionAttribute(String shortName, String longName) {
      this.ShortName = shortName ?? throw new ArgumentNullException(nameof(shortName));
      this.LongName = longName ?? throw new ArgumentNullException(nameof(longName));
    }

    /// <summary>
    /// Gets long name of this command line option. This name is usually a single English word.
    /// </summary>
    /// <value>
    /// The long name.
    /// </value>
    public String LongName {
      get;
    }

    /// <summary>
    /// Gets a short name of this command line option, made of one character.
    /// </summary>
    /// <value>
    /// The short name.
    /// </value>
    public String ShortName {
      get;
    }

    /// <summary>
    /// When applying attribute to <see cref="System.Collections.Generic.IEnumerable{T}"/> target properties,
    /// it allows you to split an argument and consume its content as a sequence.
    /// </summary>
    public Char Separator { get; set; } = '\0';

    /// <summary>
    /// Gets or sets mapped property default value.
    /// </summary>
    /// <value>
    /// The default value.
    /// </value>
    public Object DefaultValue {
      get; set;
    }

    /// <summary>
    /// Gets or sets a value indicating whether a command line option is required.
    /// </summary>
    /// <value>
    ///   <c>true</c> if required; otherwise, <c>false</c>.
    /// </value>
    public Boolean Required {
      get; set;
    }

    /// <summary>
    /// Gets or sets a short description of this command line option. Usually a sentence summary.
    /// </summary>
    /// <value>
    /// The help text.
    /// </value>
    public String HelpText {
      get; set;
    }
  }
}