//// 支持正则表达式的批量替换处理。
//

try
{
  var hMainWnd=AkelPad.GetMainWnd();
}
catch (oError)
{
  WScript.Quit();
}

if (!(AkelPad.Include("sr_function.js")))
{
  WScript.Quit();
}

//选项
var bShowCountOfChanges=false;
var nFilterIndex=2;

//按钮
var BT_REPLACEALL =4;

//方向
var DN_DOWN      =0x00000001;
var DN_UP        =0x00000002;
var DN_BEGINNING =0x00000004;
var DN_SELECTION =0x00000008;
var DN_ALLFILES  =0x00000010;

var pScriptName=WScript.ScriptName;
var pInitialFile=AkelPad.GetAkelDir(5) + "\\Params\\" + pScriptName.substring(0, pScriptName.lastIndexOf("."));

var pFile;

var WshShell = new ActiveXObject("WScript.shell");
var fso = new ActiveXObject("Scripting.FileSystemObject");
var oSys=AkelPad.SystemFunction();
var nAkelEdit=AkelPad.IsAkelEdit();

var pFindIt;
var pReplaceWith;
var pReplaceWithEsc;
var pStringsArray;
var bRegExp           =1;
var bSensitive        =0;
var bMultiline        =0;
var bEscSequences     =0;
var bReplaceFunction  =0;
var nDirection        =0;
var nDirectionFirst   =0;
var bDescription      =false;
var bOptions          =false;
var bSearchReplace    =false;
var bSearchReplaceAll =false;

var nButton           =BT_REPLACEALL;

var STRID_FILTER       =21;
var STRID_SYNTAXERROR  =22;
var STRID_SAME         =23;
var STRID_COUNTFILES   =24;
var STRID_COUNTCHANGES =25;
var STRID_ERROROPTIONS =26;

var nFilterIndex=2;

var oPattern;
var pSelText;
var nInitialSelStart;
var nInitialSelEnd;
var nSelStart;
var nSelEnd;
var lpInitialScroll;
var nMatches=0;
var nChangesCur=0;
var nChanges=0;
var nChangedFiles=0;
var nResult=-1;
var i;

if (WScript.Arguments.length)
{
  if (WScript.Arguments(0)=='-pExt="ini"')
  {
    if (! AkelPad.Include("ShowMenuEx.js"))
    {
      WScript.Quit();
    }
    pFile = getEnvironmentPath(pInitialFile+"\\" + getSelectedMenuItem(POS_CURSOR, false));
    if (!pFile)
    {
      WScript.Quit();
    }
  }
  else
  {
    pFile = getEnvironmentPath(pInitialFile+"\\" + WScript.Arguments(0));
    if (!pFile)
    {
      if (pFile=FileDialog(true, hMainWnd, pInitialFile+"\\*", GetLangString(STRID_FILTER), nFilterIndex))
      {
      }
      else
      {
        WScript.Quit();
      }
    }
  }
}
else
{
  if (! AkelPad.Include("ShowMenuEx.js"))
  {
    WScript.Quit();
  }
  pFile = getEnvironmentPath(pInitialFile+"\\" + getSelectedMenuItem(POS_CURSOR, false));
  WScript.Echo(pFile);
  if (!pFile)
  {
    WScript.Quit();
  }
}

var pText;

if (!(pText=AkelPad.ReadFile(pFile)))
{
  WScript.Quit();
}

pText=pText.replace(/\r\n|\r|\n/g, "\r");
var pLinesArray   =pText.split("\r");

var lpFrameInit=AkelPad.SendMessage(hMainWnd, 1288 /*AKD_FRAMEFIND*/, 1 /*FWF_CURRENT*/, 0);
var hWndEdit=AkelPad.GetEditWnd();

var d=new Date();
var t=d.getTime();

