// http://akelpad.sourceforge.net/forum/viewtopic.php?p=8939#8939
// Version: 2015-09-19
// Author: KDJ
//
// *** Insert text/line number at beginning/end of selection ***
//
// Usage:
//   Call("Scripts::Main", 1, "InsertTextLN.js", "0") - insert in selection
//   Call("Scripts::Main", 1, "InsertTextLN.js", "1") - insert in each of selected lines
//   Call("Scripts::Main", 1, "InsertTextLN.js", "2") - insert in each part of columnar selection
//
// Remarks:
//   Argument "0" is default, can be omitted.
//   The script should be saved in Unicode format.

var oSys   = AkelPad.SystemFunction();
var pClass = "AkelPad::Scripts::" + WScript.ScriptName + "::" + oSys.Call("kernel32::GetCurrentProcessId");
var hDlg   = oSys.Call("User32::FindWindowExW", 0, 0, pClass, 0);

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

  oSys.Call("User32::SetForegroundWindow", hDlg);
  WScript.Quit();
}

var hMainWnd  = AkelPad.GetMainWnd();
var hEditWnd  = AkelPad.GetEditWnd();
var bReadOnly = AkelPad.GetEditReadOnly(hEditWnd);
var bColSel   = AkelPad.SendMessage(hEditWnd, 3127 /*AEM_GETCOLUMNSEL*/, 0, 0);
var nStrMax   = 15;
var pStrA     = "";
var pStrB     = "";
var bEscNL    = 0;
var bEscTab   = 1;
var nRange    = 0;
var bIsLNL    = 0;
var pPadLNL   = "";
var pPreLNL   = "";
var pSufLNL   = "";
var bRelLNL   = 0;
var pIniLNL   = "1";
var pStepLNL  = "1";
var bIsLNR    = 0;
var pPadLNR   = "";
var pPreLNR   = "";
var pSufLNR   = "";
var bRelLNR   = 0;
var pIniLNR   = "1";
var pStepLNR  = "1";
var bReplace  = 0;
var nDlgX     = 200;
var nDlgY     = 100;
var lpStrsA;
var lpStrsB;

var pTxtCaption   = "插入文本和行号";
var pTxtNoColSel  = "未列选。";
var pTxtA         =["选定区域的开头:",
                    "在行左:",
                    "在列选的每一个行左:"];
var pTxtB         =["选定区域的末尾:",
                    "在行右:",
                    "在列选的每一个行右:"];
var pTxtEscNL     = "\\n = 换行符(&N)";
var pTxtEscTab    = "\\t = 制表符(&T)";
var pTxtRange     = "范围";
var pTxtSelection = "选定区域(&E)";
var pTxtLines     = "选定的行(&D)";
var pTxtColSel    = "列选(&C)";
var pTxtLNL       = "左边行号(&L)";
var pTxtLNR       = "右边行号(&R)";
var pTxtPadLN     = "填充字符:";
var pTxtPreLN     = "前缀:";
var pTxtSufLN     = "后缀:";
var pTxtRelLN     = "相对数";
var pTxtIniLN     = "开始数:";
var pTxtStepLN    = "增量:";
var pTxtReplace   = "替换选定区域(&S)";
var pTxtApply     = "应用";
var pTxtOK        = "确定";
var pTxtClose     = "关闭";

ReadIni();

if (WScript.Arguments.length)
  nRange = parseInt(WScript.Arguments(0));

if ((nRange != 0) && (nRange != 1) && (nRange != 2))
  nRange = 0;

if ((nRange == 2) && (! bColSel))
{
  AkelPad.MessageBox(hEditWnd, pTxtNoColSel, pTxtCaption, 48 /*MB_ICONEXCLAMATION*/);
  nRange = 0;
}

