//
// Locals
//
static ATOM noteScriptClassAtom;
static const char * const noteScriptWindowClass="SynfactorynoteScriptClass";

#define WL_PROJECT 0        // project this window belongs to
#define WL_PATCH 4          // patch this window belongs to
#define WL_OBJECT 8         // object this window belongs to
#define WL_EDITCONTROL 12    // window handle of edit child window
#define WL_CHANGEDFLAG 16   // Set when user has changed script
#define WL_BUTTONCANCEL 20  // window handle of cancel button
#define WL_BUTTONUPDATE 24  // window handle of update button
#define WL_BUTTONCLOSE 28   // window handle of close button
#define WL_LAST 32

#define BUTTON_CANCEL 1
#define BUTTON_UPDATE 2
#define BUTTON_CLOSE  3



//
// Create a notescript editor for specified object
//
HWND createNoteScriptEditorWindow(int project, int patch, int object, const char *WinTitle) {
  HWND newWindow=CreateWindowEx(
    WS_EX_TOOLWINDOW, noteScriptWindowClass,
    WinTitle, WS_OVERLAPPEDWINDOW | WS_SYSMENU | WS_CLIPCHILDREN,
    CW_USEDEFAULT, CW_USEDEFAULT,
    500,
    350,
    mainWindow, NULL, theInstance, NULL);
  UpdateWindow(newWindow);
  SetWindowLong(newWindow, WL_PROJECT, project);
  SetWindowLong(newWindow, WL_PATCH, patch);
  SetWindowLong(newWindow, WL_OBJECT, object);

  return newWindow;
}



//
// Copy changed script to DSP module
// Because background audio driver is using the script buffer, we try to aquire audio lock first
//
void copyScriptToModule(HWND hwnd) {
  int project=GetWindowLong(hwnd, WL_PROJECT);
  int patch=GetWindowLong(hwnd, WL_PATCH);
  int object=GetWindowLong(hwnd, WL_OBJECT);
  HWND editBox=(HWND)GetWindowLong(hwnd, WL_EDITCONTROL);

  if (projects[project].patches[patch].objects[object].objectType==OBJ_NOTESCRIPT) {
    // Aquire exclusive access to dynamic data-structures.
    lockMutex(theAudioMutex);

    // We have exclusive access to dynamic data-structures.

    if (projects[project].patches[patch].objects[object].dsp) {
      if (projects[project].dsp[projects[project].patches[patch].objects[object].dsp].scriptInfo->script) {
        // Free old script buffer
        free(projects[project].dsp[projects[project].patches[patch].objects[object].dsp].scriptInfo->script);
      }
    
      projects[project].dsp[projects[project].patches[patch].objects[object].dsp].scriptInfo->script=(char *)calloc(GetWindowTextLength(editBox)+1, sizeof(char));
      GetWindowText(editBox, projects[project].dsp[projects[project].patches[patch].objects[object].dsp].scriptInfo->script, GetWindowTextLength(editBox)+1);

      projects[project].dsp[projects[project].patches[patch].objects[object].dsp].io[0].intern=0;
      projects[project].dsp[projects[project].patches[patch].objects[object].dsp].io[1].intern=0;
      projects[project].dsp[projects[project].patches[patch].objects[object].dsp].io[2].intern=0;
      projects[project].dsp[projects[project].patches[patch].objects[object].dsp].io[3].intern=0;
    }

    unlockMutex(theAudioMutex);
  }
  if (projects[project].patches[patch].objects[object].objectType==OBJ_TEXT) {
    if (projects[project].patches[patch].objects[object].name) {
      free(projects[project].patches[patch].objects[object].name);
    }
    projects[project].patches[patch].objects[object].name=(char *)calloc(GetWindowTextLength(editBox)+1, sizeof(char));
    GetWindowText(editBox, projects[project].patches[patch].objects[object].name, GetWindowTextLength(editBox)+1);
    mainWindowRefresh=true;
  }
}



