/* Mule for Win32 Install Program */
#include <windows.h>
#include <ddeml.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>

int win32_platform_id;
int codepage;

typedef struct slmessage
{
  int cp;
  unsigned char *message;
} slmessage;

/* US CP is 437,.... -1 must be last entry. It is default...*/

#define ENGLISH -1
#define NIHONGO 932

slmessage access_denied[] =
{
  {NIHONGO, "アクセスが拒否されました\n"
   "Administrator権限で実行してください。\n"},
  {ENGLISH, "Access denied.\n"
   "Run this program with administrator privilege."}
};
slmessage undetect_error[] =
{
  {NIHONGO, "システムの原因不明のエラー\n"},
  {ENGLISH, "Undetected system error.\n"},
};
slmessage usage[] =
{
  {ENGLISH, "Usage:install [/a] [/A home-dir] [HOME-DIRECTORY]\n"},
};
slmessage lt_check_error[] =
{
  {NIHONGO, "展開に失敗しています。\n"
   "INSTALL.Mule のWinZipの注意点を良く読みなさい。\n"},
  {ENGLISH, "Some files not extracted correctly from the archive.\n"
   "Read the description about WinZip in INSTALL.Mule.\n"},
};
slmessage lfn_check_error[] =
{
  {NIHONGO, "展開に失敗しています。\n"
   "Long File Nameの使えるtar & gzip を使って下さい。\n"},
  {ENGLISH, "Some files not extracted correctly from the archive.\n"
   "Use tar & gzip which can handle Long File Names properly.\n"},
};
slmessage pf_error[] =
{
  {NIHONGO, "このプログラムはWindows95/NTでのみ動作します。\n"},
  {ENGLISH, "This program can run only on Windows95 or NT.\n"},
};
slmessage nd_homedrive[] =
{
  {NIHONGO, "HOMEDRIVEが定義されていない。\n"},
  {ENGLISH, "HOMEDRIVE is not defined. \n"},
};
slmessage nd_homepath[] =
{
  {NIHONGO, "HOMEPATHが定義されていない。\n"},
  {ENGLISH, "HOMEPATH is not defined. \n"},
};
slmessage home_prompt[] =
{
  {NIHONGO, "ディフォルトのホームディレクトリを入力してください。\n"
   "何も設定しないとこの場所からMuleは.emacsを読みます。\n"},
  {ENGLISH, "Enter the default home directory. (system default)\n"
   "Mule read .emacs in this directory without any settings.\n"},
};

void slmessage_fprintf(lang, stream, slfmt, ...)
     int lang;
     FILE *stream;
     slmessage *slfmt;
{
  va_list va;

  va_start(va, slfmt);
  for (;!(slfmt->cp == lang || slfmt->cp == -1);slfmt++);
  vfprintf(stream, slfmt->message, va);
  va_end(va);
}

HDDEDATA CALLBACK DdeCallback (UINT uType, UINT uFmt, HCONV hconv,
			       HSZ hsz1, HSZ hsz2, HDDEDATA hdata,
			       DWORD dwData1, DWORD dwData2)
{
  return NULL;
}

#define DdeCommand(str) 	\
	DdeClientTransaction (str, strlen (str)+1, HConversation, (HSZ)NULL, \
		              CF_TEXT, XTYP_EXECUTE, 30000, NULL)

#define REG_ROOT "SOFTWARE\\GNU\\Mule\\Environment"
#define MULE_CLASS ""

void error_op(int errorflag)
{
  if (errorflag != ERROR_SUCCESS){
    switch(errorflag) {
    case ERROR_ACCESS_DENIED:
      slmessage_fprintf(codepage, stderr, access_denied);
      break;
    default:
      slmessage_fprintf(codepage, stderr, undetect_error);
      break;
    }
    exit(100);
  }
  return;
}

void error_usage(void)
{
  slmessage_fprintf(codepage, stderr, usage);
  exit(1);
}

HKEY create_key(HKEY hrootkey)
{
  HKEY hkey;
  DWORD result;
  int errorflag;

  errorflag = RegCreateKeyEx(hrootkey, REG_ROOT,
			     0, MULE_CLASS, REG_OPTION_NON_VOLATILE,
			     KEY_WRITE, NULL, &hkey, &result);

  error_op(errorflag);

  return hkey;
}

void check_files(unsigned char *mule_root)
{
  unsigned char buf[MAX_PATH];
  FILE *handle;
  int data, flag;

  sprintf(buf, "%slisp\\win32scrollbar.el", mule_root);
  flag = access(buf, 0);
  if (flag != 0) {
    slmessage_fprintf(codepage, stderr, lfn_check_error);
    exit(100);
  }
  sprintf(buf, "%slisp\\loaddefs.el", mule_root);
  handle = fopen(buf, "rb");
  while ((data = fgetc(handle)) != EOF) {
    if (data == '\n') break;
    if (data == '\r') {
      slmessage_fprintf(codepage, stderr, lt_check_error);
      exit(100);
    }
  }
  return;
}

void set_value(HKEY hkey, unsigned char *name, unsigned char *value)
{
  int errorflag;

  errorflag = RegSetValueEx (hkey, name, 0, REG_SZ,
			     value, lstrlen (value) + 1);
  error_op(errorflag);
}

void set_value_path(HKEY hkey, 
		    unsigned char *name,
		    unsigned char *dir_name,
		    unsigned char *subdir)
{
  unsigned char full_name[MAX_PATH];
  strcpy(full_name, dir_name);
  strcat(full_name, subdir);
  set_value(hkey, name, full_name);
}

