/*
 * This file is part of the Poliqarp suite.
 * 
 * Copyright (C) 2009 by Instytut Podstaw Informatyki Polskiej
 * Akademii Nauk (IPI PAN; Institute of Computer Science, Polish
 * Academy of Sciences; cf. www.ipipan.waw.pl).  All rights reserved.
 * 
 * This file may be distributed and/or modified under the terms of the
 * GNU General Public License version 2 as published by the Free Software
 * Foundation and appearing in the file gpl.txt included in the packaging
 * of this file.  (See http://www.gnu.org/licenses/translations.html for
 * unofficial translations.)
 * 
 * A commercial license is available from IPI PAN (contact
 * Michal.Ciesiolka@ipipan.waw.pl or ipi@ipipan.waw.pl for more
 * information).  Licensees holding a valid commercial license from IPI
 * PAN may use this file in accordance with that license.
 * 
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE.
 */

/**
 * Poliqarp GUI launcher. Only for Win32.
 */

#include <poliqarp-config.h>

#include <assert.h>
#include <windows.h>

#include <foostring/foostring.h>

#define GETJAVA_URI "http:/""/java.sun.com/getjava"
#define JAVA_REGISTRY_HKEY HKEY_LOCAL_MACHINE
#define JAVA_REGISTRY_KEY_PATH "Software\\JavaSoft\\Java Runtime Environment"
#define JAR_FILE "poliqarp.jar"

static void fatal(unsigned long rc)
{
   unsigned long format_rc;
   char buffer[BUFSIZ];
   format_rc = FormatMessage(
      FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
      NULL, rc, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
      buffer, sizeof buffer, NULL);
   if (format_rc == 0)
      sprintf(buffer, "Unknown error");
   MessageBox(NULL, buffer, "Error", MB_OK | MB_ICONERROR);
   exit(EXIT_FAILURE);
}

static unsigned long open_uri(const char *uri)
{
   unsigned long rc;
   rc = (unsigned long)ShellExecute(NULL, "open", GETJAVA_URI, NULL, NULL,
      SW_SHOWNORMAL);
   if (rc <= 32) {
      switch (rc) {
         case ERROR_FILE_NOT_FOUND:
         case ERROR_PATH_NOT_FOUND:
         case ERROR_BAD_FORMAT:
            break;
         case SE_ERR_ACCESSDENIED:
            rc = ERROR_ACCESS_DENIED;
            break;
         case SE_ERR_ASSOCINCOMPLETE:
         case SE_ERR_NOASSOC:
            rc = ERROR_NO_ASSOCIATION;
            break;
         case SE_ERR_DDEBUSY:
         case SE_ERR_DDEFAIL:
         case SE_ERR_DDETIMEOUT:
            rc = ERROR_DDE_FAIL;
            break;
         case SE_ERR_OOM:
            rc = ERROR_NOT_ENOUGH_MEMORY;
            break;
         case SE_ERR_SHARE:
            rc = ERROR_SHARING_VIOLATION;
            break;
      }
   } else
      rc = 0;
   return rc;
}

static char *get_javaw_path()
{
   static const char *javaw_suffix = "\\bin\\javaw.exe";
   const char *java_home = getenv("JAVA_HOME");
   if (java_home != NULL) {
      string_t path;
      path = string_init(java_home);
      string_append_str(path, javaw_suffix);
      return string_free_and_get_buffer(path);
   }

   long rc;
   HKEY hkey;
   string_t string = string_init(JAVA_REGISTRY_KEY_PATH);
   rc = RegOpenKeyEx(JAVA_REGISTRY_HKEY, string_str(string), 0, KEY_READ,
      &hkey);
   if (rc != ERROR_SUCCESS)
      return NULL;

   char tiny_buffer[64];
   unsigned long size = sizeof tiny_buffer;
   rc = RegQueryValueEx(hkey, "CurrentVersion", 0, NULL,
      (unsigned char*)tiny_buffer, &size);
   if (rc != ERROR_SUCCESS)
      return NULL;
   string_append_char(string, '\\');
   string_append_buf(string, tiny_buffer, size);
   rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, string_str(string), 0, KEY_READ,
      &hkey);
   string_free(string);
   if (rc != ERROR_SUCCESS)
      return NULL;
   rc = RegQueryValueEx(hkey, "JavaHome", 0, NULL, NULL, &size);
   if (rc != ERROR_SUCCESS) {
      RegCloseKey(hkey);
      return NULL;
   }
   char *buffer = malloc(size + 16);
   if (buffer == NULL) {
      RegCloseKey(hkey);
      return NULL;
   }
   rc = RegQueryValueEx(hkey, "JavaHome", 0, NULL, (unsigned char*)buffer,
      &size);
   RegCloseKey(hkey);
   if (rc != ERROR_SUCCESS) {
      free(buffer);
      return NULL;
   }
   strcat(buffer, javaw_suffix);
   return buffer;
}

static void oom_callback(string_t s)
{
   fatal(ERROR_NOT_ENOUGH_MEMORY);
}

int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev_instance,
   char *tail_command_line, int show)
{
   string_oom_callback = oom_callback;
   char *java_path = get_javaw_path();
   if (java_path == NULL) {
      int rc = MessageBox(NULL,
         "Could not find a Java Runtime Environment installed on your computer.\n"
         "Without it you cannot run " PACKAGE_NAME ".\n\n"
         "Would you like to visit the Java website to download it?",
         "Missing JRE", MB_ICONEXCLAMATION | MB_YESNO);
      if (rc == IDYES) {
         rc = open_uri(GETJAVA_URI);
         if (rc != 0)
            fatal(rc);
      } else
         return EXIT_FAILURE;
   } else {
      STARTUPINFO startup_info;
      PROCESS_INFORMATION process_info;
      memset(&startup_info, 0, sizeof startup_info);
      startup_info.cb = sizeof startup_info;
      memset(&process_info, 0, sizeof process_info);
      {
         unsigned long thread_id = GetCurrentThreadId();
         string_t command_line = string_create();
         string_format(command_line, "poliqarpd.exe --gui --detach --notify %lu", thread_id);
         unsigned long rc = CreateProcess("poliqarpd.exe",
            string_str(command_line), NULL, NULL, 0, 0, NULL, NULL,
            &startup_info, &process_info);
         string_free(command_line);
         if (rc != 0) {
            MsgWaitForMultipleObjects(1, &process_info.hProcess, 0,
               INFINITE, QS_ALLPOSTMESSAGE);
            /* deliberately ignore errors */
            CloseHandle(process_info.hProcess);
         }
         else
            fatal(GetLastError());
      }
      string_t command_line = string_init("javaw.exe -jar " JAR_FILE " ");
      string_append_str(command_line, tail_command_line);
      unsigned long rc = CreateProcess(java_path, string_str(command_line),
         NULL, NULL, 0, 0, NULL, NULL, &startup_info, &process_info);
      free(java_path);
      string_free(command_line);
      if (rc == 0)
         fatal(GetLastError());
   }
   return EXIT_SUCCESS;
}
