using System;

namespace FHTE.LTOOLS.GUI
{
	/// <summary>
	/// StringTokenizer is the rewritten Java-Class StringTokenizer in C#.
	/// The comments are taken from the JavaDocumentation.
	/// </summary>
	class StringTokenizer
	{
        // ############################################################################################################
        // FIELDS
        // ############################################################################################################
        private int currentPosition;
        private int newPosition;
        private int maxPosition;
        private string str;
        private string delimiters;
        private bool retDelims;
        private bool delimsChanged;

        /// <summary>
        /// maxDelimChar stores the value of the delimiter character with the
        /// highest value. It is used to optimize the detection of delimiter
        /// characters.
        /// </summary>
        private char maxDelimChar;

        // ############################################################################################################
        // PROPERTIES
        // ############################################################################################################

        // ############################################################################################################
        // CONSTRUCTORS
        // ############################################################################################################
        /// <summary>
        /// Constructs a string tokenizer for the specified string. The 
        /// tokenizer uses the default delimiter set, which is 
        /// <code>"&nbsp;&#92;t&#92;n&#92;r&#92;f"</code>: the space character, 
        /// the tab character, the newline character, the carriage-return character,
        /// and the form-feed character. Delimiter characters themselves will 
        /// not be treated as tokens
        /// </summary>
        /// <param name="str">string to be parsed</param>
        public StringTokenizer(string str) : this(str, " \t\n\r\f", false)
        {
        }

        /// <summary>
        /// Constructs a string tokenizer for the specified string. The 
        /// characters in the <code>delim</code> argument are the delimiters 
        /// for separating tokens. Delimiter characters themselves will not 
        /// be treated as tokens.
        /// </summary>
        /// <param name="str">a string to be parsed</param>
        /// <param name="delim">the delimiters</param>
        public StringTokenizer(string str, string delim) : this (str, delim, false)
        {
        }

        /// <summary>
        /// Constructs a string tokenizer for the specified string. All
        /// characters in the <code>delim</code> argument are the delimiters
        /// for separating tokens.
        /// If the <code>returnDelims</code> flag is <code>true</code>, then
        /// the delimiter characters are also returned as tokens. Each
        /// delimiter is returned as a string of length one. If the flag is
        /// <code>false</code>, the delimiter characters are skipped and only
        /// serve as separators between tokens.
        /// </summary>
        /// <param name="str">a string to be parsed</param>
        /// <param name="delim">the delimiters</param>
        /// <param name="returnDelims">flag indicating whether to return the delimiters as tokens</param>
        public StringTokenizer(string str, string delim, bool returnDelims) 
        {
            currentPosition = 0;
            newPosition = -1;
            delimsChanged = false;
            this.str = str;
            maxPosition = str.Length ;
            delimiters = delim;
            retDelims = returnDelims;
            SetMaxDelimChar();
        }

        // ############################################################################################################
        // METHODS
        // ############################################################################################################
        /// <summary>
        /// Set maxDelimChar to the highest char in the delimiter set.
        /// </summary>
        private void SetMaxDelimChar() 
        {
            if (delimiters == null) 
            {
                maxDelimChar = (char) 0;
                return;
            }

            char m = (char) 0;
            for (int i = 0; i < delimiters.Length; i++) 
            {
                char[] c = delimiters.ToCharArray(i, 1) ;
                if (m < c[0])
                    m = c[0];
            }
            maxDelimChar = m;
        }

        /// <summary>
        /// Skips delimiters starting from the specified position. If retDelims
        /// is false, returns the index of the first non-delimiter character at or
        /// after startPos. If retDelims is true, startPos is returned.
        /// </summary>
        /// <param name="startPos"></param>
        /// <returns></returns>
        private int SkipDelimiters(int startPos) 
        {
            if (delimiters == null)
            {
                // throw new NullPointerException();
            }

            int position = startPos;
            while (!retDelims && position < maxPosition) 
            {
                char[] c = str.ToCharArray(position, 1) ;
                if ((c[0] > maxDelimChar) || (delimiters.IndexOf(c[0]) < 0))
                    break;
                position++;
            }
            return position;
        }

        /// <summary>
        /// Skips ahead from startPos and returns the index of the next delimiter
        /// character encountered, or maxPosition if no such delimiter is found.
        /// </summary>
        /// <param name="startPos"></param>
        /// <returns>position</returns>
        private int ScanToken(int startPos) 
        {
            int position = startPos;
            while (position < maxPosition) 
            {
                char[] c = str.ToCharArray(position, 1) ;
                if ((c[0] <= maxDelimChar) && (delimiters.IndexOf(c[0]) >= 0))
                    break;
                position++;
            }
            if (retDelims && (startPos == position)) 
            {
                char[] c = str.ToCharArray(position, 1) ;
                if ((c[0] <= maxDelimChar) && (delimiters.IndexOf(c[0]) >= 0))
                    position++;
            }
            return position;
        }

