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

using System.Runtime.InteropServices;
using System.Security.Principal;
using VbExceptionFilter.AccuDemo;

namespace AccuDemo
{
    class AccuDemo
    {
        static void Main(string[] args)
        {
            if (args.Length == 1)
            {
                switch (args[0])
                {
                    case "WrapOn":
                        WrapOn();
                        break;

                    case "WrapOff":
                        WrapOff();
                        break;

                    case "Win32":
                        Win32();
                        break;

                    case "Divide":
                        Divide();
                        break;

                    case "SEH":
                        SEH();
                        break;

                    case "2P":
                        TwoPassProblem();
                        break;

                    case "2P-BB":
                        TwoPassBeltAndBraces();
                        break;

                    case "2P-PF":
                        TwoPassPartialFix();
                        break;

                    case "2P-BF":
                        TwoPassBrokenFix();
                        break;

                    default:
                        Console.WriteLine("Unrecognised argument: " + args[0]);
                        break;
                }
            }
            else
            {
                Console.WriteLine("Usage: AccuDemo <arg>");
                Console.WriteLine("WrapOn - demonstrates wrapping non exception throws");
                Console.WriteLine("WrapOff - demonstrates an assembly opting to deal with unwrapped non exception throws");
                Console.WriteLine("Win32 - demonstrates Win32Exception accessing error code");
                Console.WriteLine("Divide - demonstrates runtime translating a SEH to a Framework exception");
                Console.WriteLine("SEH - demonstrates runtime wrapping an unrecognised exception");
                Console.WriteLine("2P - demonstrates problem with 2-Pass exception handling");
                Console.WriteLine("2P-BB - demonstrates belt & braces workaround for problem with 2-Pass exception handling");
                Console.WriteLine("2P-PF - demonstrates MS partial fix for impersonation");
                Console.WriteLine("2P-BF - demonstrates fragility of MS partial fix");
            }
        }

        private static void WrapOn()
        {
            // Call assembly with wrapping ON
            try
            {
                ManagedCpp.ThrowManagedInt(42);
            }
            catch (System.Runtime.CompilerServices.RuntimeWrappedException rwe)
            {
                Console.WriteLine("WrapOn: Runtime Wrapped Exception caught: " + rwe.Message);
            }
            catch (Exception e)
            {
                Console.WriteLine("WrapOn: Exception caught: " + e.Message);
            }
        }

        private static void WrapOff()
        {
            try
            {
                NonWrapping.CallCpp();
            }
            catch (System.Runtime.CompilerServices.RuntimeWrappedException rwe)
            {
                Console.WriteLine("WrapOff: Runtime Wrapped Exception caught: " + rwe.Message);
            }
            catch (Exception e)
            {
                Console.WriteLine("WrapOff: Exception caught: " + e.Message);
            }
        }

        private static void Win32()
        {
            try
            {
                LogonAdmin("NotMyPassword");
            }
            catch (System.ComponentModel.Win32Exception w32e)
            {
                Console.WriteLine("Win32Exception caught: " + w32e.Message);
            }
        }

        [DllImport("advapi32.dll", SetLastError = true)]
        static extern bool LogonUser(string user, string domain, string pwd, int type, int provider, out IntPtr token);

        private static void LogonAdmin(string password)
        {
            IntPtr userHandle = IntPtr.Zero;

            bool loggedOn = LogonUser("administrator", "", password, 2, 0, out userHandle);
            
            if (!loggedOn)
            {
                //No need to call: Marshal.GetLastWin32Error();

                throw new System.ComponentModel.Win32Exception();
            }
        }

        private static void Divide()
        {
            try
            {
                ManagedCpp.Divide(5, 0);
            }
            catch (DivideByZeroException dbe)
            {
                Console.WriteLine("DivideByZeroException caught: " + dbe.Message);
            }
        }

        private static void SEH()
        {
            try
            {
                ManagedCpp.ThrowUnmanagedInt(99);
            }
            catch (SEHException seh)
            {
                Console.WriteLine("SEHException caught: " + seh.Message);
            }
        }

        static void TwoPassProblem()
        {
            ExceptionFilter.ShowProblem();
        }
        
        static void TwoPassBeltAndBraces()
        {
            ExceptionFilter.ShowBeltAndBraces();
        }

        static void TwoPassPartialFix()
        {
            ExceptionFilter.ShowPartialFix();
        }

        static void TwoPassBrokenFix()
        {
            ExceptionFilter.ShowBrokenFix();
        }
    }
}
