// http://akelpad.sourceforge.net/forum/viewtopic.php?p=22073#22073
// Version: 2016-02-06
// Author: KDJ
//
// *** List of AkelPad Scripts methods (Scripts-*.txt files) ***
//
// Usage:
//   Call("Scripts::Main", 1, "AkelPadMethodsView.js")
//
// Required to include: BrowseForFolder_function.js and InputBox_function.js
//
// Keyboard and mouse:
//   Tab - rigth <-> left panel
//   Ctrl(+Shift)+Tab - next/previous item in methods list
//   F1 - menu
//   F4 - maximize/restore window (also Alt+Enter)
//   right click on method name or on edit window - context menu
//   double click on method name = "OK"
//
// Remark:
//   The script should be saved in Unicode format.

var oSys     = AkelPad.SystemFunction();
var hInstDLL = AkelPad.GetInstanceDll();
var sClass   = "AkelPad::Scripts::" + WScript.ScriptName + "::" + hInstDLL;
var hDlg     = oSys.Call("User32::FindWindowExW", 0, 0, sClass, 0);

if (hDlg)
{
  SetForegroundWindow(hDlg);
  WScript.Quit();
}

if (! (AkelPad.Include("BrowseForFolder_function.js") && AkelPad.Include("InputBox_function.js")))
  WScript.Quit();

GetLangStrings();

var Scale =
{
  Init: function()
  {
    var hDC = oSys.Call("User32::GetDC", hMainWnd);
    this.ScaleX = oSys.Call("Gdi32::GetDeviceCaps", hDC, 88 /*LOGPIXELSX*/);
    this.ScaleY = oSys.Call("Gdi32::GetDeviceCaps", hDC, 90 /*LOGPIXELSY*/);
    oSys.Call("User32::ReleaseDC", hMainWnd, hDC);
    //Align to 16 pixel
    this.ScaleX += (16 - this.ScaleX % 16) % 16;
    this.ScaleY += (16 - this.ScaleY % 16) % 16;
  },
  X:  function(n) {return oSys.Call("Kernel32::MulDiv", n, this.ScaleX, 96);},
  Y:  function(n) {return oSys.Call("Kernel32::MulDiv", n, this.ScaleY, 96);},
  UX: function(n) {return oSys.Call("Kernel32::MulDiv", n, 96, this.ScaleX);},
  UY: function(n) {return oSys.Call("Kernel32::MulDiv", n, 96, this.ScaleY);}
}
Scale.Init();

var hMainWnd     = AkelPad.GetMainWnd();
var hWndParent   = hMainWnd;
var hGuiFont     = oSys.Call("Gdi32::GetStockObject", 17 /*DEFAULT_GUI_FONT*/);
var nDlgMinW     = Scale.X(640);
var nDlgMinH     = Scale.Y(300);
var oDlgPos      = {"X": 230, "Y": 200, "W": nDlgMinW, "H": nDlgMinH, "Max": 0};
var bSeparateWnd = false;
var nAPMSel      = 0;
var bAPMSort     = true;
var nAPMLang     = 0;
var bMatchCase   = false;
var bWordWrap    = false;
var sFindName    = "";
var sFindText    = "";
var sAltDir      = "";
var aAPM         = [];
var aAESel       = [{}, {}];
var aIsLang;
var sHeader;
var hSubClass;
var hFocus;
var bCloseDlg;

var nTextMax = 512;
var lpTextLV = AkelPad.MemAlloc(nTextMax * 2);
var lpLVITEM = AkelPad.MemAlloc(_X64 ? (72) : (60)); //sizeof(LVITEM)
AkelPad.MemCopy(lpLVITEM, 0x0001 /*LVIF_TEXT*/, 3 /*DT_DWORD*/);
AkelPad.MemCopy(_PtrAdd(lpLVITEM, _X64 ? 24 : 20), lpTextLV, 2 /*DT_QWORD*/);
AkelPad.MemCopy(_PtrAdd(lpLVITEM, _X64 ? 32 : 24), nTextMax, 3 /*DT_DWORD*/);

var aDlg      = [];
var IDHEADERS = 1000;
var IDNAMELV  = 1001;
var IDTEXT    = 1002;
var IDSORTB   = 1003;
var IDLANG1B  = 1004;
var IDLANG2B  = 1005;
var IDMENUB   = 1006;
var IDOKB     = 1007;
var IDCLOSEB  = 1008;

AkelPad.ScriptNoMutex();
AkelPad.WindowRegisterClass(sClass);

while (! bCloseDlg)
{
  bCloseDlg = true;

  ReadIni();
  GetArrayAPM(hMainWnd);
  if (! aAPM.length)
    break;

  aDlg[IDHEADERS]={T: sHeader,     C: "STATIC",        S: 0x50000001 /*WS_VISIBLE|WS_CHILD|SS_CENTER*/};
  aDlg[IDNAMELV ]={T: "",          C: "SysListView32", S: 0x5080800D /*WS_VISIBLE|WS_CHILD|WS_BORDER|LVS_NOSORTHEADER|LVS_SHOWSELALWAYS|LVS_SINGLESEL|LVS_REPORT*/};
  aDlg[IDTEXT   ]={T: "",          C: "AkelEditW",     S: 0x50B00804 /*WS_VISIBLE|WS_CHILD|WS_BORDER|WS_VSCROLL|WS_HSCROLL|ES_READONLY|ES_MULTILINE*/};
  aDlg[IDSORTB  ]={T: sTxtSort,    C: "BUTTON",        S: 0x50000003 /*WS_VISIBLE|WS_CHILD|BS_AUTOCHECKBOX*/};
  aDlg[IDLANG1B ]={T: sTxtEnglish, C: "BUTTON",        S: 0x50000009 /*WS_VISIBLE|WS_CHILD|BS_AUTORADIOBUTTON*/};
  aDlg[IDLANG2B ]={T: sTxtRussian, C: "BUTTON",        S: 0x50000009 /*WS_VISIBLE|WS_CHILD|BS_AUTORADIOBUTTON*/};
  aDlg[IDMENUB  ]={T: sTxtMenu,    C: "BUTTON",        S: 0x50000000 /*WS_VISIBLE|WS_CHILD*/};
  aDlg[IDOKB    ]={T: sTxtOK,      C: "BUTTON",        S: 0x50000001 /*WS_VISIBLE|WS_CHILD|BS_DEFPUSHBUTTON*/};
  aDlg[IDCLOSEB ]={T: sTxtClose,   C: "BUTTON",        S: 0x50000000 /*WS_VISIBLE|WS_CHILD*/};

  SetForegroundWindow(hMainWnd);

  oSys.Call("User32::CreateWindowExW",
    0,               //dwExStyle
    sClass,          //lpClassName
    sTxtDlgTitle,    //lpWindowName
    0x80CF0000,      //dwStyle=WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_SIZEBOX|WS_MINIMIZEBOX|WS_MAXIMIZEBOX
    oDlgPos.X,       //x
    oDlgPos.Y,       //y
    oDlgPos.W,       //nWidth
    oDlgPos.H,       //nHeight
    hWndParent,      //hWndParent
    0,               //ID
    hInstDLL,        //hInstance
    DialogCallback); //Script function callback. To use it class must be registered by WindowRegisterClass.

  oSys.Call("User32::ShowWindow", hDlg, oDlgPos.Max ? 3 /*SW_MAXIMIZE*/ : 1 /*SW_SHOWNORMAL*/);
  AkelPad.WindowGetMessage();
}

AkelPad.WindowUnregisterClass(sClass);
AkelPad.MemFree(lpTextLV);
AkelPad.MemFree(lpLVITEM);

SetForegroundWindow(hMainWnd);

