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

using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Web;
using Microsoft.Win32;
using SHDocVw;

using WebWorks.Help.Registry64;

namespace WebWorks.Help
{
  class RegistryHandler
  {
    #region Fields
    private bool m64bit;
    #endregion

    public RegistryHandler(bool param_64bit)
    {
      this.m64bit = param_64bit;
    }

    public bool is64bit
    {
      get { return this.m64bit; }
    }

    public string GetKeyValue(UIntPtr paramInHive,
                              string  paramKeyName,
                              string  paramPropertyName)
    {
      string result = null;

      try
      {
        if (this.m64bit)
        {
          result = Registry64.RegistryWOW6432.GetRegKeyValue64(
            paramInHive, paramKeyName, paramPropertyName
          );
        }
        else
        {
          result = Registry64.RegistryWOW6432.GetRegKeyValue32(
            paramInHive, paramKeyName, paramPropertyName
          );
        }
      }
      catch
      {
        // Ignore
        //
      }

      return result;
    }
  }

  class BrowserProxy
  {
    #region Fields

    private Uri  mBaseUri;
    private bool  mBrowserIsIE;
    private string  mOpenCommand;

    #endregion

    #region Constructors

    public BrowserProxy(Uri  baseUri)
    {
      // Default fields
      //
      this.mBaseUri = baseUri;
      this.mBrowserIsIE = false;
      this.mOpenCommand = String.Empty;

      // Locate default browser info
      //
      this.Initialize();
    }

    #endregion

    #region Private Methods

    private void  Initialize()
    {
      RegistryHandler registryHandler;
      string  className;
      string  queryValue;
      string  htmlHandlerKeyPath;
      string  htmlHandler;

      registryHandler = new RegistryHandler(true);
      className = "";
      htmlHandler = null;
      while ((registryHandler != null) && (htmlHandler == null))
      {
        // Vista search first
        //
        string vistaRegistryPathTemplate = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\{0}\\UserChoice";

        if (htmlHandler == null)
        {
          // Lookup handler for .htm files
          //
          className = ".htm";
          queryValue = "ProgId";
          htmlHandlerKeyPath = String.Format(vistaRegistryPathTemplate, className);
          htmlHandler = registryHandler.GetKeyValue(
            Registry64.RegHive.HKEY_CURRENT_USER, htmlHandlerKeyPath, queryValue
          );
        }
        if (htmlHandler == null)
        {
          // Lookup handler for .htm files
          //
          className = ".htm";
          queryValue = "Progid";
          htmlHandlerKeyPath = String.Format(vistaRegistryPathTemplate, className);
          htmlHandler = registryHandler.GetKeyValue(
            Registry64.RegHive.HKEY_CURRENT_USER, htmlHandlerKeyPath, queryValue
          );
        }
        if (htmlHandler == null)
        {
          // Lookup handler for .html files
          //
          className = ".html";
          queryValue = "ProgId";
          htmlHandlerKeyPath = String.Format(vistaRegistryPathTemplate, className);
          htmlHandler = registryHandler.GetKeyValue(
            Registry64.RegHive.HKEY_CURRENT_USER, htmlHandlerKeyPath, queryValue
          );
        }
        if (htmlHandler == null)
        {
          // Lookup handler for .html files
          //
          className = ".html";
          queryValue = "Progid";
          htmlHandlerKeyPath = String.Format(vistaRegistryPathTemplate, className);
          htmlHandler = registryHandler.GetKeyValue(
            Registry64.RegHive.HKEY_CURRENT_USER, htmlHandlerKeyPath, queryValue
          );
        }
        if (htmlHandler == null)
        {
          // Lookup handler for .xhtml files
          //
          className = ".xhtml";
          queryValue = "ProgId";
          htmlHandlerKeyPath = String.Format(vistaRegistryPathTemplate, className);
          htmlHandler = registryHandler.GetKeyValue(
            Registry64.RegHive.HKEY_CURRENT_USER, htmlHandlerKeyPath, queryValue
          );
        }
        if (htmlHandler == null)
        {
          // Lookup handler for .xhtml files
          //
          className = ".xhtml";
          queryValue = "Progid";
          htmlHandlerKeyPath = String.Format(vistaRegistryPathTemplate, className);
          htmlHandler = registryHandler.GetKeyValue(
            Registry64.RegHive.HKEY_CURRENT_USER, htmlHandlerKeyPath, queryValue
          );
        }

        // Pre-Vista search
        //
        if (htmlHandler == null)
        {
          // Lookup handler for .htm files
          //
          className = ".htm";
          queryValue = "";
          htmlHandlerKeyPath = className;
          htmlHandler = registryHandler.GetKeyValue(
            Registry64.RegHive.HKEY_CLASSES_ROOT, htmlHandlerKeyPath, queryValue
          );
        }
        if (htmlHandler == null)
        {
          // Lookup handler for .html files if .htm failed
          //
          className = ".html";
          queryValue = "";
          htmlHandlerKeyPath = className;
          htmlHandler = registryHandler.GetKeyValue(
            Registry64.RegHive.HKEY_CLASSES_ROOT, htmlHandlerKeyPath, queryValue
          );
        }
        if (htmlHandler == null)
        {
          // Lookup handler for .xhtml files if .html failed
          //
          className = ".xhtml";
          queryValue = "";
          htmlHandlerKeyPath = className;
          htmlHandler = registryHandler.GetKeyValue(
            Registry64.RegHive.HKEY_CLASSES_ROOT, htmlHandlerKeyPath, queryValue
          );
        }
        if (htmlHandler == null)
        {
          // Lookup handler for htmlfile if .xhtml failed
          //
          className = "htmlfile";
          queryValue = "";
          htmlHandlerKeyPath = className;
          htmlHandler = registryHandler.GetKeyValue(
            Registry64.RegHive.HKEY_CLASSES_ROOT, htmlHandlerKeyPath, queryValue
          );
        }

        // Fallback to 32-bit registry handler if no solution found
        //
        if (htmlHandler == null)
        {
          if (registryHandler.is64bit)
          {
            registryHandler = new RegistryHandler(false);
          }
          else
          {
            registryHandler = null;
          }
        }
      }

      // Continue if registry key located
      //
      if (htmlHandler != null)
      {
        string openCommandValue;
        string  applicationCommandPath;

        openCommandValue = null;

        // Access HTML handler's open command
        //
        if (openCommandValue == null)
        {
          applicationCommandPath = htmlHandler + "\\shell\\open\\command";
          openCommandValue = registryHandler.GetKeyValue(
            Registry64.RegHive.HKEY_CLASSES_ROOT, applicationCommandPath, String.Empty
          );
        }

        // Lookup with class name if HTML handler failed
        //
        if (openCommandValue == null)
        {
          applicationCommandPath = className + "\\shell\\open\\command";
          openCommandValue = registryHandler.GetKeyValue(
            Registry64.RegHive.HKEY_CLASSES_ROOT, applicationCommandPath, String.Empty
          );
        }

        if (openCommandValue != null)
        {
          CommandSplitter  commandSplitter;

          // Success!
          //
          this.mOpenCommand = openCommandValue;

          // Determine if IE is the default
          //
          // IE detection no longer needed, however, keep the boolean in case it is needed for other purposes
          //
          commandSplitter = new CommandSplitter(this.mOpenCommand);
          if (commandSplitter.Count > 0)
          {
            string  applicationPath;
            string  applicationFileName;

            applicationPath = commandSplitter[0];
            applicationFileName = Path.GetFileName(applicationPath);
            if (String.Compare(applicationFileName, "iexplore.exe", StringComparison.OrdinalIgnoreCase) == 0)
            {
               this.mBrowserIsIE = true;
            }
          }
        }
      }
    }