var IDTXTA       = 1000;
var IDTXTB       = 1001;
var IDSTRA       = 1002;
var IDSTRB       = 1003;
var IDLNL        = 1004;
var IDISLNL      = 1005;
var IDTXTPADLNL  = 1006;
var IDPADLNL     = 1007;
var IDTXTPRELNL  = 1008;
var IDTXTSUFLNL  = 1009;
var IDPRELNL     = 1010;
var IDSUFLNL     = 1011;
var IDRELLNL     = 1012;
var IDTXTINILNL  = 1013;
var IDTXTSTEPLNL = 1014;
var IDINILNL     = 1015;
var IDSTEPLNL    = 1016;
var IDESC        = 1017;
var IDESCNL      = 1018;
var IDESCTAB     = 1019;
var IDRANGE      = 1020;
var IDSELECTION  = 1021;
var IDLINES      = 1022;
var IDCOLSEL     = 1023;
var IDREPLACE    = 1024;
var IDLNR        = 1025;
var IDISLNR      = 1026;
var IDTXTPADLNR  = 1027;
var IDPADLNR     = 1028;
var IDTXTPRELNR  = 1029;
var IDTXTSUFLNR  = 1030;
var IDPRELNR     = 1031;
var IDSUFLNR     = 1032;
var IDRELLNR     = 1033;
var IDTXTINILNR  = 1034;
var IDTXTSTEPLNR = 1035;
var IDINILNR     = 1036;
var IDSTEPLNR    = 1037;
var IDAPPLY      = 1038;
var IDOK         = 1039;
var IDCLOSE      = 1040;

AkelPad.WindowRegisterClass(pClass);