function DialogCallback(hWnd, uMsg, wParam, lParam)
{
  if (uMsg == 1) //WM_CREATE
  {
    var i;

    hDlg = hWnd;

    for (i = IDHEADERS; i < aDlg.length; ++i)
    {
      aDlg[i].HWND = oSys.Call("User32::CreateWindowExW",
        0,         //dwExStyle
        aDlg[i].C, //lpClassName
        aDlg[i].T, //lpWindowName
        aDlg[i].S, //dwStyle
        0,0,0,0,   //x, y, nWidth, nHeight
        hDlg,      //hWndParent
        i,         //ID
        hInstDLL,  //hInstance
        0);        //lpParam
      SetWindowFont(aDlg[i].HWND, hGuiFont);
    }

    CheckButtons();
    SetOptionsAE();

    InsertColumnLV();
    FillLV(nAPMSel, GetInputName(), true);

    oSys.Call("User32::SetFocus", aDlg[IDTEXT].HWND);
    oSys.Call("User32::SetFocus", aDlg[IDNAMELV].HWND);

    PostMessage(hDlg, 0x8000 /*WM_APP*/, 0, 0);
  }

  else if (uMsg == 0x8000 /*WM_APP*/)
  {
    if (aAESel[nAPMLang][aAPM[nAPMSel][0]])
      SetSelAE(aAESel[nAPMLang][aAPM[nAPMSel][0]][0], aAESel[nAPMLang][aAPM[nAPMSel][0]][1]);
  }

  else if (uMsg == 7) //WM_SETFOCUS
    oSys.Call("User32::SetFocus", hFocus);

  else if (uMsg == 36) //WM_GETMINMAXINFO
  {
    AkelPad.MemCopy(_PtrAdd(lParam, 24), nDlgMinW, 3 /*DT_DWORD*/); //ptMinTrackSize_x
    AkelPad.MemCopy(_PtrAdd(lParam, 28), nDlgMinH, 3 /*DT_DWORD*/); //ptMinTrackSize_y
  }

  else if (uMsg == 3) //WM_MOVE
  {
    if (! (oSys.Call("User32::IsZoomed", hDlg) || oSys.Call("User32::IsIconic", hDlg)))
      GetWindowPos(hDlg, oDlgPos);
  }

  else if (uMsg == 5) //WM_SIZE
  {
    if (wParam == 0 /*SIZE_RESTORED*/)
      GetWindowPos(hDlg, oDlgPos);

    ResizeDlg(LoWord(lParam), HiWord(lParam));
  }

  else if (uMsg == 15) //WM_PAINT
    PaintSizeGrip();

  else if (uMsg == 256) //WM_KEYDOWN
  {
    if (wParam == 9 /*VK_TAB*/)
    {
      if (Ctrl())
      {
        if (Shift())
        {
          if (nAPMSel > 0)
            --nAPMSel;
          else
            nAPMSel = aAPM.length - 1;
        }
        else
        {
          if (nAPMSel < aAPM.length - 1)
            ++nAPMSel;
          else
            nAPMSel = 0;
        }
        SetCurSelLV(nAPMSel);
        oSys.Call("User32::SetFocus", hFocus);
      }
      else
      {
        if (hFocus == aDlg[IDNAMELV].HWND)
          oSys.Call("User32::SetFocus", aDlg[IDTEXT].HWND);
        else
          oSys.Call("User32::SetFocus", aDlg[IDNAMELV].HWND);
      }
    }
    else if (wParam == 0x43 /*C key*/)
    {
      if  (Ctrl() && (! Alt()))
      {
        if (hFocus == aDlg[IDNAMELV].HWND)
        {
          if (Shift())
            InsertNameToAP();
          else
            CopytNameToCB();
        }
        else
          InsertTextTo(! Shift());
      }
    }
    else if (wParam == 0x46 /*F key*/)
    {
      if (Ctrl() && (! Alt()))
      {
        if (hFocus == aDlg[IDNAMELV].HWND)
          FindName(Shift() ? 2 : 0);
        else
          FindText(Shift() ? 2 : 0);
      }
    }
    else if (wParam == 0x55 /*U key*/)
    {
      if (Ctrl() && (! Shift()) && (! Alt()))
      {
        bWordWrap = ! bWordWrap;
        SetWordWrapAE();
      }
    }
    else if (wParam == 0x70 /*VK_F1*/)
    {
      if ((! Ctrl()) && (! Shift()))
        MenuMain();
    }
    else if (wParam == 0x72 /*VK_F3*/)
    {
      if (! Ctrl())
      {
        if (hFocus == aDlg[IDNAMELV].HWND)
          FindNameNext(Shift() ? 3 : 1);
        else
          FindTextNext(Shift() ? 3 : 1);
      }
    }
    else if (wParam == 0x73 /*VK_F4*/)
    {
      if ((! Ctrl()) && (! Shift()))
        oSys.Call("User32::ShowWindow", hDlg, oSys.Call("User32::IsZoomed", hDlg) ? 9 /*SW_RESTORE*/ : 3 /*SW_MAXIMIZE*/);
    }
    else if (wParam == 13 /*VK_RETURN*/)
    {
      if ((! Ctrl()) && (! Shift()) && (oSys.Call("User32::GetDlgCtrlID", oSys.Call("User32::GetFocus")) < IDMENUB))
        PostMessage(hDlg, 273 /*WM_COMMAND*/, IDOKB, 0);
    }
    else if (wParam == 27 /*VK_ESCAPE*/)
      PostMessage(hDlg, 16 /*WM_CLOSE*/, 0, 0);
  }

  else if (uMsg == 260) //WM_SYSKEYDOWN
  {
    if (wParam == 0x46 /*F key*/)
    {
      if (hFocus == aDlg[IDNAMELV].HWND)
        FindName(Shift() ? 3 : 1);
      else
        FindText(Shift() ? 3 : 1);
    }
    else if (wParam == 13 /*VK_RETURN*/)
    {
      if (! Shift())
        oSys.Call("User32::ShowWindow", hDlg, oSys.Call("User32::IsZoomed", hDlg) ? 9 /*SW_RESTORE*/ : 3 /*SW_MAXIMIZE*/);
    }
  }

  else if ((uMsg == 0x004E /*WM_NOTIFY*/) && (wParam == IDNAMELV))
  {
    switch (AkelPad.MemRead(_PtrAdd(lParam, _X64 ? 16 : 8), 3 /*DT_DWORD*/))
    {
      case -101 : //LVN_ITEMCHANGED
        if (AkelPad.MemRead(_PtrAdd(lParam, _X64 ? 32 : 20) /*NMLISTVIEW.uNewState*/, 3 /*DT_DWORD*/) & 0x2 /*LVIS_SELECTED*/)
        {
          nAPMSel = GetCurSelLV();
          SetWindowText(aDlg[IDTEXT].HWND, aAPM[nAPMSel][1]);

          if (aAESel[nAPMLang][aAPM[nAPMSel][0]])
            SetSelAE(aAESel[nAPMLang][aAPM[nAPMSel][0]][0], aAESel[nAPMLang][aAPM[nAPMSel][0]][1]);
        }
        break;
      case -3 : //NM_DBLCLK
        if (AkelPad.MemRead(_PtrAdd(lParam, _X64 ? 24 : 12) /*NMITEMACTIVATE.iItem*/, 3 /*DT_DWORD*/) == -1)
          SetCurSelLV(GetCurFocLV());
        else
          PostMessage(hDlg, 273 /*WM_COMMAND*/, IDOKB, 0);
        break;
      case -2 : //NM_CLICK
      case -5 : //NM_RCLICK
      case -6 : //NM_RDBLCLK
        if (AkelPad.MemRead(_PtrAdd(lParam, _X64 ? 24 : 12) /*NMITEMACTIVATE.iItem*/, 3 /*DT_DWORD*/) == -1)
          SetCurSelLV(GetCurFocLV());
        break;
      case -7 : //NM_SETFOCUS
        hFocus = aDlg[IDNAMELV].HWND;
        break;
    }
  }

  else if (uMsg == 123) //WM_CONTEXTMENU
  {
    if (wParam == aDlg[IDNAMELV].HWND)
      MenuName(LoWord(lParam), HiWord(lParam));
    else if (wParam == aDlg[IDTEXT].HWND)
    {
      oSys.Call("User32::SetFocus", aDlg[IDTEXT].HWND);
      MenuText(LoWord(lParam), HiWord(lParam));
    }
  }

  else if (uMsg == 273) //WM_COMMAND
  {
    var nLowParam = LoWord(wParam);
    var nHiwParam = HiWord(wParam);
    var sFind;

    if (nLowParam == IDTEXT)
    {
      if (nHiwParam == 0x0100 /*EN_SETFOCUS*/)
      {
        if (SendMessage(AkelPad.GetEditWnd(), 3227 /*AEM_GETOPTIONS*/, 0, 0) & 0x00000800 /*AECO_ACTIVELINE*/)
          SendMessage(lParam, 3228 /*AEM_SETOPTIONS*/, 2 /*AECOOP_OR*/, 0x00000800 /*AECO_ACTIVELINE*/);
        hFocus = lParam;
      }
      if (nHiwParam == 0x0200 /*EN_KILLFOCUS*/)
      {
        SendMessage(lParam, 3228 /*AEM_SETOPTIONS*/, 4 /*AECOOP_XOR*/, 0x00000800 /*AECO_ACTIVELINE*/);
        aAESel[nAPMLang][aAPM[nAPMSel][0]] = [GetSelStartAE(), GetSelEndAE()];
      }
    }
    else if ((nLowParam >= IDSORTB) && (nLowParam <= IDLANG2B))
    {
      sFind = aAPM[nAPMSel][0];
      CheckButtons(nLowParam);
      GetArrayAPM(hDlg);

      if (aAPM.length)
      {
        CheckButtons();
        SetWindowText(aDlg[IDHEADERS].HWND, sHeader);
        FillLV(nAPMSel, sFind, false);
        oSys.Call("User32::SetFocus", hFocus);
      }
      else
        PostMessage(hDlg, 16 /*WM_CLOSE*/, 0, 0);
    }
    else if (nLowParam == IDMENUB)
    {
      oSys.Call("User32::DefDlgProcW", hDlg, 1025 /*DM_SETDEFID*/, IDMENUB, 0);
      oSys.Call("User32::DefDlgProcW", hDlg, 1025 /*DM_SETDEFID*/, IDOKB, 0);
      oSys.Call("User32::SetFocus", hFocus);
      MenuMain();
    }
    else if (nLowParam == IDOKB)
      PostMessage(hDlg, 16 /*WM_CLOSE*/, 1, 0);
    else if (nLowParam == IDCLOSEB)
      PostMessage(hDlg, 16 /*WM_CLOSE*/, 0, 0);
  }

  else if (uMsg == 16) //WM_CLOSE
  {
    if (wParam)
      InsertNameToAP();

    aAESel[nAPMLang][aAPM[nAPMSel][0]] = [GetSelStartAE(), GetSelEndAE()];
    WriteIni();
    AkelPad.WindowUnsubClass(aDlg[IDTEXT].HWND);
    oSys.Call("User32::DestroyWindow", hDlg);
  }

  else if (uMsg == 2) //WM_DESTROY
    oSys.Call("User32::PostQuitMessage", 0);

  return 0;
}

