/** ****************************************************************************************
         *  Converts the given unsigned 64 bit integer value to a string representation.<br>
         *  Negative numbers have to be converted to positive values when invoking this method.
         *  The maximum number of digits written are 20. The given buffer has to be large
         *  enough to receive the characters. The method does not check any overflow within the
         *  given character buffer.
         *
         *  \note This method is used internally by various AString conversion methods. It is
         *        advisable to use AString methods to convert integer values.
         *
         * @param value        The integer value to convert.
         * @param buffer       The character array to write the value to. Depending on the value
         *                     given, a maximum of 20 characters need to be allocated prior to
         *                     invoking this method.
         * @param idx          The index within the character array to write the value to.
         * @param minDigits    The minimum number of digits to append.
         *                     If given value has less digits, '0' characters are prepended.
         *                     The given value is cut to the range 1..20 (max digits of an
         *                     unsigned 64 bit integer).
         * @param sizeHint     The maximum number of digits found in the value. This is a hint
         *                     for optimizing the loop. If -1 is provided, the number is detected.
         *                     If a number is provided that is lower than the actual 'log10(value)',
         *                     the method produces unpredictable results.
         *
         * @return  The index of the new new end of the buffer.
         ******************************************************************************************/
        public int IntegerToString(ulong value, char[] buffer, int idx, int minDigits, int sizeHint)
        {
            // adjust minDigits to 1..20 and maxDigits to 1..minDigits
            if (minDigits < 1)
            {
                minDigits = 1;
            }
            if (minDigits > 20)
            {
                minDigits = 20;
            }
            if (sizeHint < minDigits)
            {
                sizeHint = minDigits;
            }
            if (sizeHint > 20)
            {
                sizeHint = 20;
            }

            int  actDigit     = sizeHint;
            bool printStarted = false;

            while (--actDigit >= 0)
            {
                // rest is zeros?
                if (value == 0)
                {
                    while (actDigit >= 0)
                    {
                        if (!(printStarted |= actDigit-- < minDigits))
                        {
                            continue;
                        }
                        buffer[idx++] = '0';
                    }
                    return(idx);
                }

                // get next d
                ulong actBase    = pow10_0to19[actDigit];
                int   digitValue = (int)(value / actBase);
                ALIB.ASSERT(digitValue <= 9);

                // did we hit i for the first time
                if (!(printStarted |= (digitValue != 0) || actDigit < minDigits))
                {
                    continue;
                }

                // print the digit
                buffer[idx++] = (char)(48 + digitValue); // 48= '0'

                // next
                value = value % actBase;
            }

            // return me for concatenated operations
            return(idx);
        }
        /** ****************************************************************************************
         * Writes hash tables stored in a ScopeStore. Keys are AStrings.
         * Value types currently supported are LogData and int (in C# different method).
         * @param store The store to use.
         * @return The total number of hash table entries written.
         ******************************************************************************************/
        public int writeStoreMap <T>(ScopeStore <Dictionary <AString, T> > store)
        {
            bool firstEntry = true;
            int  cnt        = 0;

            if (store.globalStore != null && store.globalStore.Count > 0)
            {
                cnt += store.globalStore.Count;
                if (firstEntry)
                {
                    firstEntry = false;
                }
                else
                {
                    target.NewLine();
                }
                target._NC("  Scope.Global:").NewLine();
                maxKeyLength = writeStoreMapHelper(store.globalStore, "    ");
            }

            foreach (KeyValuePair <Thread, List <Dictionary <AString, T> > > thread in store.threadOuterStore)
            {
                if (thread.Value.Count == 0)
                {
                    continue;
                }
                ALIB.ASSERT(thread.Value.Count == 1);
                if (firstEntry)
                {
                    firstEntry = false;
                }
                else
                {
                    target.NewLine();
                }
                target._NC("  Scope.ThreadOuter ");  storeThreadToScope(thread.Key)._(':').NewLine();
                cnt         += thread.Value[0].Count;
                maxKeyLength = writeStoreMapHelper(thread.Value[0], "    ");
            }

            foreach (PathMap <Dictionary <AString, T> > map in store.languageStore)
            {
                if (firstEntry)
                {
                    firstEntry = false;
                }
                else
                {
                    target.NewLine();
                }
                target._NC("  ");
                storeKeyToScope(map)._(':').NewLine();
                cnt         += map.Value.Count;
                maxKeyLength = writeStoreMapHelper(map.Value, "    ");
            }

            foreach (KeyValuePair <Thread, List <Dictionary <AString, T> > > thread in store.threadInnerStore)
            {
                if (thread.Value.Count == 0)
                {
                    continue;
                }
                ALIB.ASSERT(thread.Value.Count == 1);
                if (firstEntry)
                {
                    firstEntry = false;
                }
                else
                {
                    target.NewLine();
                }
                target._NC("  Scope.ThreadInner ");  storeThreadToScope(thread.Key)._(':').NewLine();
                cnt         += thread.Value[0].Count;
                maxKeyLength = writeStoreMapHelper(thread.Value[0], "    ");
            }

            return(cnt);
        }
        /** ****************************************************************************************
         *  Appends the given double value as string representation.
         *
         *  This method supports to write a variable or fixed number of digits for the integral
         *  and the fractional part of the provided value, or in <em>scientific notation</em>.
         *  In <em>scientific notation</em>, the value is multiplied with a power of 10 so that
         *  the integral part of the number falls into the range of 0 and 9. Then, the the negative
         *  value of the exponent of this multiplicand is appended, separated by the string defined in
         *  #DecimalExponentSeparator.
         *
         *  The output format is dependent on various settings provided in the fields of this class.
         *
         * @param value     The double value to append.
         * @param buffer    The character array to write the value into.
         *                  Depending on the value given and the format settings, a maximum of
         *                  32 characters need to be allocated prior to invoking this method.
         * @param idx       The index within the buffer to start writing to.
         *
         * @return   The index pointing behind the last character written.
         ******************************************************************************************/
        public int FloatToString(double value, char[] buffer, int idx)
        {
            // for debugging:
            // char* origBuffer= buffer;
            // for( int i= 0; i<24; i++ )
            //   origBuffer[i]= '\0';

            const int maxFloatSignificantDigits = 16;

            // negative? -> turn positive
            if (value < 0.0)
            {
                buffer[idx++] = '-';
                value         = -value;
            }

            // calc dot position
            int exp10 = value != 0.0   ? (int)Math.Floor((Math.Log10(value)))
                                        : 0;

            // decide if we are using scientific format (with e) or not
            bool scientific = (ForceScientificFormat ||
                               (MinIntegralDigits < 0 &&
                                FractionalDigits < 0 &&
                                (exp10 > 6 || exp10 <= -5)
                               ));

            int minIntegralDigits = Math.Min(MinIntegralDigits, 15);
            int fractionalDigits  = Math.Min(FractionalDigits, 15);



            // result variables used for output
            ulong intPart;
            ulong fractPart;
            int   unusedFractDigits;
            int   firstNonZero;
            int   intPartSize;

            // scientific output
            if (scientific)
            {
                int dotPos = maxFloatSignificantDigits - exp10;
                intPart     = (ulong)(value * Math.Pow(10, dotPos));
                fractPart   = intPart % pow10_0to19[maxFloatSignificantDigits];
                intPart     = intPart / pow10_0to19[maxFloatSignificantDigits];
                intPartSize = 1;

                // determine first non zero fract number
                firstNonZero = 0;
                if (fractPart > 0)
                {
                    ALIB.ASSERT(maxFloatSignificantDigits - firstNonZero < 20);
                    while (fractPart < pow10_0to19[maxFloatSignificantDigits - firstNonZero - 1])
                    {
                        firstNonZero++;
                    }
                    ALIB.ASSERT(maxFloatSignificantDigits - firstNonZero > 0);
                }
                firstNonZero++;

                unusedFractDigits = fractionalDigits >= 0 ?  maxFloatSignificantDigits - fractionalDigits
                                                     :  1;
            }

            // normal output, number > 0
            else if (exp10 >= 0)
            {
                intPartSize = maxFloatSignificantDigits - exp10;
                ALIB.ASSERT(intPartSize > 0 && intPartSize <= maxFloatSignificantDigits);

                intPart   = (ulong)(value * Math.Pow(10, intPartSize));
                fractPart = intPart % pow10_0to19[intPartSize];
                intPart   = intPart / pow10_0to19[intPartSize];

                // determine first non zero fract number
                firstNonZero = 0;
                if (fractPart > 0)
                {
                    ALIB.ASSERT(intPartSize - firstNonZero < 20);
                    while (fractPart < pow10_0to19[intPartSize - firstNonZero - 1])
                    {
                        firstNonZero++;
                    }
                    ALIB.ASSERT(intPartSize - firstNonZero > 0);
                }
                firstNonZero++;

                unusedFractDigits = fractionalDigits >= 0 ?  intPartSize - fractionalDigits
                                                     :  1;
            }

            // normal output, number  < 0
            else
            {
                // just zeros? -> write them and return
                firstNonZero      = -exp10;
                intPart           = 0;
                intPartSize       = 1;
                fractPart         = (ulong)(value * Math.Pow(10, maxFloatSignificantDigits + firstNonZero));
                unusedFractDigits = fractionalDigits >= 0 ?  maxFloatSignificantDigits - (fractionalDigits - firstNonZero)
                                                     :  1;
            }

            // cut fract digits and round it up
            if ((fractionalDigits < 0 || fractionalDigits >= firstNonZero - 1) &&
                unusedFractDigits > 0 &&
                unusedFractDigits <= 18)
            {
                ulong rest = fractPart % pow10_0to19[unusedFractDigits];
                fractPart = fractPart / pow10_0to19[unusedFractDigits];
                if (rest > pow10_0to19[unusedFractDigits] / 2)
                {
                    fractPart++;
                    int  overflowDigit = 0;
                    bool overflow      = false;
                    while (overflowDigit <= fractionalDigits &&
                           !(overflow |= fractPart == pow10_0to19[overflowDigit]) &&
                           fractPart > pow10_0to19[overflowDigit]
                           )
                    {
                        overflowDigit++;
                    }

                    if (overflow)
                    {
                        if (overflowDigit == fractionalDigits)
                        {
                            fractPart = 0;
                            intPart++;
                        }
                        else
                        {
                            ALIB.ASSERT(firstNonZero > 1);
                            firstNonZero--;
                        }
                    }
                }
            }

            // write int part
            if (intPart != 0L || minIntegralDigits != 0)
            {
                idx = IntegerToString(intPart, buffer, idx, minIntegralDigits, intPartSize);
            }

            // write dot
            buffer[idx++] = DecimalPointCharacter;


            // write fract part
            if (fractionalDigits != 0)
            {
                int fractZeros = firstNonZero - 1;
                if (fractionalDigits > 0 && fractZeros > fractionalDigits)
                {
                    fractZeros = fractionalDigits;
                }

                for (int i = 0; i < fractZeros; i++)
                {
                    buffer[idx++] = '0';
                }

                int  qtyDigits       = fractionalDigits - fractZeros;
                int  actDigit        = maxFloatSignificantDigits + 1;
                int  cntOmittedZeros = 0;
                int  cntDigits       = 0;
                bool printStarted    = false;
                while (fractPart > 0 &&
                       (qtyDigits < 0 || cntDigits < qtyDigits)
                       )
                {
                    actDigit--;

                    // get next d
                    uint digitValue = (uint)(fractPart / pow10_0to19[actDigit]);

                    ALIB.ASSERT(digitValue <= 9);

                    // don't write, yet?
                    if (!(printStarted |= (digitValue != 0)))
                    {
                        continue;
                    }
                    cntDigits++;

                    // write digtit unless its a '0'
                    if (digitValue == 0)
                    {
                        cntOmittedZeros++;
                    }
                    else
                    {
                        for (int i = 0; i < cntOmittedZeros; i++)
                        {
                            buffer[idx++] = '0';
                        }
                        cntOmittedZeros = 0;
                        buffer[idx++]   = (char)(48 + digitValue); // 48= '0'
                    }

                    // next
                    fractPart = fractPart % pow10_0to19[actDigit];
                }

                // assure that if -1 for fractDigits if given,at least 1 digit is printed
                if (fractionalDigits < 0)
                {
                    qtyDigits = 1;
                }

                // write omitted zeros
                if (cntDigits < qtyDigits)
                {
                    for (int i = 0; i < cntOmittedZeros; i++)
                    {
                        buffer[idx++] = '0';
                    }
                    cntDigits += cntOmittedZeros;

                    // write missing digits
                    for (int i = cntDigits; i < qtyDigits; i++)
                    {
                        buffer[idx++] = '0';
                    }
                }
            }

            // write eNN
            if (scientific)
            {
                for (int i = 0; i < DecimalExponentSeparator.Length; i++)
                {
                    buffer[idx++] = DecimalExponentSeparator[i];
                }

                if (exp10 < 0)
                {
                    buffer[idx++] = '-';
                }
                else if (WriteExponentPlusSign)
                {
                    buffer[idx++] = '+';
                }

                idx = IntegerToString((ulong)(exp10 >= 0 ? exp10 : -exp10), buffer, idx, 2, 3);
            }

            return(idx);
        }