    private void  NavigateToLocation(WebBrowser  webBrowser,
                                     string      locationURL)
    {
      ThreadStart  job;
      Thread       thread;

      // Handle via background thread
      //
      job = delegate()
        {
          try
          {
            object  navigateFlags;
            object  navigateTargetFrame;
            object  navigatePostData;
            object  navigateHeaders;

            // Navigate to location
            //
            navigateFlags = null;
            navigateTargetFrame = null;
            navigatePostData = null;
            navigateHeaders = null;
            webBrowser.Navigate(locationURL, ref navigateFlags, ref navigateTargetFrame, ref navigatePostData, ref navigateHeaders);

            // Wait for load
            //
            while (webBrowser.Busy)
            {
              // Sleep a bit
              //
              Thread.Sleep(100);
            }

            // Bring window to foreground
            //
            if (webBrowser.HWND != 0)
            {
              if (User32.IsIconic((IntPtr)webBrowser.HWND))
              {
                User32.OpenIcon((IntPtr)webBrowser.HWND);
              }
              else
              {
                User32.SetForegroundWindow((IntPtr)webBrowser.HWND);
              }
            }
          }
          catch
          {
            // Ignore it
            //
          }
        };

      // Fire event
      //
      thread = new Thread(job);
      thread.Start();
    }

    private void  LaunchWithURL(string  locationURL)
    {
      try
      {
        string           launchURL;
        string           launchCommand;
        CommandSplitter  commandSplitter;
        string           command;
        string           escapedArguments;

        // Need to redirect through temporary file?
        //
        if (locationURL.StartsWith("file:"))
        {
          string  temporaryFilePath;
          Uri     temporaryFileUri;

          // Use temporary file URL
          //
          temporaryFilePath = System.IO.Path.GetTempFileName();
          System.IO.File.Delete(temporaryFilePath);
          temporaryFilePath += ".html";
          WWHelpAPI.WriteRedirectHTMLFile(temporaryFilePath, locationURL);
          temporaryFileUri = new Uri(temporaryFilePath);
          launchURL = temporaryFileUri.AbsoluteUri;
        }
        else
        {
          // Use original URL
          //
          launchURL = locationURL;
        }

        // Build launch command
        //
        if (this.mOpenCommand.Contains("%1"))
        {
          launchCommand = this.mOpenCommand.Replace("%1", launchURL);
        }
        else
        {
          launchCommand = this.mOpenCommand + " \"" + launchURL + "\"";
        }

        // Split out command from arguments
        //
        commandSplitter = new CommandSplitter(launchCommand);
        if (commandSplitter.Count > 0)
        {
          Process  process;

          command = commandSplitter[0];
          escapedArguments = commandSplitter.GetArgsRange(1, commandSplitter.Count - 1);

          // Configure process
          //
          process = new Process();
          process.StartInfo = new ProcessStartInfo();
          process.StartInfo.FileName = command;
          process.StartInfo.Arguments = escapedArguments;
          process.StartInfo.UseShellExecute = false;
          process.StartInfo.RedirectStandardOutput = false;
          process.StartInfo.RedirectStandardError = false;
          process.StartInfo.CreateNoWindow = true;
          process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;

          // Launch
          //
          process.Start();
        }
      }
      catch
      {
        // Ignore!
        //
      }
    }

    #endregion

    #region Public Methods

    public void  DisplayURL(string  locationURL)
    {
      if (this.mOpenCommand.Length > 0)
      {
        // Launch a new browser
        //
        this.LaunchWithURL(locationURL);
      }
    }

    #endregion
  }
}