function EditCallback(hWnd, uMsg, wParam, lParam)
{
  var lpPOINT;
  var lpAECHARRANGE;
  var nOffset1;
  var nOffset2;
  var sLink;

  if (uMsg == 515 /*WM_LBUTTONDBLCLK*/)
  {
    lpPOINT       = AkelPad.MemAlloc(8 /*sizeof(POINT)*/);
    lpAECHARRANGE = AkelPad.MemAlloc(_X64 ? 48 : 24 /*sizeof(AECHARRANGE)*/);

    AkelPad.MemCopy(_PtrAdd(lpPOINT, 0), LoWord(lParam), 3 /*DT_DWORD*/);
    AkelPad.MemCopy(_PtrAdd(lpPOINT, 4), HiWord(lParam), 3 /*DT_DWORD*/);

    if (AkelPad.SendMessage(hWnd, 3196 /*AEM_POINTONURL*/, lpPOINT, lpAECHARRANGE))
    {
      nOffset1 = AkelPad.SendMessage(hWnd, 3136 /*AEM_INDEXTORICHOFFSET*/, 0, lpAECHARRANGE);
      nOffset2 = AkelPad.SendMessage(hWnd, 3136 /*AEM_INDEXTORICHOFFSET*/, 0, _PtrAdd(lpAECHARRANGE, _X64 ? 24 : 12));

      AkelPad.SetEditWnd(hWnd);
      sLink = AkelPad.GetTextRange(nOffset1, nOffset2);
      AkelPad.SetEditWnd(0);

      oSys.Call("Shell32::ShellExecuteW", 0, "open", sLink, 0, 0, 1 /*SW_SHOWNORMAL*/);
      AkelPad.WindowNoNextProc(hSubClass);
    }

    AkelPad.MemFree(lpPOINT);
    AkelPad.MemFree(lpAECHARRANGE);
  }

  return 0;
}

function SendMessage(hWnd, uMsg, wParam, lParam)
{
  return oSys.Call("User32::SendMessageW", hWnd, uMsg, wParam, lParam);
}

function PostMessage(hWnd, uMsg, wParam, lParam)
{
  return oSys.Call("User32::PostMessageW", hWnd, uMsg, wParam, lParam);
}

function LoWord(nDwNum)
{
  return nDwNum & 0xFFFF;
}

function HiWord(nDwNum)
{
  return (nDwNum >> 16) & 0xFFFF;
}

function MkLong(nLoWord, nHiWord)
{
  return (nLoWord & 0xFFFF) | (nHiWord << 16);
}

function Ctrl()
{
  return oSys.Call("User32::GetKeyState", 0x11 /*VK_CONTROL*/) & 0x8000;
}

function Shift()
{
  return oSys.Call("User32::GetKeyState", 0x10 /*VK_SHIFT*/) & 0x8000;
}

function Alt()
{
  return oSys.Call("user32::GetKeyState", 0x12 /*VK_MENU*/) & 0x8000;
}

function GetInputName()
{
  var hEditWnd = AkelPad.GetEditWnd();
  var lpIndex1 = AkelPad.MemAlloc(_X64 ? 24 : 12 /*sizeof(AECHARINDEX)*/);
  var lpIndex2 = AkelPad.MemAlloc(_X64 ? 24 : 12 /*sizeof(AECHARINDEX)*/);
  var nOffset1;
  var nOffset2;

  SendMessage(hEditWnd, 3130 /*AEM_GETINDEX*/, 3 /*AEGI_FIRSTSELCHAR*/, lpIndex1);
  SendMessage(hEditWnd, 3130 /*AEM_GETINDEX*/, 4 /*AEGI_LASTSELCHAR*/, lpIndex2);

  if (SendMessage(hEditWnd, 3133 /*AEM_INDEXCOMPARE*/, lpIndex1, lpIndex2) == 0)
  {
    if (! SendMessage(hEditWnd, 3146 /*AEM_ISDELIMITER*/, 0x11 /*AEDLM_WORD|AEDLM_PREVCHAR*/, lpIndex1))
      SendMessage(hEditWnd, 3145 /*AEM_GETPREVBREAK*/, 0x1 /*AEWB_LEFTWORDSTART*/, lpIndex1);

    if (! SendMessage(hEditWnd, 3146 /*AEM_ISDELIMITER*/, 0x10 /*AEDLM_WORD*/, lpIndex2))
      SendMessage(hEditWnd, 3144 /*AEM_GETNEXTBREAK*/, 0x8 /*AEWB_RIGHTWORDEND*/, lpIndex2);
  }

  nOffset1 = SendMessage(hEditWnd, 3136 /*AEM_INDEXTORICHOFFSET*/, 0, lpIndex1);
  nOffset2 = SendMessage(hEditWnd, 3136 /*AEM_INDEXTORICHOFFSET*/, 0, lpIndex2);

  AkelPad.MemFree(lpIndex1);
  AkelPad.MemFree(lpIndex2);

  return AkelPad.GetTextRange(nOffset1, nOffset2).replace(/^\s*(AkelPad)?\.?|\s+$/g, "");
}

