using System;
using System.Text;
using System.Diagnostics;
using Xmlsq;

/*  
 * $Id: TestXmlsq.cs $
 * Last updated:
 *   $Date: 2021-07-17 09:13 $
 *   $Version: 1.0.0 $
 */
/* Some tests using the XMLSQ .NET interface.
 * 
 * Requires `xmlsq` to be installed on your system: available from <http://cryptosys.net/xmlsq/>
 * Add a reference to `diXmlsqNet.dll`
 * 
 * Test files, e.g. `bookstore.xml`, are in `xmlsq-testfiles.zip`. These must be in the CWD.
 * 
 * This is a Console Application written for target .NET Framework 4.0 and above 
 * Please report any bugs to <https://cryptosys.net/contact>
 */
/******************************* LICENSE ***********************************
 * Copyright (C) 2020-21 David Ireland, DI Management Services Pty Limited.
 * All rights reserved. <www.di-mgt.com.au> <www.cryptosys.net>
 * The code in this module is licensed under the terms of the MIT license.  
 * For a copy, see <http://opensource.org/licenses/MIT>
****************************************************************************
*/

namespace TestXmlsq
{
    class TestXmlsq
    {
        private const int MIN_VERSION = 10000;

        static string quote_str(string s)
        {
            return "'" + s + "'";
        }

        static void test_Bookstore()
        {
            int n;
            string s, query;
            string xmlfile;

            xmlfile = "bookstore.xml";
            Console.WriteLine("FILE: {0}", xmlfile);
            Console.WriteLine("Get the root element...");
            query = "/";
            s = Query.GetText(xmlfile, query);
            Console.WriteLine("Query: {0}", query);
            Console.WriteLine(s);

            Console.WriteLine("Get text of 2nd title element...");
            query = "(//title)[2]";
            s = Query.GetText(xmlfile, query);
            Console.WriteLine("Query: {0}", query);
            Console.WriteLine(s);

            Console.WriteLine("Get count of book elements...");
            query = "//book";
            n = Xmlsq.Query.Count(xmlfile, query);
            Console.WriteLine("COUNT: Query: {0}", query);
            Console.WriteLine(n);

            Console.WriteLine("Get text of first book element...");
            query = "//book";
            s = Query.GetText(xmlfile, query);
            Console.WriteLine("GETTEXT: Query: {0}", query);
            Console.WriteLine(s);

            Console.WriteLine("Full Xpath query...");
            query = "//book";
            s = Query.FullQuery(xmlfile, query);
            Console.WriteLine("FULLQUERY: Query: {0}", query);
            Console.WriteLine(s);

            Console.WriteLine("Get text of first title element...");
            query = "//title";
            s = Query.GetText(xmlfile, query);
            Console.WriteLine("Query: {0}", query);
            Console.WriteLine(s);

            Console.WriteLine("Full Xpath query...");
            query = "//title";
            Console.WriteLine("Query: {0}", query);
            s = Query.FullQuery(xmlfile, query);
            Console.WriteLine(s);

            Console.WriteLine("Full Xpath query with `raw` option...");
            query = "//title";
            Console.WriteLine("Query: {0}", query);
            s = Query.FullQuery(xmlfile, query, Query.Opts.Raw);
            Console.WriteLine(s);

            Console.WriteLine("Get text of 3rd title element (UTF-8-encoded)...");
            query = "(//title)[3]";
            Console.WriteLine("Query: {0}", query);
            s = Query.GetText(xmlfile, query);
            Console.WriteLine(s);

            Console.WriteLine("Get text of 3rd title element asciified...");
            query = "(//title)[3]";
            Console.WriteLine("Query: {0}", query);
            s = Query.GetText(xmlfile, query, Query.Opts.Asciify);
            Console.WriteLine(s);

            Console.WriteLine("Get text of 3rd title element converted to native .NET UTF-16 string...");
            query = "(//title)[3]";
            Console.WriteLine("Query: {0}", query);
            s = Query.GetText(xmlfile, query);
            // Convert a string containing UTF-8 to a native .NET UTF-16 string
            s = Encoding.UTF8.GetString(Encoding.Default.GetBytes(s));
            // Should now print OK in .NET
            Console.WriteLine(s);
        }

        static void test_UseCount()
        {
            int n;
            string s, query;
            string xmlfile;

            Console.WriteLine("\nUSE THE COUNT TO QUERY EACH MATCHING ELEMENT...");

            xmlfile = "bookstore.xml";
            Console.WriteLine("FILE: {0}", xmlfile);

            Console.WriteLine("Use the count to query each matching element in turn...");
            query = "//title";
            n = Xmlsq.Query.Count(xmlfile, query);
            Console.WriteLine("COUNT: Query: {0}", query);
            Console.WriteLine(n);

            for (int i = 1; i <= n; i++) {
                // Compose query
                query = string.Format("(//title)[{0}]", i);
                Console.WriteLine("Query: {0}", query);
                // then use it
                s = Query.GetText(xmlfile, query, Query.Opts.Asciify);
                Console.WriteLine(s);

            }
            

        }