for (;;)
{
  try
  {
    var nIndex=-1;

    while (++nIndex < pLinesArray.length-1)
    {
      pFindIt=null;
      pReplaceWith=null;
      pReplaceWithEsc=null;
      pStringsArray=null;
      CollectGarbage();

      if (!bSearchReplaceAll)
      {
        if (pLinesArray[nIndex]=="[SearchReplaceAll]")
        {
          bSearchReplaceAll=true;

          MakeSelection();

          continue;
        }
        else if (pLinesArray[nIndex]=="[Description]")
        {
          bDescription=true;
          bOptions=false;
          bSearchReplace=false;
          continue;
        }
        else if (pLinesArray[nIndex]=="[Options]")
        {
          bDescription=false;
          bOptions=true;
          bSearchReplace=false;
          continue;
        }
        else if (pLinesArray[nIndex]=="[SearchReplace]")
        {
          bDescription=false;
          bOptions=false;
          bSearchReplace=true;
          continue;
        }
        else
        {
          if (bDescription)
          {
            continue;
          }
          else if (bOptions)
          {
            if (pLinesArray[nIndex]=="RegExp=1")
            {
              bRegExp=1;
            }
            else if (pLinesArray[nIndex]=="RegExp=0")
            {
              bRegExp=0;
            }
            else if (pLinesArray[nIndex]=="Sensitive=1")
            {
              bSensitive=1;
            }
            else if (pLinesArray[nIndex]=="Sensitive=0")
            {
              bSensitive=0;
            }
            else if (pLinesArray[nIndex]=="Multiline=1")
            {
              bMultiline=1;
            }
            else if (pLinesArray[nIndex]=="Multiline=0")
            {
              bMultiline=0;
            }
            else if (pLinesArray[nIndex]=="EscSequences=1")
            {
              bEscSequences=1;
            }
            else if (pLinesArray[nIndex]=="EscSequences=0")
            {
              bEscSequences=0;
            }
            else if (pLinesArray[nIndex]=="ReplaceFunction=1")
            {
              bReplaceFunction=1;
            }
            else if (pLinesArray[nIndex]=="ReplaceFunction=0")
            {
              bReplaceFunction=0;
            }
            else if (pLinesArray[nIndex]=="Direction=1")
            {
              nDirection=1;
            }
            else if (pLinesArray[nIndex]=="Direction=2")
            {
              nDirection=2;
            }
            else if (pLinesArray[nIndex]=="Direction=4")
            {
              nDirection=4;
            }
            else if (pLinesArray[nIndex]=="Direction=8")
            {
              nDirection=8;
            }
            else if (pLinesArray[nIndex]=="Direction=16")
            {
              nDirection=16;
            }

            if (nDirectionFirst)
            {
              nDirection=nDirectionFirst;
            }
            else
            {
              if (nDirection)
              {
                if (nDirection==DN_DOWN || nDirection==DN_UP || nDirection==DN_BEGINNING || nDirection==DN_SELECTION || nDirection==DN_ALLFILES)
                {
                }
                else
                {
                  nDirection=DN_BEGINNING;
                }
                nDirectionFirst=nDirection;
              }
            }
            continue;
          }
          else if (bSearchReplace)
          {
            MakeSelection();
          }
          else
          {
            continue;
          }
        }
      }

      pStringsArray=pLinesArray[nIndex].split("\t");
      pFindIt=pStringsArray[0];
      if (pStringsArray[1])
      {
        pReplaceWith=pStringsArray[1];
      }
      else
      {
        pReplaceWith="";
      }

      if (pFindIt=="")
      {
        continue;
      }

      if (bSensitive && pFindIt==pReplaceWith)
      {
        MessageBox(hMainWnd, GetLangString(STRID_SAME)+(nIndex+1).toString(), pScriptName, 64 /*MB_ICONINFORMATION*/);
        continue;
      }

      if (bRegExp && AkelPad.Include("cnRegExp.js"))
      {
        pFindIt=cnRegExp(pFindIt);
      }

      try
      {
        oPattern=new RegExp((bRegExp?pFindIt:EscRegExp(pFindIt)), (bSensitive?"":"i") + ((nButton == BT_REPLACEALL || nDirection & DN_UP)?"g":"") + (bMultiline?"m":""));
      }
      catch (oError)
      {
        MessageBox(hMainWnd, oError.description, pScriptName, 16 /*MB_ICONERROR*/);
        continue;
      }

      if (nChangesCur)
      {
        if (bShowCountOfChanges)
        {
          nMatches=pSelText.match(oPattern);
          nMatches=nMatches?nMatches.length:0;
          nChangesCur+=nMatches;
        }
      }
      else
      {
        nMatches=pSelText.match(oPattern);
        nMatches=nMatches?nMatches.length:0;
        nChangesCur+=nMatches;
      }

      if (nMatches)
      {
        pReplaceWithEsc=pReplaceWith;
        if (bRegExp && bReplaceFunction)
        {
          //使用函数替换: Infocatcher 写的代码。
          if (!/(^|[^\w.])return(\s+\S|\s*\()/.test(pReplaceWithEsc))
          {
            pReplaceWithEsc="return " + pReplaceWithEsc;
          }
          pReplaceWithEsc='var args={}, l=arguments.length;'
                        + 'for (var i=0; i < l; i+=1)\n'
                        + '  args["$" + i]=arguments[i];\n'
                        + 'args.offset=arguments[l - 2];\n'
                        + 'args.s=arguments[l - 1];\n'
                        + 'with (args)\n'
                        + '{\n'
                        +    pReplaceWithEsc
                        + '\n}';
          try
          {
            pReplaceWithEsc=new Function(pReplaceWithEsc);
          }
          catch (oError)
          {
            MessageBox(hMainWnd, oError.description, pScriptName, 16 /*MB_ICONERROR*/);
            WScript.Quit();
          }
        }
        else if (bEscSequences)
        {
          if (!bRegExp)
          {
            if (!(pFindIt=TranslateEscapeString(pFindIt)))
            {
              MessageBox(hMainWnd, GetLangString(STRID_SYNTAXERROR), pScriptName, 16 /*MB_ICONERROR*/);
              WScript.Quit();
            }
          }
        }

        if (!bReplaceFunction && pReplaceWithEsc)
        {
          if (bEscSequences)
          {
            pReplaceWithEsc=pReplaceWithEsc.replace(/\\\\/g, "\0");

            if (bRegExp && pFindIt.search(/\([^\(\)]*?\)/g) != -1)
            {
              if (pReplaceWithEsc.search(/\\[^rnt1-9]/g) != -1)
              {
                MessageBox(hWndDialog, GetLangString(STRID_SYNTAXERROR), pScriptName, 16 /*MB_ICONERROR*/);
                oSys.Call("user32::SetFocus", hWndWith);
                WScript.Quit();
              }
            }
            else
            {
              if (pReplaceWithEsc.search(/\\[^rnt]/g) != -1)
              {
                MessageBox(hWndDialog, GetLangString(STRID_SYNTAXERROR), pScriptName, 16 /*MB_ICONERROR*/);
                oSys.Call("user32::SetFocus", hWndWith);
                WScript.Quit();
              }
            }

            pReplaceWithEsc=pReplaceWithEsc.replace(/\\r\\n|\\r|\\n/g, "\n");
            pReplaceWithEsc=pReplaceWithEsc.replace(/\\t/g, "\t");
          }

          if (bRegExp && pFindIt.search(/\([^\(\)]*?\)/g) != -1)
          {
            pReplaceWithEsc=pReplaceWithEsc.replace(/\\(\d)/g,"$$$1");
          }

          if (bEscSequences)
          {
            pReplaceWithEsc=pReplaceWithEsc.replace(/\0/g, "\\");
          }
        }
        pSelText=pSelText.replace(oPattern, pReplaceWithEsc);
      }
    }

    if (nChangesCur)
    {
      if (bShowCountOfChanges)
      {
        nChangedFiles+=1;
        nChanges+=nChangesCur;
        nChangesCur=0;
      }

      var nFirstLine;
      var nInitialLine;
      var nInitialCharInLine;

      //保存选定范围
      nFirstLine=SaveLineScroll(hWndEdit);
      nInitialLine=AkelPad.SendMessage(hWndEdit, 1078 /*EM_EXLINEFROMCHAR*/, 0, nInitialSelStart);
      nInitialCharInLine=nInitialSelStart - AkelPad.SendMessage(hWndEdit, 187 /*EM_LINEINDEX*/, nInitialLine, 0);

      //替换选定范围
      if (nAkelEdit)
      {
        if (nDirection & DN_SELECTION)
        {
          if (AkelPad.SendMessage(hWndEdit, 3127 /*AEM_GETCOLUMNSEL*/, 0, 0))
          {
            dwOptions=AkelPad.SendMessage(hWndEdit, 3227 /*AEM_GETOPTIONS*/, 0, 0);
            if (!(dwOptions & 0x40 /*AECO_PASTESELECTCOLUMN*/))
            {
              AkelPad.SendMessage(hWndEdit, 3228 /*AEM_SETOPTIONS*/, 2 /*AECOOP_OR*/, 0x40 /*AECO_PASTESELECTCOLUMN*/);
            }
            AkelPad.ReplaceSel(pSelText);
            if (!(dwOptions & 0x40 /*AECO_PASTESELECTCOLUMN*/))
            {
              AkelPad.SendMessage(hWndEdit, 3228 /*AEM_SETOPTIONS*/, 4 /*AECOOP_XOR*/, 0x40 /*AECO_PASTESELECTCOLUMN*/);
            }
          }
          else
          {
            AkelPad.ReplaceSel(pSelText);
            AkelPad.SetSel(nSelStart, nSelStart + pSelText.length, 0x8 /*AESELT_LOCKSCROLL*/);
          }
        }
        else
        {
          AkelPad.SetSel(nSelStart, nSelEnd, 0x8 /*AESELT_LOCKSCROLL*/);

          //替换选区
          AkelPad.ReplaceSel(pSelText);

          i=AkelPad.SendMessage(hWndEdit, 187 /*EM_LINEINDEX*/, nInitialLine, 0) + nInitialCharInLine;
          AkelPad.SetSel(i, i + (nInitialSelEnd - nInitialSelStart), 0x8 /*AESELT_LOCKSCROLL*/);
        }
        pSelText=null;
        CollectGarbage();
      }

      RestoreLineScroll(hWndEdit, nFirstLine);
    }

    if (nDirection & DN_ALLFILES)
    {
      nDirection&=~DN_DOWN;
      //下一个 MDI 帧
      lpFrameCur=AkelPad.Command(4316 /*IDM_WINDOW_FRAMENEXT*/);
      hWndEdit=AkelPad.GetEditWnd();

      if (lpFrameCur != lpFrameInit)
      {
        continue;
      }
    }

    if (bShowCountOfChanges)
    {
      if (nDirection & DN_ALLFILES)
      {
        MessageBox(hMainWnd, GetLangString(STRID_COUNTFILES) + nChangedFiles + "\n" + GetLangString(STRID_COUNTCHANGES) + nChanges, pScriptName, 64 /*MB_ICONINFORMATION*/);
      }
      else
      {
        MessageBox(hMainWnd, GetLangString(STRID_COUNTCHANGES) + nChanges, pScriptName, 64 /*MB_ICONINFORMATION*/);
      }
    }
  }
  catch (oError)
  {
    MessageBox(hMainWnd, oError.description, pScriptName, 16 /*MB_ICONERROR*/);
  }
  break;
}
var d=new Date();
t=(d.getTime()-t)/1000;

if (Math.round(t)>1)
{
  MessageBox(hMainWnd, "    "+t.toFixed(3)+" s", pScriptName, 0 /*MB_OK*/);
}


//函数
function FileDialog(bOpenTrueSaveFalse, hWnd, pInitialFile, pFilter, nFilterIndex)
{
  var nFlags=0x880804; //OFN_HIDEREADONLY|OFN_PATHMUSTEXIST|OFN_EXPLORER|OFN_ENABLESIZING
  var pDefaultExt="txt";
  var lpStructure;
  var lpFilterBuffer;
  var lpFileBuffer;
  var lpExtBuffer;
  var oSys;
  var pResultFile="";
  var nCallResult;

  if (lpFilterBuffer=AkelPad.MemAlloc(256 * _TSIZE))
  {
    AkelPad.MemCopy(lpFilterBuffer, pFilter.substr(0, 255), _TSTR);

    if (lpFileBuffer=AkelPad.MemAlloc(256 * _TSIZE))
    {
      AkelPad.MemCopy(lpFileBuffer, pInitialFile.substr(0, 255), _TSTR);

      if (lpExtBuffer=AkelPad.MemAlloc(256 * _TSIZE))
      {
        AkelPad.MemCopy(lpExtBuffer, pDefaultExt.substr(0, 255), _TSTR);

        if (lpStructure=AkelPad.MemAlloc(_X64?136:76))  //sizeof(OPENFILENAMEA) or sizeof(OPENFILENAMEW)
        {
          //Fill structure
          AkelPad.MemCopy(lpStructure, _X64?136:76, 3 /*DT_DWORD*/);                     //lStructSize
          AkelPad.MemCopy(lpStructure + (_X64?8:4), hWnd, 2 /*DT_QWORD*/);               //hwndOwner
          AkelPad.MemCopy(lpStructure + (_X64?24:12), lpFilterBuffer, 2 /*DT_QWORD*/);   //lpstrFilter
          AkelPad.MemCopy(lpStructure + (_X64?44:24), nFilterIndex, 3 /*DT_DWORD*/);     //nFilterIndex
          AkelPad.MemCopy(lpStructure + (_X64?48:28), lpFileBuffer, 2 /*DT_QWORD*/);     //lpstrFile
          AkelPad.MemCopy(lpStructure + (_X64?56:32), 256, 3 /*DT_DWORD*/);              //nMaxFile
          AkelPad.MemCopy(lpStructure + (_X64?96:52), nFlags, 3 /*DT_DWORD*/);           //Flags
          AkelPad.MemCopy(lpStructure + (_X64?104:60), lpExtBuffer, 2 /*DT_QWORD*/);     //lpstrDefExt

          if (oSys=AkelPad.SystemFunction())
          {
            //Call dialog
            if (bOpenTrueSaveFalse == true)
            {
              nCallResult=oSys.Call("comdlg32::GetOpenFileName" + _TCHAR, lpStructure);
            }
            else
            {
              nCallResult=oSys.Call("comdlg32::GetSaveFileName" + _TCHAR, lpStructure);
            }

            //Result file
            if (nCallResult)
            {
              pResultFile=AkelPad.MemRead(lpFileBuffer, _TSTR);
            }
          }
          AkelPad.MemFree(lpStructure);
        }
        AkelPad.MemFree(lpExtBuffer);
      }
      AkelPad.MemFree(lpFileBuffer);
    }
    AkelPad.MemFree(lpFilterBuffer);
  }
  return pResultFile;
}

function getEnvironmentPath(paths)
{
  var path = WshShell.ExpandEnvironmentStrings(paths);
  if (fso.FileExists(path))
  {
    return path;
  }
  return "";
}


function MakeSelection()
{
  if (nDirectionFirst)
  {
    if (nDirection!=nDirectionFirst)
    {
      nDirection=nDirectionFirst;
    }
  }
  else
  {
    if (nDirection==DN_DOWN || nDirection==DN_UP || nDirection==DN_BEGINNING || nDirection==DN_SELECTION || nDirection==DN_ALLFILES)
    {
    }
    else
    {
      nDirection=DN_BEGINNING;
    }
    nDirectionFirst=nDirection;
  }

  if (pSelText==undefined || pSelText==null)
  {
    nInitialSelStart=AkelPad.GetSelStart();
    nInitialSelEnd=AkelPad.GetSelEnd();

    //获取范围
    if (nDirection & DN_DOWN)
    {
      nSelStart=nInitialSelStart;
      nSelEnd=-1;
    }
    else if (nDirection & DN_UP)
    {
      nSelStart=0;
      nSelEnd=nInitialSelEnd;
    }
    else if (nDirection & DN_BEGINNING)
    {
      nSelStart=0;
      nSelEnd=-1;
    }
    else if (nDirection & DN_SELECTION)
    {
      if (AkelPad.SendMessage(hWndEdit, 3125 /*AEM_GETSEL*/, 0, 0))
      {
        nSelStart=nInitialSelStart;
        nSelEnd=nInitialSelEnd;
      }
      else
      {
        nSelStart=0;
        nSelEnd=-1;
        nDirection=DN_BEGINNING;
      }
    }
    else if (nDirection & DN_ALLFILES)
    {
      nSelStart=0;
      nSelEnd=-1;
    }

    if (nAkelEdit && AkelPad.SendMessage(hWndEdit, 3127 /*AEM_GETCOLUMNSEL*/, 0, 0) && (nDirection & DN_SELECTION))
    {
      pSelText =AkelPad.GetSelText(2);
    }
    else
    {
      pSelText=AkelPad.GetTextRange(nSelStart, nSelEnd, 2 /*\n*/);
    }
  }

  if (bRegExp != 0)
  {
    bRegExp=1;
  }
  if (bSensitive != 1)
  {
    bSensitive=0;
  }
  if (bMultiline != 1)
  {
    bMultiline=0;
  }
  if (bEscSequences != 1)
  {
    bEscSequences=0;
  }
  if (bReplaceFunction != 1)
  {
    bReplaceFunction=0;
  }
  else
  {
    bEscSequences=0;
  }

  if (nButton!=BT_REPLACEALL)
  {
    nButton=BT_REPLACEALL;
  }
}


function GetLangString(nStringID)
{
  var nLangID=AkelPad.GetLangId(1 /*LANGID_PRIMARY*/);

  if (nLangID == 0x4) //LANG_CHINESE
  {
    if (nStringID == STRID_FILTER)
    {
      return "所有文件 (*.*)\x00*.*\x00文本文件 (*.txt)\x00*.txt\x00\x00";
    }
    if (nStringID == STRID_SYNTAXERROR)
    {
      return "语法错误:\n \\\\ - 反斜线\n \\r - 换行符\n \\t - 制表符";
    }
    if (nStringID == STRID_SAME)
    {
      return "查找内容与替换内容相同。行号为: ";
    }
    if (nStringID == STRID_COUNTFILES)
    {
      return "替换文件数: ";
    }
    if (nStringID == STRID_COUNTCHANGES)
    {
      return "替换次数: ";
    }
    if (nStringID == STRID_ERROROPTIONS)
    {
      return "选项错误。行号为: ";
    }
  }
  else
  {
    if (nStringID == STRID_FILTER)
    {
      return "All Files (*.*)\x00*.*\x00Text files (*.txt)\x00*.txt\x00\x00";
    }
    if (nStringID == STRID_SYNTAXERROR)
    {
      return "Syntax error:\n \\\\ - backslash\n \\r - line feed\n \\t - tabulation";
    }
    if (nStringID == STRID_SAME)
    {
      return "the content of Find equal to Replace's. Line #: ";
    }
    if (nStringID == STRID_COUNTFILES)
    {
      return "Changed files: ";
    }
    if (nStringID == STRID_COUNTCHANGES)
    {
      return "Count of changes: ";
    }
    if (nStringID == STRID_ERROROPTIONS)
    {
      return "Options error. Line #: ";
    }
  }
  return "";
}