// http://akelpad.sourceforge.net/forum/viewtopic.php?p=18575#18575
// UndoMax.js      v1.3      2012-06-27      (En/Ru)
// Advanced Undo/Redo manipulation.
//
// Usage:  Call("Scripts::Main", 1, "UndoMax.js", "[s[ l[ p]]]")
//    s - settings, integer 0...31, default 0:
//        b00001 (1)  -   undo mode         (0 - after opening, 1 - last/no save)
//        b00010 (2)  -   undo/redo switch      (0 - undo, 1 - redo)
//        b00100 (4)  -   report            (0 - do nothing, 1 - show the number of actions performed upon script completion)
//        b01000 (8)  -   prompt            (0 - do nothing, 1 - request command arguments at startup)
//        b10000 (16) -  shiftkeys         (0 - enable, 1 - disable. use to avoid conflict if you call the script through hot key combination with shift)
//        The report and the prompt can also be activated by shift keys holding in moment of script startup(or by pressing during a pause after startup):
//        Report - left shift key.  Prompt - right shift key.
//    l - limit, specified number of undo/redo actions. Default 0 - maximum actions.
//    p - waiting time of shift pressing after startup, in milliseconds, default 0. Use when calling the script through hot key combination and want to use the shift keys.
// Examples:
//    Call("Scripts::Main", 1, "UndoMax.js", "0")  or  Call("Scripts::Main", 1, "UndoMax.js")
//         Undo all changes made after document opening.
//    Call("Scripts::Main", 1, "UndoMax.js", "1")
//         Undo all changes made since the last save. The same result would Reopen (F5), but need confirmation.
//    Call("Scripts::Main", 1, "UndoMax.js", "2")
//         Redo all changes.
//    Call("Scripts::Main", 1, "UndoMax.js", "1 10")
//         Try to repeat undo 10 times within the last saved.
//    Call("Scripts::Main", 1, "UndoMax.js", "6 7")
//         Try to repeat redo 7 times with report.
//    Call("Scripts::Main", 1, "UndoMax.js", "4")
//         Undo all changes made after document opening with report.
//    Call("Scripts::Main", 1, "UndoMax.js", "28")
//        Prompt with report.
//    Call("Scripts::Main", 1, "UndoMax.js", "1 0 250")
//        Undo all(last save) with a pause 250 ms, for example, to assign hot key combination Alt+U to be able to use the shift keys .

var hMainWnd=AkelPad.GetMainWnd();
var hWndEdit = AkelPad.GetEditWnd();
var oSys = AkelPad.SystemFunction();
var uSettings = 0;
var limit = 0;
var aNamber;
var aReport = "";
var rKey = 0;
var pKey = 0;
var usPause = 0;

if (hMainWnd && hWndEdit)
{
  if(WScript.Arguments.length > 0)
     uSettings = WScript.Arguments(0);
  if(WScript.Arguments.length > 1)
     limit = WScript.Arguments(1);
  if(WScript.Arguments.length > 2)
     usPause = WScript.Arguments(2);
  WScript.Sleep(usPause);
  if (!(uSettings&16))
     {
      pKey = oSys.Call("user32::GetAsyncKeyState", 161/*VK_RSHIFT*/);
      rKey = oSys.Call("user32::GetAsyncKeyState", 160/*VK_LSHIFT*/);
     }
  if ((uSettings&8) || (pKey<0))
    {
     var cpResult = AkelPad.InputBox(hMainWnd, "UndoMax.js", GetLangString(0) + (uSettings&3) + " " + limit + ")", "")
     if (cpResult)
        {
         var arrResult = cpResult.split(' ');
         if (arrResult[0])   uSettings = ((uSettings&4) | arrResult[0]);
         if (arrResult[1])   limit = arrResult[1];
         else limit = 0;
        }
     else if (cpResult === undefined)
         WScript.Quit();
    }
  if (limit == 0) limit = Number.MAX_VALUE;
  aNamber = (uSettings&2)?uniRedo(limit):uniUndo((uSettings&1), limit);
  if ((uSettings&4) || (rKey<0))
    {
     aReport += (uSettings&2)?"Redo":"Undo";
     aReport += GetLangString(1) + aNamber;
     AkelPad.MessageBox(hMainWnd, aReport, "UndoMax.js", 64 /*MB_OK, MB_ICONINFORMATION*/);
    }
}

