/// Generate/Verify MD5 checksum of files
//  use the lastest version of MD5dll.dll, which is a plugin of NSIS from http://nsis.sourceforge.net/mediawiki/images/d/d7/Md5dll.zip
//  Download it and place unicode version of md5dll.dll into "AkelPad\AkelFiles\Tools\Md5dll\".
//
//  "MD5Files" Call("Scripts::Main", 1, "MD5Files.js")
//  
//  Usage: Select a fileslist and run this script. The filelist may be in fullpath, like
//           d:\TotalCMD\AkelPad\AkelFiles\Docs\Scripts-Eng.txt
//           d:\TotalCMD\AkelPad\AkelFiles\Docs\AkelHistory-Eng.txt
//           d:\TotalCMD\AkelPad\AkelFiles\Docs\AkelHelp-Eng.htm
//  
//         or without path, but in file like "d:\TotalCMD\AkelPad\AkelFiles\Docs\Docs.lst",
//           Scripts-Eng.txt
//           AkelHistory-Eng.txt
//           AkelHelp-Eng.htm
//  
//         MD5Files.js will "think" the location of files of list be in the same folder as "Docs.lst".
//
//  Note: If the selection of all files not exist, or the MD5 checksum list all OK or the result same as before,
//        MD5Files.js will not make any change.


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

var nInitialSelStart=AkelPad.GetSelStart();
var nInitialSelEnd=AkelPad.GetSelEnd();

if (nInitialSelStart != nInitialSelEnd)
{
  var oSys=AkelPad.SystemFunction();
  
  //NSIS
  var NSIS_MAX_STRLEN=1024;
  //var nNsisUnicode=0 /*DT_ANSI*/;
  var nNsisUnicode=1 /*DT_UNICODE*/;
  var lpStack=0;

  var hWndEdit = AkelPad.GetEditWnd();

  if (AkelPad.IsAkelEdit()) AkelPad.SendMessage(hWndEdit, 3185 /*AEM_LOCKSCROLL*/, 3 /*SB_BOTH*/, true);

  SetRedraw(hWndEdit, false);
  //  SelCompleteLine(hWndEdit, nInitialSelStart, nInitialSelEnd);
  var nSelStart=AkelPad.GetSelStart();
  var pSelText =AkelPad.GetSelText(2);
  var pLinesArray=pSelText.split("\n");
  var nIndex=-1;
  var bModified=false;
  var fso=new ActiveXObject("Scripting.FileSystemObject");
  var pParentFolder=fso.GetParentFolderName(AkelPad.GetEditFile(0))+"\\";

  while (++nIndex < pLinesArray.length)
  {
    if (fso.FileExists(pLinesArray[nIndex]))
    {
      pLinesArray[nIndex]=GetMD5File(pLinesArray[nIndex]) + " *" + pLinesArray[nIndex];
      bModified=true;
    }
    else if (fso.FileExists(pParentFolder+pLinesArray[nIndex]))
    {
      pLinesArray[nIndex]=GetMD5File(pParentFolder+pLinesArray[nIndex]) + " *" + pLinesArray[nIndex];
      bModified=true;
    }
    else
    {
      pLineArray=pLinesArray[nIndex].split(" *");
      pLineArray[0]=pLineArray[0].toLowerCase();

      if (fso.FileExists(pLineArray[1]))
      {
        pLineArray[2]=GetMD5File(pLineArray[1]);

        if (pLineArray[2]!=pLineArray[0])
        {
          pLinesArray[nIndex]=/*"________________________________\n" + pLineArray[0] +"\n" +*/ pLineArray[2] + " *" + pLineArray[1];
          bModified=true;
        }
      }
      else if (fso.FileExists(pParentFolder+pLineArray[1]))
      {
        pLineArray[2]=GetMD5File(pParentFolder+pLineArray[1]);

        if (pLineArray[2]!=pLineArray[0])
        {
          pLinesArray[nIndex]=/*"________________________________\n" + pLineArray[0] +"\n" +*/ pLineArray[2] + " *" + pLineArray[1];
          bModified=true;
        }
      }
      else if (fso.FileExists(pLineArray[0]))
      {
        pLinesArray[nIndex]=GetMD5File(pLineArray[0])+ " *" + pLineArray[0];
        bModified=true;
      }
      else if (fso.FileExists(pParentFolder+pLineArray[0]))
      {
        pLinesArray[nIndex]=GetMD5File(pParentFolder+pLineArray[0])+ " *" + pLineArray[0];
        bModified=true;
      }
    }
  }
  pSelText=pLinesArray.join("\n");

  if (bModified)
  {
    AkelPad.ReplaceSel(pSelText);
    nSelEnd=AkelPad.GetSelEnd();
    AkelPad.SetSel(nSelStart,nSelEnd);
  }
  else
  {
    AkelPad.SetSel(nInitialSelStart,nInitialSelEnd);
  }

  if (AkelPad.IsAkelEdit()) AkelPad.SendMessage(hWndEdit, 3185 /*AEM_LOCKSCROLL*/, 3 /*SB_BOTH*/, false);

  SetRedraw(hWndEdit, true);
}