//0x50000000 = WS_VISIBLE|WS_CHILD
//0x50000007 = WS_VISIBLE|WS_CHILD|BS_GROUPBOX
//0x50000009 = WS_VISIBLE|WS_CHILD|BS_AUTORADIOBUTTON
//0x50010000 = WS_VISIBLE|WS_CHILD|WS_TABSTOP
//0x50010001 = WS_VISIBLE|WS_CHILD|WS_TABSTOP|BS_DEFPUSHBUTTON
//0x50010003 = WS_VISIBLE|WS_CHILD|WS_TABSTOP|BS_AUTOCHECKBOX
//0x50010080 = WS_VISIBLE|WS_CHILD|WS_TABSTOP|ES_AUTOHSCROLL
//0x50012080 = WS_VISIBLE|WS_CHILD|WS_TABSTOP|ES_AUTOHSCROLL|ES_NUMBER
//0x50210042 = WS_VISIBLE|WS_CHILD|WS_TABSTOP|WS_VSCROLL|CBS_DROPDOWN|CBS_AUTOHSCROLL
//0x90CA0040 = WS_VISIBLE|WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|DS_SETFONT
AkelPad.CreateDialog(0, pClass, pTxtCaption, 0x90CA0040, nDlgX, nDlgY, 485, 275, hMainWnd, DialogCallback, 0x2 /*CDF_PIXELS*/, 0, 0, "MS Shell Dlg", 1, 8, "|",
  //ExSt, Class,      Title,         Style,        X,   Y,   W,   H, ID,      lParam,
  0x0000, "STATIC",   "",            0x50000000,  10,  10, 225,  13, IDTXTA,       0, "|",
  0x0000, "STATIC",   "",            0x50000000, 250,  10, 225,  13, IDTXTB,       0, "|",
  0x0000, "COMBOBOX", "",            0x50210042,  10,  26, 225,  21, IDSTRA,       0, "|",
  0x0000, "COMBOBOX", "",            0x50210042, 250,  26, 225,  21, IDSTRB,       0, "|",
  0x0000, "BUTTON",   "",            0x50000007,  10,  55, 155, 177, IDLNL,        0, "|",
  0x0000, "BUTTON",   pTxtLNL,       0x50010003,  20,  70, 135,  16, IDISLNL,      0, "|",
  0x0000, "STATIC",   pTxtPadLN,     0x50000000,  20,  93,  70,  13, IDTXTPADLNL,  0, "|",
  0x0200, "EDIT",     pPadLNL,       0x50010080,  90,  91,  20,  20, IDPADLNL,     0, "|",
  0x0000, "STATIC",   pTxtPreLN,     0x50000000,  20, 117,  65,  13, IDTXTPRELNL,  0, "|",
  0x0000, "STATIC",   pTxtSufLN,     0x50000000,  90, 117,  65,  13, IDTXTSUFLNL,  0, "|",
  0x0200, "EDIT",     pPreLNL,       0x50010080,  20, 132,  65,  20, IDPRELNL,     0, "|",
  0x0200, "EDIT",     pSufLNL,       0x50010080,  90, 132,  65,  20, IDSUFLNL,     0, "|",
  0x0000, "BUTTON",   pTxtRelLN,     0x50010003,  20, 165, 135,  16, IDRELLNL,     0, "|",
  0x0000, "STATIC",   pTxtIniLN,     0x50000000,  20, 186,  65,  13, IDTXTINILNL,  0, "|",
  0x0000, "STATIC",   pTxtStepLN,    0x50000000,  90, 186,  65,  13, IDTXTSTEPLNL, 0, "|",
  0x0200, "EDIT",     pIniLNL,       0x50012080,  20, 201,  65,  20, IDINILNL,     0, "|",
  0x0200, "EDIT",     pStepLNL,      0x50012080,  90, 201,  65,  20, IDSTEPLNL,    0, "|",
  0x0000, "BUTTON",   "",            0x50000007, 175,  55, 135,  58, IDESC,        0, "|",
  0x0000, "BUTTON",   pTxtEscNL,     0x50010003, 185,  70, 120,  16, IDESCNL,      0, "|",
  0x0000, "BUTTON",   pTxtEscTab,    0x50010003, 185,  90, 120,  16, IDESCTAB,     0, "|",
  0x0000, "BUTTON",   pTxtRange,     0x50000007, 175, 122, 135,  81, IDRANGE,      0, "|",
  0x0000, "BUTTON",   pTxtSelection, 0x50000009, 185, 140, 120,  16, IDSELECTION,  0, "|",
  0x0000, "BUTTON",   pTxtLines,     0x50000009, 185, 160, 120,  16, IDLINES,      0, "|",
  0x0000, "BUTTON",   pTxtColSel,    0x50000009, 185, 180, 120,  16, IDCOLSEL,     0, "|",
  0x0000, "BUTTON",   pTxtReplace,   0x50010003, 185, 215, 120,  16, IDREPLACE,    0, "|",
  0x0000, "BUTTON",   "",            0x50000007, 320,  55, 155, 177, IDLNR,        0, "|",
  0x0000, "BUTTON",   pTxtLNR,       0x50010003, 330,  70, 135,  16, IDISLNR,      0, "|",
  0x0000, "STATIC",   pTxtPadLN,     0x50000000, 330,  93,  70,  13, IDTXTPADLNR,  0, "|",
  0x0200, "EDIT",     pPadLNR,       0x50010080, 400,  91,  20,  20, IDPADLNR,     0, "|",
  0x0000, "STATIC",   pTxtPreLN,     0x50000000, 330, 117,  65,  13, IDTXTPRELNR,  0, "|",
  0x0000, "STATIC",   pTxtSufLN,     0x50000000, 400, 117,  65,  13, IDTXTSUFLNR,  0, "|",
  0x0200, "EDIT",     pPreLNR,       0x50010080, 330, 132,  65,  20, IDPRELNR,     0, "|",
  0x0200, "EDIT",     pSufLNR,       0x50010080, 400, 132,  65,  20, IDSUFLNR,     0, "|",
  0x0000, "BUTTON",   pTxtRelLN,     0x50010003, 330, 165, 135,  16, IDRELLNR,     0, "|",
  0x0000, "STATIC",   pTxtIniLN,     0x50000000, 330, 186,  65,  13, IDTXTINILNR,  0, "|",
  0x0000, "STATIC",   pTxtStepLN,    0x50000000, 400, 186,  65,  13, IDTXTSTEPLNR, 0, "|",
  0x0200, "EDIT",     pIniLNR,       0x50012080, 330, 201,  65,  20, IDINILNR,     0, "|",
  0x0200, "EDIT",     pStepLNR,      0x50012080, 400, 201,  65,  20, IDSTEPLNR,    0, "|",
  0x0000, "BUTTON",   pTxtApply,     0x50010000, 120, 242,  75,  23, IDAPPLY,      0, "|",
  0x0000, "BUTTON",   pTxtOK,        0x50010001, 205, 242,  75,  23, IDOK,         0, "|",
  0x0000, "BUTTON",   pTxtClose,     0x50010000, 290, 242,  75,  23, IDCLOSE,      0, "|"
  );

