/****************************************************************************
 *                pvedit.cpp
 *
 * This file contains editor support code.
 *
 * Author: Christopher J. Cason.
 *
 * from Persistence of Vision(tm) Ray Tracer version 3.6.
 * Copyright 1991-2003 Persistence of Vision Team
 * Copyright 2003-2004 Persistence of Vision Raytracer Pty. Ltd.
 *---------------------------------------------------------------------------
 * NOTICE: This source code file is provided so that users may experiment
 * with enhancements to POV-Ray and to port the software to platforms other
 * than those supported by the POV-Ray developers. There are strict rules
 * regarding how you are permitted to use this file. These rules are contained
 * in the distribution and derivative versions licenses which should have been
 * provided with this file.
 *
 * These licences may be found online, linked from the end-user license
 * agreement that is located at http://www.povray.org/povlegal.html
 *---------------------------------------------------------------------------
 * This program is based on the popular DKB raytracer version 2.12.
 * DKBTrace was originally written by David K. Buck.
 * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
 *****************************************************************************/

#define POVWIN_FILE
#define _WIN32_IE COMMONCTRL_VERSION
#define WIN32_LEAN_AND_MEAN

#include <math.h>
#include <setjmp.h>
#include <string.h>
#include <windows.h>
#include "frame.h"
#include "colour.h"
#include "povray.h"
#include "optout.h"
#include "userio.h"
#include "parse.h"
#pragma hdrstop

#include <sys\stat.h>
#include "pvengine.h"
#include "pvedit.h"

USING_POV_NAMESPACE

HINSTANCE               hLibPovEdit ;

extern FILE             *debugFile ;
extern HWND             main_window ;
extern bool             use_editors ;

#ifdef CUSTOM_KEYWORDS_IN_WINPOV_PATCH
  bool                  use_pov_keywords = true;
  char                  *additional_keywords = strdup( "#\n" );
#endif

static HWND (WINAPI *CreateTabWindow) (HWND ParentWindow, HWND StatusWindow, char *HomePath) ;
static DWORD (WINAPI *GetDLLVersion) (void) ;
static void (WINAPI *SetWindowPosition) (int x, int y, int w, int h) ;
static void (WINAPI *SetMessageWindow) (HWND MessageWindow) ;
static void (WINAPI *RestoreState) (int RestoreFiles) ;
static void (WINAPI *SaveState) (void) ;
static bool (WINAPI *SelectFile) (char *FileName) ;
static bool (WINAPI *BrowseFile) (bool CreateNewWindow) ;
static bool (WINAPI *LoadFile) (char *FileName) ;
static bool (WINAPI *CloseFile) (char *FileName) ;
static bool (WINAPI *SaveFile) (char *FileName) ;
static bool (WINAPI *ExternalLoadFile) (char *ParamString) ;
static DWORD (WINAPI *GetTab) (void) ;
static DWORD (WINAPI *GetFlags) (void) ;
static char *(WINAPI *GetFilename) (void) ;
static void (WINAPI *NextTab) (bool Forward) ;
static bool (WINAPI *CanClose) (bool AllFiles) ;
static bool (WINAPI *SaveModified) (char *FileName) ;
static void (WINAPI *ShowMessages) (bool on) ;
static void (WINAPI *DispatchMenuId) (DWORD id) ;
static void (WINAPI *SetVisible) (bool visible) ;
static HMENU (WINAPI *GetMenuHandle) (int which) ;
static void (WINAPI *SetNotifyBase) (HWND WindowHandle, int MessageBase) ;
static void (WINAPI *UpdateMenus) (HMENU MenuHandle) ;
static void (WINAPI *GetContextHelp) (void) ;
static void (WINAPI *SetTabFocus) (void) ;
static bool (WINAPI *ShowParseError) (char *FileName, char *Message, int Line, int Col) ;
static bool (WINAPI *PassOnMessage) (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, DWORD *rVal) ;
static void (WINAPI *SetKeywords) (LPCSTR Keywords) ;

void                    **FunctionPtrs [] =
                        {
                         (void **) &CreateTabWindow,
                         (void **) &SetWindowPosition,
                         (void **) &SetMessageWindow,
                         (void **) &RestoreState,
                         (void **) &SaveState,
                         (void **) &SelectFile,
                         (void **) &BrowseFile,
                         (void **) &LoadFile,
                         (void **) &CloseFile,
                         (void **) &SaveFile,
                         (void **) &ExternalLoadFile,
                         (void **) &GetTab,
                         (void **) &GetFlags,
                         (void **) &GetFilename,
                         (void **) &NextTab,
                         (void **) &CanClose,
                         (void **) &SaveModified,
                         (void **) &ShowMessages,
                         (void **) &DispatchMenuId,
                         (void **) &SetVisible,
                         (void **) &GetMenuHandle,
                         (void **) &SetNotifyBase,
                         (void **) &UpdateMenus,
                         (void **) &GetContextHelp,
                         (void **) &SetTabFocus,
                         (void **) &ShowParseError,
                         (void **) &PassOnMessage,
                         (void **) &SetKeywords
                        } ;