function uniUndo(mod, lim)
{
  var n = 0;
  if (((!(mod&1)) && AkelPad.SendMessage(hWndEdit, 3075 /*AEM_CANUNDO*/, 0, 0)) || (AkelPad.SendMessage(hWndEdit, 3086 /*AEM_GETMODIFY*/, 0, 0) && (mod&1)))
  {
    SetRedraw(hWndEdit, false);
    AkelPad.SendMessage(hWndEdit, 3185 /*AEM_LOCKSCROLL*/, 3 /*SB_BOTH*/, true);
    while (AkelPad.SendMessage(hWndEdit, 3075 /*AEM_CANUNDO*/, 0, 0))
    {
      if ( (!AkelPad.SendMessage(hWndEdit, 3086 /*AEM_GETMODIFY*/, 0, 0) && (mod&1)) || (n >= lim) )
        break;
      AkelPad.SendMessage(hWndEdit, 3077 /*AEM_UNDO*/, 0, 0);
      ++n;
    }
    AkelPad.SendMessage(hWndEdit, 3185 /*AEM_LOCKSCROLL*/, 3 /*SB_BOTH*/, false);
    SetRedraw(hWndEdit, true);
  }
  return n;
}

function uniRedo(lim)
{
  var n = 0;
  if (AkelPad.SendMessage(hWndEdit, 3076 /*AEM_CANREDO*/, 0, 0))
  {
    SetRedraw(hWndEdit, false);
    AkelPad.SendMessage(hWndEdit, 3185 /*AEM_LOCKSCROLL*/, 3 /*SB_BOTH*/, true);
    while (AkelPad.SendMessage(hWndEdit, 3076 /*AEM_CANREDO*/, 0, 0))
    {
      if (n >= lim)
        break;
      AkelPad.SendMessage(hWndEdit, 3078 /*AEM_REDO*/, 0, 0);
      ++n;
    }
    AkelPad.SendMessage(hWndEdit, 3185 /*AEM_LOCKSCROLL*/, 3 /*SB_BOTH*/, false);
    SetRedraw(hWndEdit, true);
  }
  return n;
}

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

function GetLangString(nStringID)
{
  var nLangID=AkelPad.GetLangId(1 /*LANGID_PRIMARY*/);
  if (nLangID == 0x19) //LANG_RUSSIAN
  {
    if (nStringID == 0)
      return "\u0412\u0432\u0435\u0434\u0438\u0442\u0435\u0020\u043D\u043E\u0432\u044B\u0435\u0020\u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B\u003A\u0020\u0053\u0020\u005B\u004C\u005D\u000D\u000A\u0053\u0020\u002D\u0020\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435\u0020\u0028\u0030\u0020\u002D\u0020\u0075\u006E\u0064\u006F\u003B\u0020\u0031\u0020\u002D\u0020\u0075\u006E\u0064\u006F\u0020\u0434\u043E\u0020\u0441\u043E\u0445\u0440\u0430\u043D\u0435\u043D\u0438\u044F\u003B\u0020\u0032\u0020\u002D\u0020\u0072\u0065\u0064\u006F\u0029\u000D\u000A\u004C\u0020\u002D\u0020\u043A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E\u0020\u043F\u043E\u0432\u0442\u043E\u0440\u043E\u0432\u0020\u0028\u043C\u0430\u043A\u0441\u0438\u043C\u0443\u043C\u0020\u0435\u0441\u043B\u0438\u0020\u043D\u0435\u0020\u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u043E\u0029\u000D\u000A\u0028\u004F\u004B\u0020\u002D\u0020\u0442\u0435\u043A\u0443\u0449\u0438\u0435\u002E\u0020\u0043\u0061\u006E\u0063\u0065\u006C\u0020\u002D\u0020\u0432\u044B\u0445\u043E\u0434\u002E\u0020\u0422\u0435\u043A\u0443\u0449\u0438\u0435\u003A\u0020";
    if (nStringID == 1)
      return "\u0020\u0432\u044B\u043F\u043E\u043B\u043D\u0435\u043D\u043E\u003A\u0020";
  }
  else
  {
    if (nStringID == 0)
      return "Enter new script arguments: A [N]\nA - action (0 - undo; 1 - undo last save; 2 - redo)\nN - reiteration number (maximum if not specified)\n(OK - current, Cancel - exit. Current: ";
    if (nStringID == 1)
      return " actions: ";
  }
  return "";
}