        static void test_Errors()
        {
            int n;
            string s, query;
            string xmlfile;

            Console.WriteLine("\nEXPECTING ERRORS...");

            xmlfile = "bookstore.xml";
            query = "///badquery";
            Console.WriteLine("Query: {0}", query);
            try {
                s = Query.GetText(xmlfile, query);
            }
            catch (XmlsqErrorException e) {
                Console.WriteLine(e.Message);
            }

            xmlfile = "missing.xml";
            query = "//title";
            Console.WriteLine("FILE: {0}", xmlfile);
            Console.WriteLine("Query: {0}", query);
            try {
                s = Query.GetText(xmlfile, query);
            }
            catch (XmlsqErrorException e) {
                Console.WriteLine(e.Message);
            }
            xmlfile = "notxml.txt";
            query = "/a";
            Console.WriteLine("FILE: {0}", xmlfile);
            Console.WriteLine("Query: {0}", query);
            try {
                s = Query.GetText(xmlfile, query);
            }
            catch (XmlsqErrorException e) {
                Console.WriteLine(e.Message);
            }
            xmlfile = "missing.xml";
            query = "//title";
            Console.WriteLine("FILE: {0}", xmlfile);
            Console.WriteLine("Query: {0}", query);
            try {
                n = Query.Count(xmlfile, query);
            }
            catch (XmlsqErrorException e) {
                Console.WriteLine(e.Message);
            }

        }

        static void test_Empty()
        {
            int n;
            string s, query;

            Console.WriteLine("\nTESTING FOR EMPTY VALUES...");
            // Pass XML as a string
            string xml = @"<a><b foo=''></b><c>test1</c><e /></a>";
            Console.WriteLine("xml={0}", xml);

            Console.WriteLine("Get text of element b (empty, so add quote delimiters to see something)...");
            query = "a/b";
            s = Query.GetText(xml, query);
            Console.WriteLine("Query: {0}", query);
            Console.WriteLine(quote_str(s));

            Console.WriteLine("Similarly for empty element <e />...");
            query = "//e";
            s = Query.GetText(xml, query);
            Console.WriteLine("Query: {0}", query);
            Console.WriteLine(quote_str(s));

            Console.WriteLine("And for empty attribute foo=\"\"...");
            query = "//b/@foo";
            s = Query.GetText(xml, query);
            Console.WriteLine("Query: {0}", query);
            Console.WriteLine(quote_str(s));

            Console.WriteLine("But we get the same result if the element is missing...");
            query = "//notthere";
            s = Query.GetText(xml, query);
            Console.WriteLine("Query: {0}", query);
            Console.WriteLine(quote_str(s));

            Console.WriteLine("And if the attribute is not there...");
            query = "//b/@baz";
            s = Query.GetText(xml, query);
            Console.WriteLine("Query: {0}", query);
            Console.WriteLine(quote_str(s));

            Console.WriteLine("To differentiate: use the Query.Count method...");
            query = "//e";
            n = Query.Count(xml, query);
            Console.WriteLine("Query: {0}", query);
            Console.WriteLine("Count={0}", n);
            query = "//notthere";
            n = Query.Count(xml, query);
            Console.WriteLine("Query: {0}", query);
            Console.WriteLine("Count={0}", n);
            query = "//b/@foo";
            n = Query.Count(xml, query);
            Console.WriteLine("Query: {0}", query);
            Console.WriteLine("Count={0}", n);
            query = "//b/@baz";
            n = Query.Count(xml, query);
            Console.WriteLine("Query: {0}", query);
            Console.WriteLine("Count={0}", n);

        }

        static void test_Whitespace()
        {
            string s, query;

            Console.WriteLine("\nIGNORABLE WHITESPACE...");
            // Pass XML as a string
            string xml = @"<a foo = '   val   de  ri '>  hello   world </a>";
            Console.WriteLine("xml={0}", xml);

            query = "/a";
            s = Query.GetText(xml, query);
            Console.WriteLine("Query: {0}", query);
            Console.WriteLine(quote_str(s));
            Console.WriteLine("-- with Trim option (note whitespace in middle of element content is unchanged)");
            s = Query.GetText(xml, query, Query.Opts.Trim);
            Console.WriteLine(quote_str(s));

            query = "/a/@foo";
            s = Query.GetText(xml, query);
            Console.WriteLine("Query: {0}", query);
            Console.WriteLine(quote_str(s));
            Console.WriteLine("-- with Trim option (note whitespace inside attribute value is collapsed)");
            s = Query.GetText(xml, query, Query.Opts.Trim);
            Console.WriteLine(quote_str(s));
        }

        static void Main(string[] args)
        {

            // Make sure minimum required version of core DLL is installed...
            Console.WriteLine("Xmlsq core DLL Version={0:D5}", Xmlsq.Gen.Version());

            if (Gen.Version() < MIN_VERSION) {
                Console.WriteLine("FATAL ERROR: Require DLL version " + MIN_VERSION + " or later.");
                return;
            }

            Console.WriteLine("This .NET module Version={0}", Xmlsq.Gen.NetVersion());

            // Handle command-line arguments
            // [some]      just do some tests (default = do all)
            bool doSome = false;
            for (int iarg = 0; iarg < args.Length; iarg++) {
                if (args[iarg] == "some")
                    doSome = true;
            }

            //*************
            // DO THE TESTS
            //*************
            if (doSome) // Use "some" in the command line
			{   // Do some tests - comment these out as required
                //test_Bookstore();
                //test_Errors();
                //test_Empty();
                //test_UseCount();
                test_Whitespace();
            } 
            else 
            {   // Do all the test modules (default)
                test_Bookstore();
                test_Errors();
                test_Empty();
                test_UseCount();
                test_Whitespace();
            }

            // FINALLY, DISPLAY QUICK INFO ABOUT THE CORE DLL
            Console.WriteLine("\nDETAILS OF CORE DLL...");
            Console.WriteLine("DLL Version={0:D5} [{1}] Compiled=[{2}] ",
                Gen.Version(), Gen.Platform(), Gen.CompileTime());
            Console.WriteLine("[{0}]", Gen.ModuleName());
        }
    }
}