if (hDlg)
{
  AkelPad.ScriptNoMutex();
  AkelPad.WindowGetMessage(0x2 /*WGM_NOKEYSEND*/);
}

AkelPad.WindowUnregisterClass(pClass);

function DialogCallback(hWnd, uMsg, wParam, lParam)
{
  var nID, i;

  if (uMsg == 272 /*WM_INITDIALOG*/)
  {
    hDlg = hWnd;

    //Fill comboboxes
    for (i = 0; i < lpStrsA.length; ++i)
      SendDlgItemMessage(IDSTRA, 323 /*CB_ADDSTRING*/, 0, lpStrsA[i]);
    for (i = 0; i < lpStrsB.length; ++i)
      SendDlgItemMessage(IDSTRB, 323 /*CB_ADDSTRING*/, 0, lpStrsB[i]);
    SetDlgItemText(IDSTRA, pStrA);
    SetDlgItemText(IDSTRB, pStrB);

    //Check
    CheckDlgButton(IDISLNL,   bIsLNL);
    CheckDlgButton(IDRELLNL,  bRelLNL);
    CheckDlgButton(IDESCNL,   bEscNL);
    CheckDlgButton(IDESCTAB,  bEscTab);
    CheckDlgButton(IDREPLACE, bReplace);
    CheckDlgButton(IDISLNR,   bIsLNR);
    CheckDlgButton(IDRELLNR,  bRelLNR);

    //Set limit edit text
    SendDlgItemMessage(IDPADLNL, 197 /*EM_LIMITTEXT*/, 1, 0);
    SendDlgItemMessage(IDPADLNR, 197 /*EM_LIMITTEXT*/, 1, 0);
  }

  else if (uMsg == 6 /*WM_ACTIVATE*/)
  {
    if (LoWord(wParam))
    {
      hEditWnd  = AkelPad.GetEditWnd();
      bReadOnly = AkelPad.GetEditReadOnly(hEditWnd);
      bColSel   = AkelPad.SendMessage(hEditWnd, 3127 /*AEM_GETCOLUMNSEL*/, 0, 0);

      if (hEditWnd && (! bReadOnly))
      {
        for (i = IDTXTA; i <= IDOK; ++i)
          oSys.Call("User32::EnableWindow", GetDlgItem(i), 1);
        for (i = IDTXTPADLNL; i <= IDRELLNL; ++i)
          oSys.Call("User32::EnableWindow", GetDlgItem(i), bIsLNL);
        for (i = IDTXTINILNL; i <= IDSTEPLNL; ++i)
          oSys.Call("User32::EnableWindow", GetDlgItem(i), (bIsLNL && bRelLNL));
        for (i = IDTXTPADLNR; i <= IDRELLNR; ++i)
          oSys.Call("User32::EnableWindow", GetDlgItem(i), bIsLNR);
        for (i = IDTXTINILNR; i <= IDSTEPLNR; ++i)
          oSys.Call("User32::EnableWindow", GetDlgItem(i), (bIsLNR && bRelLNR));

        if ((nRange == 2) && (! bColSel))
          nRange = 0;

        oSys.Call("User32::CheckRadioButton", hDlg, IDSELECTION, IDCOLSEL, IDSELECTION + nRange);
        oSys.Call("User32::EnableWindow", GetDlgItem(IDCOLSEL), bColSel);

        SetDlgItemText(IDTXTA, pTxtA[nRange]);
        SetDlgItemText(IDTXTB, pTxtB[nRange]);
      }
      else
      {
        for (i = IDTXTA; i <= IDOK; ++i)
          oSys.Call("User32::EnableWindow", GetDlgItem(i), 0);

        oSys.Call("User32::DefDlgProcW", hDlg, 1025 /*DM_SETDEFID*/, IDCLOSE, 0);
      }
    }
  }

  else if (uMsg == 273 /*WM_COMMAND*/)
  {
    nID = LoWord(wParam);

    if ((nID == IDISLNL) || (nID == IDRELLNL))
    {
      bIsLNL  = IsDlgButtonChecked(IDISLNL);
      bRelLNL = IsDlgButtonChecked(IDRELLNL);
      for (i = IDTXTPADLNL; i <= IDRELLNL; ++i)
        oSys.Call("User32::EnableWindow", GetDlgItem(i), bIsLNL);
      for (i = IDTXTINILNL; i <= IDSTEPLNL; ++i)
        oSys.Call("User32::EnableWindow", GetDlgItem(i), (bIsLNL && bRelLNL));
    }

    else if (nID == IDESCNL)
      bEscNL = IsDlgButtonChecked(nID);

    else if (nID == IDESCTAB)
      bEscTab = IsDlgButtonChecked(nID);

    else if ((nID >= IDSELECTION) && (nID <= IDCOLSEL))
    {
      nRange = nID - IDSELECTION;
      SetDlgItemText(IDTXTA, pTxtA[nRange]);
      SetDlgItemText(IDTXTB, pTxtB[nRange]);
    }

    else if (nID == IDREPLACE)
      bReplace = IsDlgButtonChecked(IDREPLACE);

    else if ((nID == IDISLNR) || (nID == IDRELLNR))
    {
      bIsLNR  = IsDlgButtonChecked(IDISLNR);
      bRelLNR = IsDlgButtonChecked(IDRELLNR);
      for (i = IDTXTPADLNR; i <= IDRELLNR; ++i)
        oSys.Call("User32::EnableWindow", GetDlgItem(i), bIsLNR);
      for (i = IDTXTINILNR; i <= IDSTEPLNR; ++i)
        oSys.Call("User32::EnableWindow", GetDlgItem(i), (bIsLNR && bRelLNR));
    }

    else if ((nID == IDAPPLY) || (nID == IDOK))
    {
      InsertText();

      if (nID == IDOK)
        oSys.Call("User32::PostMessageW", hDlg, 16 /*WM_CLOSE*/, 0, 0);
    }

    else if ((nID == IDCLOSE) || (nID == 2 /*IDCANCEL*/))
      oSys.Call("User32::PostMessageW", hDlg, 16 /*WM_CLOSE*/, 0, 0);
  }

  else if (uMsg == 16 /*WM_CLOSE*/)
  {
    WriteIni();
    oSys.Call("User32::PostQuitMessage", 0);
    oSys.Call("User32::DestroyWindow", hDlg);
  }

  return 0;
}

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

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