function GetWindowPos(hWnd, oRect)
{
  var lpRect = AkelPad.MemAlloc(16); //sizeof(RECT)

  if (hWnd)
    oSys.Call("User32::GetWindowRect", hWnd, lpRect);
  else
    oSys.Call("User32::SystemParametersInfoW", 0x30 /*SPI_GETWORKAREA*/, 0, lpRect, 0);

  oRect.X = AkelPad.MemRead(_PtrAdd(lpRect,  0), 3 /*DT_DWORD*/);
  oRect.Y = AkelPad.MemRead(_PtrAdd(lpRect,  4), 3 /*DT_DWORD*/);
  oRect.W = AkelPad.MemRead(_PtrAdd(lpRect,  8), 3 /*DT_DWORD*/) - oRect.X;
  oRect.H = AkelPad.MemRead(_PtrAdd(lpRect, 12), 3 /*DT_DWORD*/) - oRect.Y;

  AkelPad.MemFree(lpRect);
}

function SetForegroundWindow(hWnd)
{
  if (! oSys.Call("User32::IsWindowVisible", hWnd))
    oSys.Call("User32::ShowWindow", hWnd, 8 /*SW_SHOWNA*/);
  if (oSys.Call("User32::IsIconic", hWnd))
    oSys.Call("User32::ShowWindow", hWnd, 9 /*SW_RESTORE*/);

  oSys.Call("User32::SetForegroundWindow", hWnd);
}

function SetWindowText(hWnd, sText)
{
  oSys.Call("User32::SetWindowTextW", hWnd, sText);
}

function SetWindowFont(hWnd, hFont)
{
  SendMessage(hWnd, 48 /*WM_SETFONT*/, hFont, true);
}

function GetSelStartAE()
{
  AkelPad.SetEditWnd(aDlg[IDTEXT].HWND);
  var nSelStart = AkelPad.GetSelStart();
  AkelPad.SetEditWnd(0);
  return nSelStart;
}

function GetSelEndAE()
{
  AkelPad.SetEditWnd(aDlg[IDTEXT].HWND);
  var nSelEnd = AkelPad.GetSelEnd();
  AkelPad.SetEditWnd(0);
  return nSelEnd;
}

function SetSelAE(nSelStart, nSelEnd)
{
  AkelPad.SetEditWnd(aDlg[IDTEXT].HWND);
  AkelPad.SetSel(nSelStart, nSelEnd);
  AkelPad.SetEditWnd(0);
}

function GetSelTextAE()
{
  AkelPad.SetEditWnd(aDlg[IDTEXT].HWND);
  var sText = AkelPad.GetSelText(0);
  AkelPad.SetEditWnd(0);
  return sText;
}

function SetWordWrapAE()
{
  SendMessage(aDlg[IDTEXT].HWND, 0x0CAA /*AEM_SETWORDWRAP*/, bWordWrap ? 1 /*AEWW_WORD*/ : 0 /*AEWW_NONE*/, 0);
}

function SetOptionsAE()
{
  var hEditWnd = AkelPad.GetEditWnd();
  var lpRect;
  var lpAECOLORS;
  var lpPOINT;

  hSubClass = AkelPad.WindowSubClass(aDlg[IDTEXT].HWND, EditCallback, 515 /*WM_LBUTTONDBLCLK*/);

  lpRect = AkelPad.MemAlloc(16); //sizeof(RECT)
  AkelPad.MemCopy(_PtrAdd(lpRect,  0), 4, 3 /*DT_DWORD*/);
  AkelPad.MemCopy(_PtrAdd(lpRect,  4), 4, 3 /*DT_DWORD*/);
  AkelPad.MemCopy(_PtrAdd(lpRect,  8), 4, 3 /*DT_DWORD*/);
  AkelPad.MemCopy(_PtrAdd(lpRect, 12), 4, 3 /*DT_DWORD*/);
  SendMessage(aDlg[IDTEXT].HWND, 3178 /*AEM_SETRECT*/, 0x03 /*AERC_MARGINS|AERC_UPDATE*/, lpRect);
  AkelPad.MemFree(lpRect);

  SetWindowFont(aDlg[IDTEXT].HWND, SendMessage(hMainWnd, 1233 /*AKD_GETFONTW*/, 0, 0));
  SendMessage(aDlg[IDTEXT].HWND, 3228 /*AEM_SETOPTIONS*/, 2 /*AECOOP_OR*/, 0x10000000 /*AECO_DISABLEBEEP*/);
  SendMessage(aDlg[IDTEXT].HWND, 3234 /*AEM_EXSETOPTIONS*/, 2 /*AECOOP_OR*/, 0x00000001 /*AECOE_DETECTURL*/);
  SetWordWrapAE();

  if (hEditWnd)
  {
    lpAECOLORS = AkelPad.MemAlloc(17 * 4);
    AkelPad.MemCopy(lpAECOLORS, 0x0001FFFE /*AECLR_ALL*/, 3 /*DT_DWORD*/);
    SendMessage(hEditWnd, 3231 /*AEM_GETCOLORS*/, 0, lpAECOLORS);
    SendMessage(aDlg[IDTEXT].HWND, 3232 /*AEM_SETCOLORS*/, 0, lpAECOLORS);
    AkelPad.MemFree(lpAECOLORS);

    if (SendMessage(hEditWnd, 3227 /*AEM_GETOPTIONS*/, 0, 0) & 0x00001000 /*AECO_ACTIVELINEBORDER*/)
      SendMessage(aDlg[IDTEXT].HWND, 3228 /*AEM_SETOPTIONS*/, 2 /*AECOOP_OR*/, 0x00001000 /*AECO_ACTIVELINEBORDER*/);

    lpPOINT = AkelPad.MemAlloc(8);
    SendMessage(hEditWnd, 3237 /*AEM_GETCARETWIDTH*/, 0, lpPOINT);
    SendMessage(aDlg[IDTEXT].HWND, 3238 /*AEM_SETCARETWIDTH*/, 0, lpPOINT);
    AkelPad.MemFree(lpPOINT);

    SendMessage(aDlg[IDTEXT].HWND, 3260 /*AEM_SETLINEGAP*/, SendMessage(hEditWnd, 3259 /*AEM_GETLINEGAP*/, 0, 0), 0);
  }
}

function GetCurFocLV()
{
  return SendMessage(aDlg[IDNAMELV].HWND, 0x100C /*LVM_GETNEXTITEM*/, -1, 0x0001 /*LVNI_FOCUSED*/);
}

function GetCurSelLV()
{
  return SendMessage(aDlg[IDNAMELV].HWND, 0x100C /*LVM_GETNEXTITEM*/, -1, 0x0002 /*LVNI_SELECTED*/);
}

function SetCurSelLV(nItem)
{
  AkelPad.MemCopy(_PtrAdd(lpLVITEM, 12), 0x0003 /*LVIS_SELECTED|LVIS_FOCUSED*/, 3 /*DT_DWORD*/);
  AkelPad.MemCopy(_PtrAdd(lpLVITEM, 16), 0x0003 /*LVIS_SELECTED|LVIS_FOCUSED*/, 3 /*DT_DWORD*/);
  SendMessage(aDlg[IDNAMELV].HWND, 0x102B /*LVM_SETITEMSTATE*/, nItem, lpLVITEM);
  SendMessage(aDlg[IDNAMELV].HWND, 0x1013 /*LVM_ENSUREVISIBLE*/, nItem, false);
}