        /// <summary>
        /// Tests if there are more tokens available from this tokenizer's string.
        /// If this method returns <tt>true</tt>, then a subsequent call to
        /// <tt>NextToken</tt> with no argument will successfully return a token.
        /// </summary>
        /// <returns><code>true</code> if and only if there is at least one token
        /// in the string after the current position; <code>false</code> 
        /// otherwise</returns>
        public bool HasMoreTokens() 
        {
            /*
             * Temporary store this position and use it in the following
             * NextToken() method only if the delimiters have'nt been changed in
             * that NextToken() invocation.
             */
            newPosition = SkipDelimiters(currentPosition);
            return (newPosition < maxPosition);
        }

        /// <summary>
        /// Returns the next token from this string tokenizer.
        /// java-exception:
        /// @exception  NoSuchElementException  if there are no more tokens in this
        ///             tokenizer's string.
        /// </summary>
        /// <returns>the next token from this string tokenizer.</returns>
        public string NextToken() 
        {
            /* 
             * If next position already computed in HasMoreElements() and
             * delimiters have changed between the computation and this invocation,
             * then use the computed value.
             */

            currentPosition = (newPosition >= 0 && !delimsChanged) ?  
            newPosition : SkipDelimiters(currentPosition);

            /* Reset these anyway */
            delimsChanged = false;
            newPosition = -1;

            if (currentPosition >= maxPosition)
            {
                // throw new NoSuchElementException();
            }
            int start = currentPosition;
            currentPosition = ScanToken(currentPosition);
            return str.Substring(start, currentPosition - start);
        }

        /// <summary>
        /// Returns the next token in this string tokenizer's string. First, 
        /// the set of characters considered to be delimiters by this 
        /// <tt>StringTokenizer</tt> object is changed to be the characters in 
        /// the string <tt>delim</tt>. Then the next token in the string
        /// after the current position is returned. The current position is 
        /// advanced beyond the recognized token.  The new delimiter set 
        /// remains the default after this call. 
        /// java-exception:
        /// @exception  NoSuchElementException  if there are no more tokens in this 
        ///             tokenizer's string.
        /// </summary>
        /// <param name="delim">the new delimiters</param>
        /// <returns>the next token, after switching to the new delimiter set</returns>
        public string NextToken(String delim) 
        {
            delimiters = delim;

            /* delimiter string specified, so set the appropriate flag. */
            delimsChanged = true;

            SetMaxDelimChar();
            return NextToken();
        }


        /// <summary>
        /// Returns the same value as the <code>HasMoreTokens</code>
        /// method. It exists so that this class can implement the
        /// <code>Enumeration</code> interface. 
        ///          @see     java.util.Enumeration
        ///          @see     java.util.StringTokenizer#HasMoreTokens()
        /// </summary>
        /// <returns><code>true</code> if there are more tokens;
        /// <code>false</code> otherwise.</returns>
        public bool HasMoreElements() 
        {
            return HasMoreTokens();
        }

        /// <summary>
        /// Returns the same value as the <code>NextToken</code> method,
        /// except that its declared return value is <code>Object</code> rather than
        /// <code>String</code>. It exists so that this class can implement the
        /// <code>Enumeration</code> interface. 
        /// java-exception:
        ///          @exception  NoSuchElementException  if there are no more tokens in this
        ///                      tokenizer's string.
        ///          @see        java.util.Enumeration
        ///          @see        java.util.StringTokenizer#NextToken()
        /// 
        /// </summary>
        /// <returns>the next token in the string.</returns>
        public object NextElement() 
        {
            return NextToken();
        }

        /// <summary>
        /// Calculates the number of times that this tokenizer's 
        /// <code>NextToken</code> method can be called before it generates an 
        /// exception. The current position is not advanced.
        ///           @see     java.util.StringTokenizer#NextToken()
        /// </summary>
        /// <returns>the number of tokens remaining in the string using the current delimiter set.</returns>
        public int CountTokens() 
        {
            int count = 0;
            int currpos = currentPosition;
            while (currpos < maxPosition) 
            {
                currpos = SkipDelimiters(currpos);
                if (currpos >= maxPosition)
                    break;
                currpos = ScanToken(currpos);
                count++;
            }
            return count;
        }

		/// <summary>
		/// The main entry point for the application to test the StringTokenizer.
		/// </summary>
		[STAThread]
		static void Main(string[] args)
		{
			//
			// TODO: Add code to start application here
			//
            // string teststr = "dies ist ein Test" ;
            string teststr = "drwxr-xr-x    0    0      4096 Wed Mar 12 04:11:23 2003 joerg" ;
            StringTokenizer st = new StringTokenizer(teststr, " ") ;
            int i = 0;
            while (st.HasMoreTokens()) 
            {
                Console.WriteLine(i++ + ": " + st.NextToken());
            }
            Console.ReadLine() ;

		}
	}
}