//
// Script editor window procedure
//
static LRESULT CALLBACK noteScriptEditorProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  switch(uMsg) {
  case WM_CREATE:
    SetWindowLong(hwnd, WL_EDITCONTROL, (LONG)CreateWindowEx(0, "EDIT", "", ES_MULTILINE | ES_AUTOVSCROLL | WS_CHILD | WS_VSCROLL | WS_VISIBLE, 0, 0, 0, 0, hwnd, (HMENU)1, theInstance, NULL));
    SetWindowLong(hwnd, WL_BUTTONCANCEL, (LONG)CreateWindowEx(0, "BUTTON", "Cancel", BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD, 0, 0, 0, 0, hwnd, (HMENU)BUTTON_CANCEL, theInstance, NULL));
    SetWindowLong(hwnd, WL_BUTTONUPDATE, (LONG)CreateWindowEx(0, "BUTTON", "Apply", BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD, 0, 0, 0, 0, hwnd, (HMENU)BUTTON_UPDATE, theInstance, NULL));
    SetWindowLong(hwnd, WL_BUTTONCLOSE, (LONG)CreateWindowEx(0, "BUTTON", "OK", BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD, 0, 0, 0, 0, hwnd, (HMENU)BUTTON_CLOSE, theInstance, NULL));
    EnableWindow((HWND)GetWindowLong(hwnd, WL_BUTTONUPDATE), FALSE);
    SendMessage((HWND)GetWindowLong(hwnd, WL_EDITCONTROL), WM_SETFONT, (WPARAM)GetStockObject(SYSTEM_FIXED_FONT), MAKELPARAM(TRUE, 0));
    break;
  case WM_COMMAND: {
      switch(HIWORD(wParam)) {
      case EN_CHANGE: // script is changed by user
        SetWindowLong(hwnd, WL_CHANGEDFLAG, 1);
        EnableWindow((HWND)GetWindowLong(hwnd, WL_BUTTONUPDATE), TRUE);
        break;
      case BN_CLICKED: // button pressed
        switch(LOWORD(wParam)) {
        case BUTTON_CANCEL:
          ShowWindow(hwnd, SW_HIDE);
          SetFocus(mainWindow);          
          break;
        case BUTTON_CLOSE:
          ShowWindow(hwnd, SW_HIDE);
          SetFocus(mainWindow);          
          if (GetWindowLong(hwnd, WL_CHANGEDFLAG)) {
            copyScriptToModule(hwnd);
          }
          break;
        case BUTTON_UPDATE:
          if (GetWindowLong(hwnd, WL_CHANGEDFLAG)) {
            copyScriptToModule(hwnd);
            SetWindowLong(hwnd, WL_CHANGEDFLAG, 0);
            EnableWindow((HWND)GetWindowLong(hwnd, WL_BUTTONUPDATE), FALSE);
            SetFocus((HWND)GetWindowLong(hwnd, WL_EDITCONTROL));
          }
          break;
        default:
          break;
        }
      }
    } break;
  case WM_SHOWWINDOW: {
      int project=GetWindowLong(hwnd, WL_PROJECT);
      int patch=GetWindowLong(hwnd, WL_PATCH);
      int object=GetWindowLong(hwnd, WL_OBJECT);
      if (((BOOL)wParam)==TRUE) {
        if (projects[project].patches[patch].objects[object].objectType==OBJ_NOTESCRIPT && projects[project].patches[patch].objects[object].dsp && projects[project].dsp[projects[project].patches[patch].objects[object].dsp].scriptInfo->script) {
          SendMessage((HWND)GetWindowLong(hwnd, WL_EDITCONTROL), WM_SETTEXT, 0, (LONG)(void *)projects[project].dsp[projects[project].patches[patch].objects[object].dsp].scriptInfo->script);
          SetWindowLong(hwnd, WL_CHANGEDFLAG, 0);
          SetFocus((HWND)GetWindowLong(hwnd, WL_EDITCONTROL));
        }
        if (projects[project].patches[patch].objects[object].objectType==OBJ_TEXT && projects[project].patches[patch].objects[object].name) {
          SendMessage((HWND)GetWindowLong(hwnd, WL_EDITCONTROL), WM_SETTEXT, 0, (LONG)(void *)projects[project].patches[patch].objects[object].name);
          SetWindowLong(hwnd, WL_CHANGEDFLAG, 0);
          SetFocus((HWND)GetWindowLong(hwnd, WL_EDITCONTROL));
        }
      }
    } break;
  case WM_SIZE: {
      RECT clientRect;
      GetClientRect(hwnd, &clientRect);
      SetWindowPos((HWND)GetWindowLong(hwnd, WL_EDITCONTROL), NULL, 0, 0, clientRect.right, clientRect.bottom - 26, SWP_NOZORDER);
      SetWindowPos((HWND)GetWindowLong(hwnd, WL_BUTTONCLOSE), NULL, clientRect.right - 3*80, clientRect.bottom - 24, 64, 24, SWP_NOZORDER);
      SetWindowPos((HWND)GetWindowLong(hwnd, WL_BUTTONCANCEL), NULL, clientRect.right - 2*80, clientRect.bottom - 24, 64, 24, SWP_NOZORDER);
      SetWindowPos((HWND)GetWindowLong(hwnd, WL_BUTTONUPDATE), NULL, clientRect.right - 80, clientRect.bottom - 24, 64, 24, SWP_NOZORDER);
    } break;
  case WM_CLOSE: {
      ShowWindow(hwnd, SW_HIDE);
      SetFocus(mainWindow);
      if (GetWindowLong(hwnd, WL_CHANGEDFLAG)) {
        copyScriptToModule(hwnd);
      }
    } break;
  default:
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
  }

  return 0;
}



//
// Initialise transport window
//
void InitNoteScriptEditor(void) {
  WNDCLASSEX myClass;

  // Create window class for transportWindow
  myClass.cbSize=(UINT)(sizeof(myClass));
  myClass.style=CS_DBLCLKS; /* Enable double click processing */
  myClass.lpfnWndProc=noteScriptEditorProc;
  myClass.cbClsExtra=0;
  myClass.cbWndExtra=WL_LAST;
  myClass.hInstance=theInstance;
  myClass.hIcon=LoadIcon(theInstance, MAKEINTRESOURCE(IDI_MAINICON));
  myClass.hCursor=LoadCursor(NULL, IDC_ARROW);
  myClass.hbrBackground=(HBRUSH)GetStockObject(LTGRAY_BRUSH);
  myClass.lpszMenuName=NULL;
  myClass.lpszClassName=noteScriptWindowClass;
  myClass.hIconSm=NULL;
  noteScriptClassAtom=RegisterClassEx(&myClass);

  logprintf("Activated noteScriptEditor\n");
}



//
// DeInitTransportWindow
//
void DeInitNoteScriptEditor(void) {
  UnregisterClass((LPCSTR)(noteScriptClassAtom), theInstance);
  DeleteAtom(noteScriptClassAtom);
  logprintf("Deactivated noteScriptEditor\n");
}