function InsertColumnLV()
{
  var lpLVCOLUMN = AkelPad.MemAlloc(_X64 ? 56 : 44 /*sizeof(LVCOLUMN)*/);

  AkelPad.MemCopy(lpLVCOLUMN, 6, 3 /*DT_DWORD*/); //mask=LVCF_WIDTH|LVCF_TEXT
  AkelPad.MemCopy(_PtrAdd(lpLVCOLUMN, 8),          Scale.X(182), 3 /*DT_DWORD*/); //cx
  AkelPad.MemCopy(_PtrAdd(lpLVCOLUMN, _X64 ? 16 : 12), lpTextLV, 2 /*DT_QWORD*/); //pszText
  AkelPad.MemCopy(lpTextLV, sTxtName, 1 /*DT_UNICODE*/);
  SendMessage(aDlg[IDNAMELV].HWND, 0x1061 /*LVM_INSERTCOLUMNW*/, 0, lpLVCOLUMN);

  AkelPad.MemCopy(_PtrAdd(lpLVCOLUMN, 8), 0, 3 /*DT_DWORD*/); //cx
  AkelPad.MemCopy(lpTextLV, "AX", 1 /*DT_UNICODE*/);
  SendMessage(aDlg[IDNAMELV].HWND, 0x1061 /*LVM_INSERTCOLUMNW*/, 1, lpLVCOLUMN);

  SendMessage(aDlg[IDNAMELV].HWND, 0x1036 /*LVM_SETEXTENDEDLISTVIEWSTYLE*/, 0, 0x0021 /*LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES*/);
  AkelPad.MemFree(lpLVCOLUMN);
}

function FillLV(nSel, sFind, bFindOnStart)
{
  var oRE = GetFindNameRegExp(sFind);
  var i;

  SendMessage(aDlg[IDNAMELV].HWND, 0x000B /*WM_SETREDRAW*/, false, 0);
  SendMessage(aDlg[IDNAMELV].HWND, 0x1009 /*LVM_DELETEALLITEMS*/, 0, 0);

  for (i = 0; i < aAPM.length; ++i)
  {
    AkelPad.MemCopy(_PtrAdd(lpLVITEM, 4), i, 3 /*DT_DWORD*/); //iItem
    AkelPad.MemCopy(_PtrAdd(lpLVITEM, 8), 0, 3 /*DT_DWORD*/); //iSubItem
    AkelPad.MemCopy(lpTextLV, aAPM[i][0], 1 /*DT_UNICODE*/);
    SendMessage(aDlg[IDNAMELV].HWND, 0x104D /*LVM_INSERTITEMW*/, 0, lpLVITEM);

    AkelPad.MemCopy(_PtrAdd(lpLVITEM, 8), 1, 3 /*DT_DWORD*/); //iSubItem
    AkelPad.MemCopy(lpTextLV, aAPM[i][3], 1 /*DT_UNICODE*/);
    SendMessage(aDlg[IDNAMELV].HWND, 0x1074 /*LVM_SETITEMTEXTW*/, i, lpLVITEM);

    if (sFind)
    {
      if ((bFindOnStart && oRE.test(aAPM[i][0])) || ((! bFindOnStart) && (aAPM[i][0] == sFind)))
      {
        if (bFindOnStart)
          sFindName = sFind;

        nSel  = i;
        sFind = "";
      }
    }
  }

  if (nSel >= aAPM.length)
    nSel = aAPM.length - 1;
  if (nSel < 0)
    nSel = 0;

  SetCurSelLV(nSel);
  SendMessage(aDlg[IDNAMELV].HWND, 0x000B /*WM_SETREDRAW*/, true, 0);
}

function GetArrayAPM(hWnd)
{
  var oFSO     = new ActiveXObject("Scripting.FileSystemObject");
  var sDocsDir = AkelPad.GetAkelDir(2 /*ADTYPE_DOCS*/) + "\\";
  var aDocFile = ["Scripts-Chs.txt", "Scripts-Eng.txt"];
  var sText;
  var oRE;
  var aExec;
  var i;

  aIsLang     = [false, false];
  sHeader     = "";
  aAPM.length = 0;

  while (! (aIsLang[0] || aIsLang[1]))
  {
    if (sAltDir)
    {
      for (i = 0; i < 2; ++i)
        aIsLang[i] = oFSO.FileExists(sAltDir + aDocFile[i]);
    }

    if (aIsLang[0] || aIsLang[1])
      sDocsDir = sAltDir;
    else
    {
      for (i = 0; i < 2; ++i)
        aIsLang[i] = oFSO.FileExists(sDocsDir + aDocFile[i]);

      if (! (aIsLang[0] || aIsLang[1]))
      {
        AkelPad.MessageBox(hWnd, sTxtNoFiles + "\n" + ((sAltDir && (sAltDir.toUpperCase() != sDocsDir.toUpperCase())) ? (sAltDir + aDocFile[0] + "\n" + sAltDir + aDocFile[1] + "\n") : "") + sDocsDir + aDocFile[0] + "\n" + sDocsDir + aDocFile[1], sTxtDlgTitle, 0x30 /*MB_ICONWARNING*/);

        if (! sAltDir)
          sAltDir = AkelPad.GetAkelDir(1 /*ADTYPE_AKELFILES*/) + "\\";

        sAltDir = BrowseForFolder(hWnd, sTxtChooseDir, sAltDir);

        if (! sAltDir)
          return;
        else if (sAltDir.slice(-1) != "\\")
          sAltDir += "\\";
      }
    }
  }

  if (! aIsLang[nAPMLang])
    nAPMLang = Number(! nAPMLang);

  sText = AkelPad.ReadFile(sDocsDir + aDocFile[nAPMLang], 0, 936 /*ANSI Cyrillic*/, 0).replace(/\r\n/g, "\n");

  //aAPM["name", "text", "AkelPad." if method name, "+" if ActiveX]
  //methods and constants
  oRE = /^((AkelPad\.)?([\w.()]+)( \(\+ActiveX\))?\n_+\n+[\s\S]+?\n)\n*(?=[\w.() +]+\n_+)|^((AkelPad\.)?([\w.()]+)( \(\+ActiveX\))?\n_+\n+[\s\S]+?\n)\n*(?=\*{3} \S.+\S \*{3}\n)/gm
  while (aExec = oRE.exec(sText))
  {
    if (aExec[1])
      aAPM.push([aExec[3], aExec[1], aExec[2], aExec[4] ? "+" : ""]);
    else if (aExec[5])
      aAPM.push([aExec[7], aExec[5], aExec[6], aExec[8] ? "+" : ""]);
  }

  if (bAPMSort)
    aAPM.sort(
      function(a1, a2)
      {
        if (a1[0] < a2[0])
          return -1;
        else if (a1[0] > a2[0])
          return 1;
        else
          return 0;
      });

  //Scripts-*.txt
  //first char in Name must be "*"
  if (aExec = /(^\*{4,}\n\*{3} +(\S.+\S) +\*{3}\n\*{4,}\n+[\s\S]+?\n)/m.exec(sText))
  {
    sHeader = aExec[2];
    aAPM.push(["*** " + aDocFile[nAPMLang] + " ***", aExec[1], "", ""]);
  }

  oRE = /^((\*{3} \S.+\S \*{3})\n+[\s\S]+?\n)\n*(?=\*{3} \S.+\S \*{3}\n)|(^(\*{3} \S.+\S \*{3})\n+[\s\S]+)/gm;
  while (aExec = oRE.exec(sText))
  {
    if (aExec[1])
      aAPM.push([aExec[2].replace(/ \(.+\)/, ""), aExec[1], "", ""]);
    else if (aExec[3])
      aAPM.push([aExec[4].replace(/ \(.+\)/, ""), aExec[3], "", ""]);
  }
}

function CheckButtons(nButton)
{
  if (nButton == IDSORTB)
    bAPMSort = ! bAPMSort;
  else if ((nButton == IDLANG1B) || (nButton == IDLANG2B))
    nAPMLang = nButton - IDLANG1B;

  SendMessage(aDlg[IDSORTB ].HWND, 241 /*BM_SETCHECK*/, bAPMSort, 0);
  SendMessage(aDlg[IDLANG1B].HWND, 241 /*BM_SETCHECK*/, (nAPMLang == 0), 0);
  SendMessage(aDlg[IDLANG2B].HWND, 241 /*BM_SETCHECK*/, (nAPMLang == 1), 0);

  oSys.Call("User32::EnableWindow", aDlg[IDLANG1B].HWND, aIsLang[0]);
  oSys.Call("User32::EnableWindow", aDlg[IDLANG2B].HWND, aIsLang[1]);
}