//Functions
function GetMD5File(lpFileName)
{
  pushstring(lpFileName);
  nsiscall(".\\AkelFiles\\Tools\\Md5dll\\md5dll.dll::GetMD5File");
  return popstring();
}

function nsiscall(pFunction)
{
  var lppStack;

  if (lppStack=AkelPad.MemAlloc(4 /*DWORD*/))
  {
    AkelPad.MemCopy(lppStack, lpStack, 3 /*DT_DWORD*/);
    oSys.Call(pFunction, hMainWnd, NSIS_MAX_STRLEN, 0, lppStack);
    lpStack=AkelPad.MemRead(lppStack, 3 /*DT_DWORD*/);
    AkelPad.MemFree(lppStack);
  }
}

function pushstring(pString)
{
  var lpTop;

  if (lpTop=oSys.Call("kernel32::GlobalAlloc", 0x40 /*GPTR*/, (nNsisUnicode?NSIS_MAX_STRLEN * 2:NSIS_MAX_STRLEN) + 8 /*sizeof(stack_t)*/))
  {
    AkelPad.MemCopy(lpTop + 4 /*stack_t.text*/, pString.substr(0, NSIS_MAX_STRLEN), nNsisUnicode);
    AkelPad.MemCopy(lpTop + 0 /*stack_t.next*/, lpStack, 3 /*DT_DWORD*/);
    lpStack=lpTop;
  }
}

function popstring(pString)
{
  var lpTop;
  var pString="";

  if (lpStack)
  {
    lpTop=lpStack;
    pString=AkelPad.MemRead(lpTop + 4 /*stack_t.text*/, nNsisUnicode);
    lpStack=AkelPad.MemRead(lpTop + 0 /*stack_t.next*/, 3 /*DT_DWORD*/);
    oSys.Call("kernel32::GlobalFree", lpTop);
  }
  return pString;
}

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

function SelCompleteLine(hWnd, nMinSel, nMaxSel)
{
  if (nMinSel < nMaxSel)
  {
    var nMinLine=AkelPad.SendMessage(hWnd, 1078 /*EM_EXLINEFROMCHAR*/, 0, nMinSel);
    var nMaxLine=AkelPad.SendMessage(hWnd, 1078 /*EM_EXLINEFROMCHAR*/, 0, nMaxSel);
    var nMinLineIndex=AkelPad.SendMessage(hWnd, 187 /*EM_LINEINDEX*/, nMinLine, 0);
    var nMaxLineIndex=AkelPad.SendMessage(hWnd, 187 /*EM_LINEINDEX*/, nMaxLine, 0);
    var nMaxLineLength=AkelPad.SendMessage(hWnd, 193 /*EM_LINELENGTH*/, nMaxSel, 0);

    if (nMaxLineIndex == nMaxSel) --nMaxLine;
    else if (nMaxLineLength) nMaxSel=nMaxLineIndex + nMaxLineLength + 1;
    nMinSel=nMinLineIndex;

    AkelPad.SetSel(nMinSel, nMaxSel);
    return nMaxLine - nMinLine + 1;
  }
  return 0;
}
