// Copyright (c) 2004-2016 Quadralay Corporation.  All rights reserved.
// 

using System;
using System.Collections;
using System.Text;

namespace WebWorks.Help
{
  /// <summary>
  /// Parses and splits a string into a list of arguments
  /// </summary>
  public sealed class CommandSplitter
  {
    #region Members
    ArrayList mArgsList = new ArrayList();
    #endregion

    #region Constructor
    public CommandSplitter(string args)
    {
      ProcessCommand(args);
    }
    #endregion

    #region Properties
    public string[] Args
    {
      get{return (string[])mArgsList.ToArray(typeof(string));}
    }

    public int Count
    {
      get{return mArgsList.Count;}
    }

    public string this[int index]
    {
      get{return mArgsList[index].ToString();}
    }
    #endregion

    #region ProcessCommand
    private bool ProcessCommand(string args)
    {
      bool hadError = false;                    
      bool inQuotes = false;

      mArgsList.Clear();
      
      StringBuilder currentArg = new StringBuilder();
      int index = 0;
            
      try
      {
        while (index < args.Length)
        {
          if(!inQuotes)
          {
            // skip whitespace if we are in quotes
            while((index < args.Length) && char.IsWhiteSpace(args[index]))
            {
              index += 1;
            }
          }
          
          // process one argument until we hit whitespace and are not in quotes
          while ((index < args.Length) && (!char.IsWhiteSpace(args[index]) || inQuotes))
          {
            if (args[index] == '\\')
            {
              int slashCount = 1;

              // go to the next character
              index += 1;

              // loop until we don't see a slash
              while (index < args.Length && args[index] == '\\')
              {
                index += 1;
                slashCount += 1;
              }
              
              // Add slashes, 1 slash for every 2
              currentArg.Append('\\', slashCount / 2);

              if(index < args.Length)
              {
                if (args[index] == '"')
                {
                  // if slashes are add then we are escaping a quote
                  if (0 != (slashCount & 1))
                  {
                    currentArg.Append('"');
                  }
                  else
                  {
                    inQuotes = !inQuotes;
                  }
                }
                else
                {
                  if (0 != (slashCount & 1))
                  {
                    currentArg.Append('\\');
                  }

                  currentArg.Append(args[index]);
                }
              }
            }
            else if (args[index] == '"')
            {
              inQuotes = !inQuotes;
            }
            else
            {
              // just append the text
              currentArg.Append(args[index]);
            }

            index += 1;
          } // while
          
          // Add argument to list
          mArgsList.Add(currentArg.ToString());
          currentArg.Length = 0;
        }
      }
      catch (System.IndexOutOfRangeException)
      {
        if (currentArg.Length > 0)
        {
          // valid argument can be terminated by EOF
          mArgsList.Add(currentArg.ToString());
        }
      }

      // if we ended and are still in quotes then there was a mismatch
      if (inQuotes)
      {
        hadError = true;
      }
            
      return hadError;
    }
    #endregion
  
    #region GetArgsRange
    public string GetArgsRange(int start, int end)
    {
      StringBuilder args = new StringBuilder();
      
      if(start < mArgsList.Count && end < mArgsList.Count)
      {
        for(int index = start; index <= end; index++)
        {
          if(index > start)
            args.Append(' ');

          if (mArgsList[index].ToString().Contains(" "))
          {
            args.Append('"');
            args.Append(mArgsList[index].ToString().Replace("\"", "\\\""));
            args.Append('"');
          }
          else
          {
            args.Append(mArgsList[index].ToString().Replace("\"", "\\\""));
          }
        }
      }
      return args.ToString();
    }
    #endregion
  }
}