function PaintSizeGrip()
{
  var lpPaint = AkelPad.MemAlloc(_X64 ? 72 : 64); //sizeof(PAINTSTRUCT)
  var lpRect  = AkelPad.MemAlloc(16); //sizeof(RECT)
  var hDC;

  if (hDC = oSys.Call("User32::BeginPaint", hDlg, lpPaint))
  {
    oSys.Call("User32::GetClientRect", hDlg, lpRect);

    AkelPad.MemCopy(_PtrAdd(lpRect, 0), AkelPad.MemRead(_PtrAdd(lpRect,  8), 3 /*DT_DWORD*/) - oSys.Call("User32::GetSystemMetrics",  2 /*SM_CXVSCROLL*/), 3 /*DT_DWORD*/);
    AkelPad.MemCopy(_PtrAdd(lpRect, 4), AkelPad.MemRead(_PtrAdd(lpRect, 12), 3 /*DT_DWORD*/) - oSys.Call("User32::GetSystemMetrics", 20 /*SM_CYVSCROLL*/), 3 /*DT_DWORD*/);

    oSys.Call("User32::DrawFrameControl", hDC, lpRect, 3 /*DFC_SCROLL*/, 0x8 /*DFCS_SCROLLSIZEGRIP*/);
    oSys.Call("User32::EndPaint", hDlg, lpPaint);
  }

  AkelPad.MemFree(lpPaint);
  AkelPad.MemFree(lpRect);
}

function ResizeDlg(nW, nH)
{
  var nFlags = 0x14; //SWP_NOACTIVATE|SWP_NOZORDER
  var nGapW  = Scale.X(10);
  var nGapH  = Scale.Y(10);
  var nLVW   = Scale.X(230);
  var nAEW   = nW - nLVW - 3 * nGapW;
  var i;

  oSys.Call("User32::SetWindowPos",
    aDlg[IDHEADERS].HWND, 0,
    nW - nAEW - nGapW,
    nGapH,
    nAEW,
    Scale.Y(13),
    nFlags);
  oSys.Call("User32::SetWindowPos",
    aDlg[IDNAMELV].HWND, 0,
    nGapW,
    nGapH,
    nLVW,
    nH - 3 * nGapH - Scale.Y(23) - Scale.Y(25) - Scale.Y(20),
    nFlags);
  oSys.Call("User32::SetWindowPos",
    aDlg[IDTEXT].HWND, 0,
    nW - nAEW - nGapW,
    3 * nGapH,
    nAEW,
    nH - 4 * nGapH,
    nFlags);
  oSys.Call("User32::SetWindowPos",
    aDlg[IDSORTB].HWND, 0,
    nGapW,
    nH - nGapH - Scale.Y(23) - Scale.Y(25) - Scale.Y(20),
    Scale.X(80),
    Scale.Y(16),
    nFlags);
  for (i = IDLANG1B; i <= IDLANG2B; ++i)
  {
    oSys.Call("User32::SetWindowPos",
      aDlg[i].HWND, 0,
      Scale.X(160),
      nH - nGapH - Scale.Y(23) - Scale.Y(25) - (IDLANG2B - i) * Scale.Y(20),
      Scale.X(80),
      Scale.Y(16),
      nFlags);
  }
  for (i = IDMENUB; i <= IDCLOSEB; ++i)
  {
    oSys.Call("User32::SetWindowPos",
      aDlg[i].HWND, 0,
      nGapW + Scale.X((i - IDMENUB) * 80),
      nH - nGapH - Scale.Y(23),
      Scale.X(70),
      Scale.Y(23),
      nFlags);
  }

  SendMessage(aDlg[IDNAMELV].HWND, 0x101E /*LVM_SETCOLUMNWIDTH*/, 1, -2 /*LVSCW_AUTOSIZE_USEHEADER*/);
  SendMessage(aDlg[IDNAMELV].HWND, 0x1013 /*LVM_ENSUREVISIBLE*/, GetCurSelLV(), false);
  oSys.Call("user32::InvalidateRect", hDlg, 0, true);
}

function FindName(nDirection)
{
  InputBox(aDlg[IDNAMELV].HWND, sTxtFindName, [sTxtDownFromBeg, sTxtDownFromCur, sTxtUpFromEnd, sTxtUpFromCur][nDirection] + "\n\n" + sTxtName + ":", sFindName, 0, CheckFindName, nDirection, 0, (bMatchCase ? sTxtMatchCase : sTxtIgnoreCase));
}

function CheckFindName(hWnd, aName, nDirection)
{
  if (aName[0])
  {
    sFindName = aName[0];
    if (! FindNameNext(nDirection))
    {
      AkelPad.MessageBox(hWnd, sTxtNotFound, sTxtDlgTitle, 0x30 /*MB_ICONWARNING*/);
      return 0;
    }
  }
  else
    return 0;

  return -1;
}

function FindNameNext(nDirection)
{
  var bFound = false;

  if (sFindName)
  {
    var oRE = GetFindNameRegExp(sFindName);
    var nStart;
    var i;

    if (nDirection < 2)
    {
      if (nDirection == 0)
        nStart = 0;
      else
        nStart = GetCurSelLV() + 1;
  
      for (i = nStart; i < aAPM.length; ++i)
      {
        if (oRE.test(aAPM[i][0]))
        {
          SetCurSelLV(i);
          bFound = true;
          break;
        }
      }
    }
    else
    {
      if (nDirection == 2)
        nStart = aAPM.length - 1;
      else
        nStart = GetCurSelLV() - 1;
  
      for (i = nStart; i >= 0; --i)
      {
        if (oRE.test(aAPM[i][0]))
        {
          SetCurSelLV(i);
          bFound = true;
          break;
        }
      }
    }
  }

  return bFound;
}

function GetFindNameRegExp(sText)
{
  return new RegExp(sText.replace(/[\\\/.^$+*?|()\[\]{}]/g, "\\$&"), (bMatchCase ? "" : "i"));
}

function FindText(nDirection)
{
  var sText = GetSelTextAE();

  if (! sText)
    sText = sFindText;

  InputBox(aDlg[IDTEXT].HWND, sTxtFindText, [sTxtDownFromBeg, sTxtDownFromCur, sTxtUpFromEnd, sTxtUpFromCur][nDirection] + "\n\n" + sTxtText + ":", sText, 0, CheckFindText, nDirection, 0, (bMatchCase ? sTxtMatchCase : sTxtIgnoreCase));
}

function CheckFindText(hWnd, aText, nDirection)
{
  if (aText[0])
  {
    sFindText = aText[0];
    if (! FindTextNext(nDirection))
    {
      AkelPad.MessageBox(hWnd, sTxtNotFound, sTxtDlgTitle, 0x30 /*MB_ICONWARNING*/);
      return 0;
    }
  }
  else
    return 0;

  return -1;
}

function FindTextNext(nDirection)
{
  var bFound = false;
  var nNameStart;
  var nTextStart;
  var nSel;
  var i;

  if (nDirection < 2)
  {
    if (nDirection == 0)
    {
      nNameStart = 0;
      nTextStart = 0;
    }
    else
    {
      nNameStart = GetCurSelLV();
      nTextStart = GetSelEndAE();
    }

    for (i = nNameStart; i < aAPM.length; ++i)
    {
      if (bMatchCase)
        nSel = aAPM[i][1].indexOf(sFindText, (i == nNameStart) ? nTextStart : 0);
      else
        nSel = aAPM[i][1].toUpperCase().indexOf(sFindText.toUpperCase(), (i == nNameStart) ? nTextStart : 0);

      if (nSel > -1)
      {
        SetCurSelLV(i);
        SetSelAE(nSel, nSel + sFindText.length);
        bFound = true;
        break;
      }
    }
  }
  else
  {
    if (nDirection == 2)
    {
      nNameStart = aAPM.length - 1;
      nTextStart = aAPM[nNameStart][1].length;
    }
    else
    {
      nNameStart = GetCurSelLV();
      nTextStart = GetSelStartAE() - sFindText.length;

      if ((nTextStart < 0) && (--nNameStart >= 0))
        nTextStart = aAPM[nNameStart][1].length;
    }

    for (i = nNameStart; i >= 0; --i)
    {
      if (bMatchCase)
        nSel = aAPM[i][1].lastIndexOf(sFindText, (i == nNameStart) ? nTextStart : aAPM[i][1].length);
      else
        nSel = aAPM[i][1].toUpperCase().lastIndexOf(sFindText.toUpperCase(), (i == nNameStart) ? nTextStart : aAPM[i][1].length);

      if (nSel > -1)
      {
        SetCurSelLV(i);
        SetSelAE(nSel, nSel + sFindText.length);
        bFound = true;
        break;
      }
    }
  }

  return bFound;
}

