/// <summary>
        /// Formats the quantity based on a series of options to provide
        /// various human readable alternatives.
        /// </summary>
        /// <seealso cref="ForgedSoftware.Measurement.QuantityFormatInfo"/>
        /// <param name="info">An object detailing the different format options</param>
        /// <returns>The formatted string.</returns>
        public string Format(QuantityFormatInfo info)
        {
            info = info ?? QuantityFormatInfo.CurrentInfo;

            string formatType = (info.FormatParts == QuantityFormatInfo.QuantityParts.All) ? "Q" : "";

            if (info.ScientificExponent)
            {
                formatType += (info.AsciiOnly) ? "T" : "S";
            }
            formatType += info.DefaultDoubleFormat;

            string precision = (info.Precision < 0) ? "" : info.Precision.ToString();

            // Value
            string valueStr = Value.ToString(formatType + precision, info.NumberFormat);

            // Dimensions
            bool   isPlural = (Math.Abs(Value.EquivalentValue - 1) > Double.Epsilon);
            string dimStr   = FormatDimensions(info, isPlural);

            // Returning
            if (info.FormatParts == QuantityFormatInfo.QuantityParts.Dimensions)
            {
                return(dimStr);
            }
            if (info.FormatParts == QuantityFormatInfo.QuantityParts.Value)
            {
                return(valueStr);
            }
            return(string.Format(valueStr, dimStr));
        }
        /// <summary>
        /// Provides a ToString method with a couple of format options.
        /// A specific IFormatProvider can be specified, else the current culture is used.
        ///
        /// The avaliable format strings are:
        /// - "G": General format, uses the default format options
        /// - "S": Scientific format is equivalent to the General format
        /// - "R": Raw format is an rough, ascii only format
        /// </summary>
        /// <param name="format">The format letter</param>
        /// <param name="provider">An optional format provider</param>
        /// <returns>The formatted string</returns>
        public string ToString(string format, IFormatProvider provider = null)
        {
            if (String.IsNullOrEmpty(format))
            {
                format = "G";
            }
            format = format.Trim().ToUpperInvariant();

            QuantityFormatInfo options = QuantityFormatInfo.GetInstance(provider).Clone();

            switch (format)
            {
            case "G":
            case "S":
                break;

            case "R":
                options.AsciiOnly          = true;
                options.ScientificExponent = false;
                break;

            default:
                throw new ArgumentException("Provided format string is not recognized");
            }

            return(Format(options));
        }
        /// <summary>
        /// Parameterless constructor that sets up all the default values of the options
        /// </summary>
        public MeasurementOptions()
        {
            // Defaults - General
            AllowReorderingDimensions = true;

            // Defaults - Dimensions
            AllowDerivedDimensions = true;
            AllowVectorDimensions  = false;
            IgnoredDimensions      = new List <DimensionDefinition>();

            // Defaults - Units
            UseEstimatedUnits = false;
            UseRareUnits      = false;

            // Defaults - Measurement Systems
            AllowedSystemsForUnits = new List <MeasurementSystem>();
            IgnoredSystemsForUnits = new List <MeasurementSystem>();

            // Defaults - Prefixes
            UseAutomaticPrefixManagement = true;
            UseRarePrefixes               = false;
            UseUnofficalPrefixes          = false;
            AllowedRarePrefixCombinations = new List <KeyValuePair <Unit, Prefix> > {
                new KeyValuePair <Unit, Prefix>(
                    MeasurementCorpus.FindUnit("metre"), MeasurementCorpus.FindPrefix("centi"))
            };
            PreferBinaryPrefixes    = true;
            UpperPrefixValue        = 1000;
            LowerPrefixValue        = 1;
            HavingPrefixScoreOffset = 1;

            // Defaults - Formatting
            QuantityFormat = new QuantityFormatInfo();
        }
        private string FormatDimensions(QuantityFormatInfo info, bool isPlural)
        {
            List <Dimension> clonedDimensions = Dimensions.CloneList();

            if (info.SortDimensions)
            {
                clonedDimensions = clonedDimensions.OrderBy(d => - d.Power).ToList();
            }
            IEnumerable <string> dimensionStrings = clonedDimensions.Select(d => d.Format(info, isPlural));

            string joiner = (info.TextualDescription) ? " " : info.UnitSeparator;

            return(dimensionStrings.Aggregate((current, next) => current + joiner + next));
        }
        /// <summary>
        /// Provides a formatted version of the dimension given a provided
        /// set of format options.
        /// </summary>
        /// <seealso cref="ForgedSoftware.Measurement.QuantityFormatInfo"/>
        /// <param name="info">The format options</param>
        /// <param name="isPlural">Whether the dimension should be plural</param>
        /// <returns>The formatted string</returns>
        public string Format(QuantityFormatInfo info, bool isPlural)
        {
            info = info ?? QuantityFormatInfo.CurrentInfo;
            string dimensionString = "";

            if (info.TextualDescription)
            {
                var dimParts = new List <string>();
                if (Power < 0)
                {
                    dimParts.Add("per");                     // TODO - i18n
                }
                string name = PluralizedName(isPlural);
                if (Prefix != null)
                {
                    name = Prefix.Key + name;
                }
                dimParts.Add(name);
                int absPower = Math.Abs(Power);
                if (absPower == 2)
                {
                    dimParts.Add("squared");                     // TODO - i18n
                }
                else if (absPower == 3)
                {
                    dimParts.Add("cubed");                     // TODO - i18n
                }
                else if (absPower > 3 || absPower == 0)
                {
                    dimParts.Add("to the power of " + absPower);                     // TODO - i18n
                }
                dimensionString = dimParts.Aggregate((current, next) => current + " " + next);
            }
            else
            {
                if (Prefix != null)
                {
                    dimensionString += Prefix.Symbol;
                }
                dimensionString += (!string.IsNullOrWhiteSpace(Unit.Symbol)) ? Unit.Symbol : PluralizedName(isPlural);
                if (info.ShowAllPowers || Power != DEFAULT_POWER)
                {
                    string powerStr = (info.AsciiOnly) ? "^" + Power : Power.ToSuperScript();
                    dimensionString += powerStr;
                }
            }
            return(dimensionString);
        }
 /// <summary>
 /// A format method for formatting dimensions in a non-plural context.
 /// </summary>
 /// <param name="info">The format options</param>
 /// <returns>The formatted string</returns>
 public string Format(QuantityFormatInfo info)
 {
     return(Format(info, false));
 }