function GetDlgItem(nID)
{
  return oSys.Call("User32::GetDlgItem", hDlg, nID);
}

function SendDlgItemMessage(nID, uMsg, wParam, lParam)
{
  return oSys.Call("User32::SendDlgItemMessageW", hDlg, nID, uMsg, wParam, lParam);
}

function GetDlgItemText(nID)
{
  var nTextLen = SendDlgItemMessage(nID, 14 /*WM_GETTEXTLENGTH*/, 0, 0);
  var pText    = "";
  var lpBuffer;

  if (nTextLen)
  {
    lpBuffer = AkelPad.MemAlloc(nTextLen * 2 + 2);
    oSys.Call("User32::GetDlgItemTextW", hDlg, nID, lpBuffer, nTextLen + 1);
    pText = AkelPad.MemRead(lpBuffer, 1 /*DT_UNICODE*/);
    AkelPad.MemFree(lpBuffer);
  }

  return pText;
}

function SetDlgItemText(nID, pText)
{
  oSys.Call("User32::SetDlgItemTextW", hDlg, nID, pText);
}

function IsDlgButtonChecked(nID)
{
  return oSys.Call("User32::IsDlgButtonChecked", hDlg, nID);
}

function CheckDlgButton(nID, bCheck)
{
  oSys.Call("User32::CheckDlgButton", hDlg, nID, bCheck);
}