function CopytNameToCB()
{
  if ((nAPMSel >= 0) && (aAPM[nAPMSel][0].charAt(0) != "*"))
    AkelPad.SetClipboardText(aAPM[nAPMSel][2] + aAPM[nAPMSel][0] + (aAPM[nAPMSel][2] ? "()" : ""));
}

function InsertNameToAP()
{
  if ((nAPMSel >= 0) && (aAPM[nAPMSel][0].charAt(0) != "*") && AkelPad.GetEditWnd() && (! AkelPad.GetEditReadOnly(0)))
  {
    if (aAPM[nAPMSel][2])
    {
      var sSelText = AkelPad.GetSelText(0);
      AkelPad.ReplaceSel(aAPM[nAPMSel][2] + aAPM[nAPMSel][0] + "(" + sSelText + ")");
      AkelPad.SetSel(AkelPad.GetSelEnd() - sSelText.length - 1, AkelPad.GetSelEnd() - 1);
    }
    else
      AkelPad.ReplaceSel(aAPM[nAPMSel][0], -1 /*RST_SELECT*/);
  }
}

function CopyListToCB()
{
  var sText = "";
  var i;

  for (i = 0; i < aAPM.length; ++i)
  {
    if (aAPM[i][0].charAt(0) != "*")
      sText += aAPM[i][2] + aAPM[i][0] + "\r\n";
  }

  AkelPad.SetClipboardText(sText);
}

function InsertTextTo(bClipboard)
{
  var sText = GetSelTextAE();

  if (sText)
  {
    if (bClipboard)
      AkelPad.SetClipboardText(sText);
    else
      AkelPad.ReplaceSel(sText, -1 /*RST_SELECT*/);
  }
}

function MenuMain()
{
  var MF_STRING    = 0x0000;
  var MF_CHECKED   = 0x0008;
  var MF_POPUP     = 0x0010;
  var MF_SEPARATOR = 0x0800;
  var hMenu1 = oSys.Call("User32::CreatePopupMenu");
  var hMenu2 = oSys.Call("User32::CreatePopupMenu");
  var hMenu  = oSys.Call("User32::CreatePopupMenu");
  var aMenu  = [hMenu1, hMenu2];
  var oRect  = {};
  var nCmd;
  var nCmd1;
  var i;

  for (i = 1; i <= 2; ++i)
  {
    oSys.Call("User32::AppendMenuW", aMenu[i - 1], MF_STRING, 0x0000 | i, sTxtDownFromBeg + "\tCtrl+F");
    oSys.Call("User32::AppendMenuW", aMenu[i - 1], MF_STRING, 0x0200 | i, sTxtUpFromEnd   + "\tCtrl+Shift+F");
    oSys.Call("user32::AppendMenuW", aMenu[i - 1], MF_SEPARATOR, 0);
    oSys.Call("User32::AppendMenuW", aMenu[i - 1], MF_STRING, 0x0100 | i, sTxtDownFromCur + "\tAlt+F");
    oSys.Call("User32::AppendMenuW", aMenu[i - 1], MF_STRING, 0x0300 | i, sTxtUpFromCur   + "\tShift+Alt+F");
    oSys.Call("user32::AppendMenuW", aMenu[i - 1], MF_SEPARATOR, 0);
    oSys.Call("User32::AppendMenuW", aMenu[i - 1], MF_STRING, 0x0400 | i, sTxtNext     + "\tF3");
    oSys.Call("User32::AppendMenuW", aMenu[i - 1], MF_STRING, 0x0500 | i, sTxtPrevious + "\tShift+F3");
  }

  oSys.Call("User32::AppendMenuW", hMenu, MF_POPUP,  hMenu1, sTxtFindName);
  oSys.Call("User32::AppendMenuW", hMenu, MF_POPUP,  hMenu2, sTxtFindText);
  oSys.Call("user32::AppendMenuW", hMenu, MF_SEPARATOR, 0);
  oSys.Call("User32::AppendMenuW", hMenu, (bMatchCase ? MF_CHECKED : MF_STRING), 0x0003, sTxtFindCase);
  oSys.Call("User32::AppendMenuW", hMenu, (bWordWrap ? MF_CHECKED : MF_STRING), 0x0004, sTxtWrapLines + "\tCtrl+U");
  oSys.Call("User32::AppendMenuW", hMenu, (bSeparateWnd ? MF_CHECKED : MF_STRING), 0x0005, sTxtSeparateWnd);

  GetWindowPos(aDlg[IDMENUB].HWND, oRect);

  nCmd = oSys.Call("User32::TrackPopupMenu", hMenu, 0x01A0 /*TPM_NONOTIFY|TPM_RETURNCMD|TPM_BOTTOMALIGN*/, oRect.X, oRect.Y, 0, hDlg, 0);

  oSys.Call("User32::DestroyMenu", hMenu1);
  oSys.Call("User32::DestroyMenu", hMenu2);
  oSys.Call("User32::DestroyMenu", hMenu);

  nCmd1 = (nCmd >> 8) & 0xFF;
  nCmd  = nCmd & 0xFF;

  if (nCmd == 1)
  {
    oSys.Call("User32::SetFocus", aDlg[IDNAMELV].HWND);
    if (nCmd1 < 4)
      FindName(nCmd1);
    else if (nCmd1 == 4)
      FindNameNext(1);
    else if (nCmd1 == 5)
      FindNameNext(3);
  }
  else if (nCmd == 2)
  {
    oSys.Call("User32::SetFocus", aDlg[IDTEXT].HWND);
    if (nCmd1 < 4)
      FindText(nCmd1);
    else if (nCmd1 == 4)
      FindTextNext(1);
    else if (nCmd1 == 5)
      FindTextNext(3);
  }
  else if (nCmd == 3)
    bMatchCase = ! bMatchCase;
  else if (nCmd == 4)
  {
    bWordWrap = ! bWordWrap;
    SetWordWrapAE();
  }
  else if (nCmd == 5)
  {
    bSeparateWnd = ! bSeparateWnd;
    bCloseDlg    = false;
    PostMessage(hDlg, 16 /*WM_CLOSE*/, 0, 0);
  }
}