char                    *FunctionNames [] =
                        {
                         "CreateTabWindow",
                         "SetWindowPosition",
                         "SetMessageWindow",
                         "RestoreState",
                         "SaveState",
                         "SelectFile",
                         "BrowseFile",
                         "LoadFile",
                         "CloseFile",
                         "SaveFile",
                         "ExternalLoadFile",
                         "GetTab",
                         "GetFlags",
                         "GetFilename",
                         "NextTab",
                         "CanClose",
                         "SaveModified",
                         "ShowMessages",
                         "DispatchMenuId",
                         "SetVisible",
                         "GetMenuHandle",
                         "SetNotifyBase",
                         "UpdateMenus",
                         "GetContextHelp",
                         "SetTabFocus",
                         "ShowParseError",
                         "PassOnMessage",
                         "SetKeywords",
                         NULL
                        } ;

bool LoadEditorDLL (char *shortdllname, char *dllname)
{
  int                   DllVersion ;
  char                  str [256] ;
  char                  **s ;
  void                  ***f ;
  struct stat           statbuf ;

  if (!use_editors)
    return (false) ;
  if (debugFile)
  {
    fprintf (debugFile, "Editor DLL path is '%s' then '%s'\n", shortdllname, dllname) ;
    if (stat (shortdllname, &statbuf) != 0)
      fprintf (debugFile, "(We didn't find it [1])\n") ;
    if (stat (dllname, &statbuf) != 0)
      fprintf (debugFile, "(We didn't find it [2])\n") ;
  }
  if (shortdllname == NULL || (hLibPovEdit = LoadLibrary (shortdllname)) == NULL)
  {
    if ((hLibPovEdit = LoadLibraryEx (dllname, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == NULL)
    {
      if (debugFile)
        fprintf (debugFile, "Could not load Editor DLL, error code is %08lx\n", GetLastError ()) ;
      sprintf (str, "Editor DLL initialisation failed [LoadLibrary failed, code is %08lx]", GetLastError ()) ;
      PovMessageBox (str, "POV-Ray Editor error") ;
      PovMessageBox ("See the 'Internal Editor Reference' section in the help file", "Important!") ;
      return (false) ;
    }
  }
  GetDLLVersion = (DWORD (WINAPI *)(void)) GetProcAddress (hLibPovEdit, "GetDLLVersion") ;
  if (GetDLLVersion == NULL)
  {
    if (debugFile)
      fprintf (debugFile, "Could not resolve GetDLLVersion, error code is %08lx\n", GetLastError ()) ;
    PovMessageBox ("Editor DLL initialisation failed [could not resolve GetDLLVersion]", "POV-Ray Editor Error") ;
    PovMessageBox ("See the 'Built-In Editors' section in the help file", "Important!") ;
    return (false) ;
  }
  if ((DllVersion = GetDLLVersion ()) != EDITDLLVERSION)
  {
    sprintf (str, "ERROR : Wrong editor DLL version [expected %04x, got %04x].", EDITDLLVERSION, DllVersion) ;
    if (debugFile)
      fprintf (debugFile, "%s\n", str) ;
    MessageBox (NULL, str, "POV-Ray Editor Error", MB_ICONSTOP) ;
    PovMessageBox ("Editor switched off.\n\nSee the 'Built-In Editors' section in the help file", "Important!") ;
    return (false) ;
  }
  for (s = FunctionNames, f = FunctionPtrs ; *s ; s++, f++)
  {
    **f = (void *) GetProcAddress (hLibPovEdit, *s) ;
    if (**f == NULL)
    {
      if (debugFile)
        fprintf (debugFile, "Could not get address of '%s', error code is %08lx\n", *s, GetLastError ()) ;
      sprintf (str, "Editor DLL initialisation failed [could not resolve '%s']", *s) ;
      PovMessageBox (str, "Editor Error") ;
      PovMessageBox ("See the 'Built-In Editors' section in the help file", "Important!") ;
      return (false) ;
    }
  }
  return (true) ;
}

HWND InitialiseEditor (HWND ParentWindow, HWND StatusWindow, char *HomePath)
{
  char        *s ;
  HWND        hwnd ;

  if (!use_editors)
    return (NULL) ;
  POV_MEM_INIT () ;
  #ifdef CUSTOM_KEYWORDS_IN_WINPOV_PATCH
    s = POV_NAMESPACE::Get_Reserved_Words (use_pov_keywords , additional_keywords ) ;
  #else
    s = POV_NAMESPACE::Get_Reserved_Words ("#\n") ;
  #endif
  EditSetKeywords (s) ;
  POV_FREE (s) ;
  if ((hwnd = CreateTabWindow (ParentWindow, StatusWindow, HomePath)) == NULL)
  {
    PovMessageBox ("TabWindow error: see the 'Built-In Editors' section in the help file", "Important!") ;
    return (NULL) ;
  }
  return (hwnd) ;
}

void SetEditorPosition (int x, int y, int w, int h)
{
  if (!use_editors)
    return ;
  SetWindowPosition (x, y, w, h) ;
}

void EditSetMessageWindow (HWND MessageWindow)
{
  if (!use_editors)
    return ;
  SetMessageWindow (MessageWindow) ;
}

void EditRestoreState (int RestoreFiles)
{
  if (!use_editors)
    return ;
  RestoreState (RestoreFiles) ;
}

void EditSaveState (void)
{
  if (!use_editors)
    return ;
  SaveState () ;
}

bool EditSelectFile (char *FileName)
{
  if (!use_editors)
    return (false) ;
  return (SelectFile (FileName)) ;
}

bool EditBrowseFile (bool CreateNewWindow)
{
  if (!use_editors)
    return (false) ;
  return (BrowseFile (CreateNewWindow)) ;
}

// NULL means create a new, untitled, editor window.
bool EditOpenFile (char *FileName)
{
  if (!use_editors)
    return (false) ;
  return (LoadFile (FileName)) ;
}

// NULL means currently selected file
bool EditCloseFile (char *FileName)
{
  if (!use_editors)
    return (false) ;
  return (CloseFile (FileName)) ;
}

// NULL means currently selected file
bool EditSaveFile (char *FileName)
{
  if (!use_editors)
    return (false) ;
  return (SaveFile (FileName)) ;
}

bool EditExternalOpenFile (char *ParamString)
{
  if (!use_editors)
    return (false) ;
  return (ExternalLoadFile (ParamString)) ;
}

DWORD EditGetTab (void)
{
  if (!use_editors)
    return (0) ;
  return (GetTab ()) ;
}

DWORD EditGetFlags (void)
{
  if (!use_editors)
    return (EDIT_MSG_SELECTED) ;
  return (GetFlags ()) ;
}

char *EditGetFilename (void)
{
  if (!use_editors)
    return (NULL) ;
  return (GetFilename ()) ;
}

void EditNextTab (bool Forward)
{
  if (!use_editors)
    return ;
  NextTab (Forward) ;
}

bool EditCanClose (bool AllFiles)
{
  if (!use_editors)
    return (true) ;
  return (CanClose (AllFiles)) ;
}

bool EditSaveModified (char *FileName)
{
  if (!use_editors)
    return (true) ;
  return (SaveModified (FileName)) ;
}

void EditShowMessages (bool on)
{
  if (!use_editors)
    return ;
  ShowMessages (on) ;
}

void EditDispatchMenuId (DWORD id)
{
  if (!use_editors)
    return ;
  DispatchMenuId (id) ;
}

void EditUpdateMenus (HMENU MenuHandle)
{
  if (!use_editors)
    return ;
  UpdateMenus (MenuHandle) ;
}

void EditSetVisible (bool visible)
{
  if (!use_editors)
    return ;
  SetVisible (visible) ;
}

void EditSetFocus (void)
{
  if (!use_editors)
    return ;
  SetTabFocus () ;
}

HMENU EditGetMenu (int which)
{
  if (!use_editors)
    return (NULL) ;
  return (GetMenuHandle (which)) ;
}

void EditSetNotifyBase (HWND WindowHandle, int MessageBase)
{
  if (!use_editors)
    return ;
  SetNotifyBase (WindowHandle, MessageBase) ;
}

void EditContextHelp (void)
{
  if (!use_editors)
    return ;
  GetContextHelp () ;
}

bool EditShowParseError (char *FileName, char *Message, int Line, int Col)
{
  char        *s ;

  if (!use_editors)
    return (false) ;
  s = strstr (Message, "<----ERROR") ;
  if (s != NULL)
    Message = s + 10 ;
  while (*Message == ' ' || *Message == '\n')
    Message++ ;
  return (ShowParseError (FileName, Message, Line, Col)) ;
}

bool EditPassOnMessage (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, DWORD *rVal)
{
  if (!use_editors)
    return (false) ;
  return (PassOnMessage (hwnd, message, wParam, lParam, rVal)) ;
}

void EditUnload (void)
{
}

bool EditEnabled (void)
{
  return (use_editors) ;
}

void EditSetState (bool on)
{
  use_editors = on ;
}

void EditSetKeywords (LPCSTR Keywords)
{
  SetKeywords (Keywords) ;
}