function SetRedraw(hWnd, bRedraw)
{
	AkelPad.SendMessage(hWnd, 11 /*WM_SETREDRAW*/, bRedraw, 0);
	bRedraw && oSys.Call("User32::InvalidateRect", hWnd, 0, true);
}

function Pad(pString, nLen, pType, pChar)
{
  var i = 0;

  if (! pType) pType = "R";
  if (! pChar) pChar = " ";

  if (pType == "R")
  {
    while (pString.length < nLen)
      pString += pChar;
  }
  else if (pType == "L")
  {
    while (pString.length < nLen)
      pString = pChar + pString;
  }
  else if (pType == "C")
  {
    while (pString.length < nLen)
    {
      if ((i % 2) == 0)
        pString += pChar;
      else
        pString = pChar + pString;
      ++ i;
    }
  }
  return pString;
}

function InsertText()
{
  var nWordWrap = AkelPad.SendMessage(hEditWnd, 3241 /*AEM_GETWORDWRAP*/, 0, 0);

  SetRedraw(hEditWnd, false);
  if (nWordWrap > 0)
    AkelPad.Command(4209 /*IDM_VIEW_WORDWRAP*/);

  var nBegSel  = AkelPad.GetSelStart();
  var nEndSel  = AkelPad.GetSelEnd();
  var nLine1   = AkelPad.SendMessage(hEditWnd, 1078 /*EM_EXLINEFROMCHAR*/, 0, nBegSel);
  var nLine2   = AkelPad.SendMessage(hEditWnd, 1078 /*EM_EXLINEFROMCHAR*/, 0, nEndSel);
  var nLines   = nLine2 - nLine1 + 1;
  var aLinNumL = new Array(nLines);
  var aLinNumR = new Array(nLines);
  var nStep;
  var nIniNum;
  var nLenNum;
  var aLines;
  var pText;
  var i;

  if (pStrA = GetDlgItemText(IDSTRA))
  {
    if (! FindInArray(lpStrsA, pStrA))
    {
      lpStrsA.unshift(pStrA);
      SendDlgItemMessage(IDSTRA, 330 /*CB_INSERTSTRING*/, 0, pStrA);

      if (lpStrsA.length > nStrMax)
      {
        lpStrsA.length = nStrMax;
        SendDlgItemMessage(IDSTRA, 324 /*CB_DELETESTRING*/, nStrMax, 0);
      }
    }
  }

  if (pStrB = GetDlgItemText(IDSTRB))
  {
    if (! FindInArray(lpStrsB, pStrB))
    {
      lpStrsB.unshift(pStrB);
      SendDlgItemMessage(IDSTRB, 330 /*CB_INSERTSTRING*/, 0, pStrB);

      if (lpStrsB.length > nStrMax)
      {
        lpStrsB.length = nStrMax;
        SendDlgItemMessage(IDSTRB, 324 /*CB_DELETESTRING*/, nStrMax, 0);
      }
    }
  }

  pPadLNL  = GetDlgItemText(IDPADLNL);
  pPreLNL  = GetDlgItemText(IDPRELNL);
  pSufLNL  = GetDlgItemText(IDSUFLNL);
  pIniLNL  = GetDlgItemText(IDINILNL);
  pStepLNL = GetDlgItemText(IDSTEPLNL);
  pPadLNR  = GetDlgItemText(IDPADLNR);
  pPreLNR  = GetDlgItemText(IDPRELNR);
  pSufLNR  = GetDlgItemText(IDSUFLNR);
  pIniLNR  = GetDlgItemText(IDINILNR);
  pStepLNR = GetDlgItemText(IDSTEPLNR);

  for (i = 0; i < nLines; ++i)
  {
    aLinNumL[i] = "";
    aLinNumR[i] = "";
  }

  if (bEscNL)
  {
    pStrA = pStrA.replace(/\\n/g, "\r");
    pStrB = pStrB.replace(/\\n/g, "\r");
  }

  if (bEscTab)
  {
    pStrA = pStrA.replace(/\\t/g, "\t");
    pStrB = pStrB.replace(/\\t/g, "\t");
  }

  if (bIsLNL)
  {
    if (pPadLNL == "")
      pPadLNL = " ";

    if (bRelLNL)
    {
      nStep   = parseInt(pStepLNL);
      nIniNum = parseInt(pIniLNL);
      nLenNum = String((nIniNum + nStep * (nLines - 1))).length;
    }
    else
    {
      nStep   = 1;
      nIniNum = nLine1 + 1;
      nLenNum = String(nLine2 + 1).length;
    }

    for (i = 0; i < nLines; ++i)
      aLinNumL[i] = pPreLNL + Pad(String(nIniNum + nStep * i), nLenNum, "L", pPadLNL) + pSufLNL;
  }

  if (bIsLNR)
  {
    if (pPadLNR == "")
      pPadLNR = " ";

    if (bRelLNR)
    {
      nStep   = parseInt(pStepLNR);
      nIniNum = parseInt(pIniLNR);
      nLenNum = String((nIniNum + nStep * (nLines - 1))).length;
    }
    else
    {
      nStep   = 1;
      nIniNum = nLine1 + 1;
      nLenNum = String(nLine2 + 1).length;
    }

    for (i = 0; i < nLines; ++i)
      aLinNumR[i] = pPreLNR + Pad(String(nIniNum + nStep * i), nLenNum, "L", pPadLNR) + pSufLNR;
  }

  // insert in selection
  if (nRange == 0)
    pText = pStrA + aLinNumL[0] +
            (bReplace ? "" : AkelPad.GetSelText(1 /*\r*/)) +
            aLinNumR[nLines - 1] + pStrB;

  // insert in each of selected lines and columnar selection
  else
  {
    if (nRange == 1)
    {
      nEndSel = AkelPad.SendMessage(hEditWnd, 187 /*EM_LINEINDEX*/, nLine2, 0) + AkelPad.SendMessage(hEditWnd, 193 /*EM_LINELENGTH*/, nEndSel, 0);
      AkelPad.SetSel(nBegSel, nEndSel);
    }

    pText  = AkelPad.GetSelText(1 /*\r*/);
    aLines = pText.split("\r");

    for (i = 0; i < nLines; ++i)
      aLines[i] = pStrA + aLinNumL[i] +
                  (bReplace ? "" : aLines[i]) +
                  aLinNumR[i] + pStrB;

    pText = aLines.join("\r");
  }

  AkelPad.ReplaceSel(pText, -1);

  if (((nRange == 0) && bColSel) || (nRange == 2))
    AkelPad.SendMessage(hEditWnd, 3128 /*AEM_UPDATESEL*/, 0x1 /*AESELT_COLUMNON*/, 0);

  if (nWordWrap > 0)
    AkelPad.Command(4209 /*IDM_VIEW_WORDWRAP*/);
  SetRedraw(hEditWnd, true);
}

