public static bool TryParseComponents(string uri, UriKind kind, out UriElements elements, out string error)
        {
            uri = uri.Trim();

            ParserState state = new ParserState(uri, kind);
            elements = state.elements;
            error = null;

            if (uri.Length == 0 && (kind == UriKind.Relative || kind == UriKind.RelativeOrAbsolute))
            {
                state.elements.isAbsoluteUri = false;
                return true;
            }

            if (uri.Length <= 1 && kind == UriKind.Absolute)
            {
                error = "Absolute URI is too short";
                return false;
            }

            bool ok = ParseFilePath(state) &&
                ParseScheme(state);

            var scheme = state.elements.scheme;
            UriParser parser = null;
            if (!StringUtilities.IsNullOrEmpty(scheme))
            {
                parser = UriParser.GetParser(scheme);
                if (parser != null && !(parser is DefaultUriParser))
                    return true;
            }

            ok = ok &&
                ParseAuthority(state) &&
                ParsePath(state) &&
                ParseQuery(state) &&
                ParseFragment(state);

            if (StringUtilities.IsNullOrEmpty(state.elements.host) &&
                (scheme == Uri.UriSchemeHttp || scheme == Uri.UriSchemeGopher || scheme == Uri.UriSchemeNntp ||
                scheme == Uri.UriSchemeHttps || scheme == Uri.UriSchemeFtp))
                state.error = "Invalid URI: The Authority/Host could not be parsed.";

            if (!StringUtilities.IsNullOrEmpty(state.elements.host) &&
                Uri.CheckHostName(state.elements.host) == UriHostNameType.Unknown)
                state.error = "Invalid URI: The hostname could not be parsed.";

            if (!StringUtilities.IsNullOrEmpty(state.error))
            {
                elements = null;
                error = state.error;
                return false;
            }

            return true;
        }
 public ParserState(string uri, UriKind kind)
 {
     remaining = uri;
     this.kind = kind;
     elements = new UriElements();
 }