function MenuName(nX, nY)
{
  var MF_STRING    = 0x0000;
  var MF_SEPARATOR = 0x0800;
  var lpRect;
  var nX1, nY1, nY2;
  var hMenu;
  var nCmd;

  if ((nAPMSel < 0) || (aAPM[nAPMSel][0].charAt(0) == "*"))
    return;

  //menu from keyboard
  if (nX == 0xFFFF)
    SendMessage(aDlg[IDNAMELV].HWND, 0x1013 /*LVM_ENSUREVISIBLE*/, nAPMSel, false);

  lpRect = AkelPad.MemAlloc(16 /*sizeof(RECT)*/);
  SendMessage(aDlg[IDNAMELV].HWND, 0x100E /*LVM_GETITEMRECT*/, nAPMSel, lpRect);
  oSys.Call("User32::ClientToScreen", aDlg[IDNAMELV].HWND, lpRect);
  oSys.Call("User32::ClientToScreen", aDlg[IDNAMELV].HWND, _PtrAdd(lpRect, 8));
  nX1 = AkelPad.MemRead(_PtrAdd(lpRect,  0), 3 /*DT_DWORD*/);
  nY1 = AkelPad.MemRead(_PtrAdd(lpRect,  4), 3 /*DT_DWORD*/);
  nY2 = AkelPad.MemRead(_PtrAdd(lpRect, 12), 3 /*DT_DWORD*/);
  AkelPad.MemFree(lpRect);

  if (nX == 0xFFFF)
  {
    nX = nX1;
    nY = nY2;
  }
  else if ((nY < nY1) || (nY > nY2))
    return;

  hMenu = oSys.Call("User32::CreatePopupMenu");
  oSys.Call("User32::AppendMenuW", hMenu, MF_STRING, 1, sTxtCopyToCB + "\tCtrl+C");
  oSys.Call("User32::AppendMenuW", hMenu, AkelPad.GetEditWnd() && (! AkelPad.GetEditReadOnly(0)) ? MF_STRING : 0x01 /*MF_GRAYED*/, 2, sTxtInsertToAP + "\tCtrl+Shift+C");
  oSys.Call("user32::AppendMenuW", hMenu, MF_SEPARATOR, 0);
  oSys.Call("User32::AppendMenuW", hMenu, MF_STRING, 3, sTxtCopyListToCB);

  nCmd = oSys.Call("User32::TrackPopupMenu", hMenu, 0x0180 /*TPM_NONOTIFY|TPM_RETURNCMD*/, nX, nY, 0, hDlg, 0);

  oSys.Call("User32::DestroyMenu", hMenu);

  if (nCmd == 1)
    CopytNameToCB();
  else if (nCmd == 2)
    InsertNameToAP();
  else if (nCmd == 3)
    CopyListToCB();
}

function MenuText(nX, nY)
{
  var bSel  = SendMessage(aDlg[IDTEXT].HWND, 3125 /*AEM_GETSEL*/, 0, 0);
  var hMenu = oSys.Call("User32::CreatePopupMenu");
  var lpPoint;
  var nCmd;

  //menu from keyboard
  if (nX == 0xFFFF)
  {
    lpPoint = AkelPad.MemAlloc(8 /*sizeof(POINT)*/);
    oSys.Call("User32::GetCaretPos", lpPoint);
    oSys.Call("User32::ClientToScreen", aDlg[IDTEXT].HWND, lpPoint);
    nX = AkelPad.MemRead(_PtrAdd(lpPoint, 0), 3 /*DT_DWORD*/);
    nY = AkelPad.MemRead(_PtrAdd(lpPoint, 4), 3 /*DT_DWORD*/) + SendMessage(aDlg[IDTEXT].HWND, 3188 /*AEM_GETCHARSIZE*/, 0 /*AECS_HEIGHT*/, 0);
    AkelPad.MemFree(lpPoint);
  }

  oSys.Call("User32::AppendMenuW", hMenu, bSel ? 0 /*MF_STRING*/ : 0x01 /*MF_GRAYED*/, 1, sTxtCopyToCB + "\tCtrl+C");
  oSys.Call("User32::AppendMenuW", hMenu, AkelPad.GetEditWnd() && (! AkelPad.GetEditReadOnly(0)) && bSel ? 0 /*MF_STRING*/ : 0x01 /*MF_GRAYED*/, 2, sTxtInsertToAP + "\tCtrl+Shift+C");
  oSys.Call("user32::AppendMenuW", hMenu, 0x0800 /*MF_SEPARATOR*/, 0);
  oSys.Call("User32::AppendMenuW", hMenu, 0 /*MF_STRING*/, 3, sTxtSelectAll + "\tCtrl+A");

  nCmd = oSys.Call("User32::TrackPopupMenu", hMenu, 0x0180 /*TPM_NONOTIFY|TPM_RETURNCMD*/, nX, nY, 0, hDlg, 0);

  oSys.Call("User32::DestroyMenu", hMenu);

  if (nCmd == 1)
    InsertTextTo(true);
  else if (nCmd == 2)
    InsertTextTo(false);
  else if (nCmd == 3)
    SetSelAE(0, -1);
}

function ReadIni()
{
  try
  {
    eval(AkelPad.ReadFile(WScript.ScriptFullName.replace(/\.js$/i, ".ini"), 0x10 /*OD_ADT_NOMESSAGES*/, 1200 /*UTF-16LE*/, true));
  }
  catch (oError)
  {}

  oDlgPos.W  = Math.max(Scale.X(oDlgPos.W), nDlgMinW);
  oDlgPos.H  = Math.max(Scale.Y(oDlgPos.H), nDlgMinH);
  hWndParent = bSeparateWnd ? 0 : hMainWnd;
}

function WriteIni()
{
  var sIniTxt = "";
  var i;

  oDlgPos.W   = Scale.UX(oDlgPos.W);
  oDlgPos.H   = Scale.UY(oDlgPos.H);
  oDlgPos.Max = oSys.Call("User32::IsZoomed", hDlg);

  for (i in oDlgPos)
    sIniTxt += 'oDlgPos.' + i + '=' + oDlgPos[i] + ';\r\n';

  sIniTxt +=
    'bSeparateWnd=' + bSeparateWnd + ';\r\n' +
    'nAPMSel='      + nAPMSel + ';\r\n' +
    'bAPMSort='     + bAPMSort + ';\r\n' +
    'nAPMLang='     + nAPMLang + ';\r\n' +
    'bMatchCase='   + bMatchCase + ';\r\n' +
    'bWordWrap='    + bWordWrap + ';\r\n' +
    'sFindName="'   + EscapeStr(sFindName) + '";\r\n' +
    'sFindText="'   + EscapeStr(sFindText) + '";\r\n' +
    'sAltDir="'     + EscapeStr(sAltDir) + '";\r\n' +
    'aAESel[0]={';

  for (i in aAESel[0])
    sIniTxt += '"' + i + '":[' + aAESel[0][i] + '],';

  if (sIniTxt.slice(-1) == ',')
    sIniTxt = sIniTxt.slice(0, -1);

  sIniTxt += '};\r\naAESel[1]={';

  for (i in aAESel[1])
    sIniTxt += '"' + i + '":[' + aAESel[1][i] + '],';

  if (sIniTxt.slice(-1) == ',')
    sIniTxt = sIniTxt.slice(0, -1);

  sIniTxt += '};';
	
  AkelPad.WriteFile(WScript.ScriptFullName.replace(/\.js$/i, ".ini"), sIniTxt, sIniTxt.length, 1200 /*UTF-16LE*/, true);
}

function EscapeStr(sText)
{
  return sText.replace(/[\\"]/g, '\\$&').replace(/\n/g, '\\n').replace(/\r/g, '\\r');
}

function GetLangStrings()
{
  sTxtDlgTitle     = "AkelPad 方法一览";
  sTxtNoFiles      = "找不到文件:";
  sTxtChooseDir    = "请选择 Scripts 插件的说明文档的所在目录:";
  sTxtSort         = "排序方法(&S)";
  sTxtEnglish      = "中文(&C)";
  sTxtRussian      = "英语(&E)";
  sTxtMenu         = "菜单(&M)";
  sTxtOK           = "确定";
  sTxtClose        = "关闭";
  sTxtName         = "名称";
  sTxtText         = "文本";
  sTxtFindName     = "查找名称";
  sTxtFindText     = "查找文本";
  sTxtDownFromBeg  = "从开始向下";
  sTxtDownFromCur  = "从当前位置向下";
  sTxtUpFromEnd    = "从末尾向上";
  sTxtUpFromCur    = "从当前位置向上";
  sTxtNext         = "下一个";
  sTxtPrevious     = "上一个";
  sTxtMatchCase    = "区分大小写";
  sTxtIgnoreCase   = "忽略大小写";
  sTxtNotFound     = "找不到。";
  sTxtFindCase     = "查找 - 区分大小写";
  sTxtWrapLines    = "自动换行";
  sTxtSeparateWnd  = "在独立窗口中运行";
  sTxtCopyToCB     = "复制到剪贴板";
  sTxtInsertToAP   = "插入到 AkelPad";
  sTxtSelectAll    = "全选";
  sTxtCopyListToCB = "复制列表到剪贴板";
}