function FindInArray(lpArray, pText)
{
  for (var i = 0; i < lpArray.length; ++i)
  {
    if (lpArray[i] == pText)
      return true;
  }
  return false;
}

function ReadIni()
{
  var i;

  try
  {
    eval(ReadIni.Text = AkelPad.ReadFile(WScript.ScriptFullName.replace(/\.js$/i, ".ini"), 0x1D /*OD_ADT_BINARY_ERROR|OD_ADT_DETECT_CODEPAGE|OD_ADT_DETECT_BOM|OD_ADT_NOMESSAGES*/));
  }
  catch (oError)
  {}

  if (! lpStrsA)
    lpStrsA = [];
  if (! lpStrsB)
    lpStrsB = [];

  if (lpStrsA.length > nStrMax)
    lpStrsA.length = nStrMax;
  if (lpStrsB.length > nStrMax)
    lpStrsB.length = nStrMax;

  //for compatibility with ver. 2015-01-07
  for (i = lpStrsA.length - 1; i >= 0; --i)
  {
    if (! lpStrsA[i])
      lpStrsA.splice(i, 1);
  }
  for (i = lpStrsB.length - 1; i >= 0; --i)
  {
    if (! lpStrsB[i])
      lpStrsB.splice(i, 1);
  }
}

function WriteIni()
{
  var lpRect = AkelPad.MemAlloc(16); //sizeof(RECT)
  var pText  = 'lpStrsA=[';
  var i;

  oSys.Call("User32::GetWindowRect", hDlg, lpRect);
  oSys.Call("User32::ScreenToClient", hMainWnd, lpRect);
  nDlgX = AkelPad.MemRead(_PtrAdd(lpRect,  0), 3 /*DT_DWORD*/);
  nDlgY = AkelPad.MemRead(_PtrAdd(lpRect,  4), 3 /*DT_DWORD*/);
  AkelPad.MemFree(lpRect);

  for (i = 0; i < lpStrsA.length; ++i)
  {
    pText += '"' + EscapeStr(lpStrsA[i]) + '"';
    if (i < lpStrsA.length - 1)
      pText += ',';
  }
  pText += '];\r\nlpStrsB=[';

  for (i = 0; i < lpStrsB.length; ++i)
  {
    pText += '"' + EscapeStr(lpStrsB[i]) + '"';
    if (i < lpStrsB.length - 1)
      pText += ',';
  }
  pText += '];\r\n';

  pText += 'pStrA="'    + EscapeStr(pStrA)   + '";\r\n' + 
           'pStrB="'    + EscapeStr(pStrB)   + '";\r\n' + 
           'bEscNL='    + bEscNL   + ';\r\n' + 
           'bEscTab='   + bEscTab  + ';\r\n' +
           'bIsLNL='    + bIsLNL   + ';\r\n' +
           'pPadLNL="'  + EscapeStr(pPadLNL) + '";\r\n' + 
           'pPreLNL="'  + EscapeStr(pPreLNL) + '";\r\n' +
           'pSufLNL="'  + EscapeStr(pSufLNL) + '";\r\n' +
           'bRelLNL='   + bRelLNL  + ';\r\n' +
           'pIniLNL="'  + pIniLNL  + '";\r\n' +
           'pStepLNL="' + pStepLNL + '";\r\n' +
           'bIsLNR='    + bIsLNR   + ';\r\n' +
           'pPadLNR="'  + EscapeStr(pPadLNR) + '";\r\n' + 
           'pPreLNR="'  + EscapeStr(pPreLNR) + '";\r\n' +
           'pSufLNR="'  + EscapeStr(pSufLNR) + '";\r\n' +
           'bRelLNR='   + bRelLNR  + ';\r\n' +
           'pIniLNR="'  + pIniLNR  + '";\r\n' +
           'pStepLNR="' + pStepLNR + '";\r\n' +
           'bReplace='  + bReplace + ';\r\n' +
           'nDlgX='     + nDlgX + ';\r\n' +
           'nDlgY='     + nDlgY + ';'

  if (pText != ReadIni.Text) 
    AkelPad.WriteFile(WScript.ScriptFullName.replace(/\.js$/i, ".ini"), pText, pText.length, 1200 /*UTF-16LE*/, true);
}

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