void get_root(unsigned char *program, unsigned char *result)
{
  unsigned char dir_name[_MAX_DIR];
  unsigned char drive_name[_MAX_DRIVE];
  unsigned char file_name[_MAX_FNAME];
  unsigned char ext_name[_MAX_EXT];

  _splitpath(program, drive_name, dir_name, file_name, ext_name);

  sprintf(result, "%s%s", drive_name, dir_name);
}

void get_shell_name(unsigned char *result)
{
  unsigned char dir_name[_MAX_DIR];
  unsigned char drive_name[_MAX_DRIVE];
  unsigned char file_name[_MAX_FNAME];
  unsigned char ext_name[_MAX_EXT];
  unsigned char *shell_name;

  shell_name = getenv("COMSPEC");
  if (!shell_name) {
    if (win32_platform_id == 1)
      strcpy(result, "command");
    else
      strcpy(result, "cmd");
  } else {
    _splitpath(shell_name, drive_name, dir_name, file_name, ext_name);
    sprintf(result, "%s%s", file_name, ext_name);
  }
}

void call_dumpprog(unsigned char *main_root)
{
  unsigned char dumpprog[MAX_PATH];

  sprintf(dumpprog, "%sbin", main_root);
  chdir(dumpprog);

  if (win32_platform_id == 1)
    sprintf(dumpprog, "%sbin\\dumpw95.bat", main_root);
  else
    sprintf(dumpprog, "%sbin\\dump.bat", main_root);

  system(dumpprog);
}

int main (int argc, char **argv)
{
  unsigned char main_root[MAX_PATH];
  unsigned char this_prog[MAX_PATH];
  unsigned char home_dir[MAX_PATH];
  unsigned char shell_name[MAX_PATH];
  unsigned char *p;
  int personal_flag;
  int version;
  HKEY hkey;

  DWORD idDde;
  HCONV HConversation;
  HSZ program_manager;
  char additem[MAX_PATH*2 + 100];

  codepage = GetConsoleCP();

  version = GetVersion();
  if ( 0 == (version & 0x80000000) )
    win32_platform_id = 0;
  else if ((version & 0xC0000000) == 0xC0000000)
    win32_platform_id = 1;
  else {
    slmessage_fprintf(codepage, stderr, pf_error);
    exit(1);
  }

  GetModuleFileName(NULL, this_prog, MAX_PATH);
  get_root(this_prog, main_root);

  check_files(main_root);

  if (argc == 1) {
    slmessage_fprintf(codepage, stdout, home_prompt);
    fgets(home_dir, MAX_PATH, stdin);
    p = strchr(home_dir, '\n');
    if (p) *p = '\0';
    personal_flag = 0;
  }
  else if (argc == 2) {
    if (!strcmp(argv[1], "/a")) {
      p = getenv("HOMEDRIVE");
      if (!p) {
	slmessage_fprintf(codepage, stderr, nd_homedrive);
	exit(1);
      }
      strcpy(home_dir, p);
      p = getenv("HOMEPATH");
      if (!p) {
	slmessage_fprintf(codepage, stderr, nd_homepath);
	exit(1);
      }
      strcat(home_dir, p);
      personal_flag = 1;
    } else {
      strcpy(home_dir, argv[1]);
      personal_flag = 0;
    }
  }
  else if (argc == 3) {
    if (!strcmp(argv[1], "/A")){
      strncpy(home_dir, argv[2], MAX_PATH);
    }
    personal_flga = 1;
  }
  else
    error_usage();

  get_shell_name(shell_name);

  if (personal_flag) {
    hkey = create_key(HKEY_CURRENT_USER);
    set_value(hkey, "HOME", home_dir);
  } else {
    hkey = create_key(HKEY_LOCAL_MACHINE);
    set_value_path(hkey, "EMACSLOADPATH", main_root, "lisp");
    set_value_path(hkey, "EMACSDATA", main_root, "etc");
    set_value_path(hkey, "EMACSPATH", main_root, "bin");
    set_value_path(hkey, "EMACSLOCKDIR", main_root, "lock");
    set_value_path(hkey, "INFOPATH", main_root, "info");
    set_value_path(hkey, "EMACSDOC", main_root, "etc");
    set_value(hkey, "TERM", "CMD");
    set_value(hkey, "SHELL", shell_name);
    set_value(hkey, "HOME", home_dir);
  }
  RegCloseKey(hkey);

  if (!personal_flag)
    call_dumpprog(main_root);

  idDde = 0;
  DdeInitialize (&idDde, (PFNCALLBACK)DdeCallback, APPCMD_CLIENTONLY, 0);

  program_manager = DdeCreateStringHandle (idDde, "PROGMAN", CP_WINANSI);

  if (HConversation = DdeConnect (idDde, program_manager,
				  program_manager, NULL))
    {
      DdeCommand ("[CreateGroup (Mule for Win32)]");
      DdeCommand ("[ReplaceItem (Mule for Win32)]");
      sprintf (additem, "[AddItem (%s\\bin\\mulewin.exe,Mule for Win32,"
	       "%s\\bin\\mule.ico)]",
	       main_root, main_root);
      DdeCommand (additem);

      DdeDisconnect (HConversation);
    }

  DdeFreeStringHandle (idDde, program_manager);

  DdeUninitialize (idDde);

  return 0;
}
