// http://akelpad.sourceforge.net/forum/viewtopic.php?p=22834#22834
// Version: 2016-01-23
// Author: KDJ
//
// *** Changes main window title ***
// 
// Usage:
//   Call("Scripts::Main", 1, "AkelPadTitle.js", '-t="NoEditMDIPattern" -t0="NoFilePattern" -t1="FilePattern" -m="ModifiedString"')
//   Call("Scripts::Main", 1, "AkelPadTitle.js", "1") - run script with default all arguments
//   Call("Scripts::Main", 1, "AkelPadTitle.js") - without arguments - closes the script
// 
// Arguments:
//   -t  - title pattern for MDI mode without edit window, default is: -t="%%e"
//   -t0 - title pattern for empty tab without opened file, default is: -t0="%%mnew - %%e"
//   -t1 - title pattern for tab with opened file, default is: -t1="%%m%%F - %%e"
//   -m  - modified flag string, default is asterisk: -m="*"
//   -a  - text displayed, if AkelPad is running as administrator (Win-Vista+), default is: -a="Admin"
// 
//   -t, -t0, -t1 can contain:
//   %%f      - current file name without the path
//   %%F      - full file name with the path (eg: "C:\Programs\TextEditors\AkelPad\AkelFiles\Plugs\Scripts\Include\ShowMenu.js")
//   %%F{n}   - last n elements in file path (for example: %%F{-3} shows "...\Scripts\Include\ShowMenu.js")
//   %%F{k-n} - first k elements and last n elements in file path (for example: %%F{1-3} shows "C:\...\Scripts\Include\ShowMenu.js")
//   %%d      - directory of current file (eg: "C:\Programs\TextEditors\AkelPad\AkelFiles\Plugs\Scripts\Include\")
//   %%d{n}   - last n levels of directory (for example: %%d{-3} shows "...\Plugs\Scripts\Include\")
//   %%d{k-n} - first k levels and last n levels of directory (for example: %%d{1-3} shows "C:\...\Plugs\Scripts\Include\")
//   %%D      - disk, eg. "C:"
//   %%m      - modified flag
//   %%e      - exe file base name (eg: "AkelPad", "AkelPad_test")
//   %%v      - AkelPad version (eg: "4.9.7")
//   %%b      - AkelPad bit version ("x86" or "x64")
//   %%w      - windows mode ("SDI", "MDI" or "PMDI")
//   %%a      - AkelPad is running in administrator mode (Win-Vista+)
// 
// Notes:
//   After first call with any argument, the script resides in the memory.
//   Second script call without arguments, restores standard title and closes the script.
// 
// For autostart, in AkelPad.ini or registry CmdLineBegin/CmdLineEnd key, need to add eg:
//   /Call("Scripts::Main", 1, "AkelPadTitle.js", '-t0="no file%%m - AkelPad" -t1="%%f%%m - AkelPad" -m=" [modified]"')
//   /Call("Scripts::Main", 1, "AkelPadTitle.js", '-t="%%e %%v (%%b) - %%w" -t0="%%mnew - %%e %%v (%%b) - %%w" -t1="%%m%%f - %%e %%v (%%b) - %%w"')

var hScript = AkelPad.ScriptHandle(WScript.ScriptName, 3 /*SH_FINDSCRIPT*/);

//script already is running
if (hScript && AkelPad.ScriptHandle(hScript, 13 /*SH_GETMESSAGELOOP*/))
{
  if (! WScript.Arguments.length)
    AkelPad.ScriptHandle(hScript, 33 /*SH_CLOSESCRIPT*/);
}

else if (WScript.Arguments.length)
{
  var oSys        = AkelPad.SystemFunction();
  var nMDI        = AkelPad.IsMDI();
  var hMainWnd    = AkelPad.GetMainWnd();
  var sTitlePat   = AkelPad.GetArgValue("t", "%e");
  var sTitlePat0  = AkelPad.GetArgValue("t0", "%mnew - %e");
  var sTitlePat1  = AkelPad.GetArgValue("t1", "%m%F - %e");
  var sModified   = AkelPad.GetArgValue("m", "*");
  var sAdmin      = IsRunningAsAdmin() ? AkelPad.GetArgValue("a", "Admin") : "";
  var sExeName    = GetExeName();
  var sAPVersion  = GetAkelPadVersion();
  var sBitVersion = _X64 ? "x64" : "x86";
  var sWinMode    = (nMDI == 0) ? "SDI" : ((nMDI == 1) ? "MDI" : "PMDI");
  var hSubClassMain;
  var hSubClassFrame;

  if (hSubClassMain = AkelPad.WindowSubClass(1 /*WSC_MAINPROC*/, MainCallback,
                                               78 /*WM_NOTIFY*/,
                                             1035 /*AKDN_EDIT_ONSTART*/,
                                             1045 /*AKDN_FRAME_NOWINDOWS*/,
                                             1046 /*AKDN_FRAME_ACTIVATE*/,
                                             1047 /*AKDN_FRAME_DEACTIVATE*/,
                                             1078 /*AKDN_OPENDOCUMENT_FINISH*/,
                                             1080 /*AKDN_SAVEDOCUMENT_FINISH*/))
  {
    hSubClassFrame = AkelPad.WindowSubClass(3 /*WSC_FRAMEPROC*/, FrameCallback, 78 /*WM_NOTIFY*/, 5 /*WM_SIZE*/);

    SetMainTitle();
    AkelPad.ScriptNoMutex();
    AkelPad.WindowGetMessage();
    AkelPad.WindowUnsubClass(1 /*WSC_MAINPROC*/);

    if (hSubClassFrame)
      AkelPad.WindowUnsubClass(3 /*WSC_FRAMEPROC*/);

    RestoreFrameTitle();
    RestoreMainTitle();
  }
}

function MainCallback(hWnd, uMsg, wParam, lParam)
{
  if (uMsg == 78 /*WM_NOTIFY*/)
  {
    if (AkelPad.MemRead(_PtrAdd(lParam, _X64 ? 16 : 8), 3 /*DT_DWORD*/) == 2076 /*AEN_MODIFY*/)
    {
      AkelPad.WindowNextProc(hSubClassMain, hWnd, uMsg, wParam, lParam);
      SetMainTitle();
      AkelPad.WindowNoNextProc(hSubClassMain);
    }
  }
  else if ((uMsg == 1035 /*AKDN_EDIT_ONSTART*/) || (uMsg == 1047 /*AKDN_FRAME_DEACTIVATE*/))
    RestoreFrameTitle();
  else if (uMsg == 1045 /*AKDN_FRAME_NOWINDOWS*/)
    SetMainTitle(nMDI == 1 /*WMD_MDI*/);
  else if ((uMsg == 1046 /*AKDN_FRAME_ACTIVATE*/) || (uMsg == 1078 /*AKDN_OPENDOCUMENT_FINISH*/) || (uMsg == 1080 /*AKDN_SAVEDOCUMENT_FINISH*/))
    SetMainTitle();

  return 0;
}

function FrameCallback(hWnd, uMsg, wParam, lParam)
{
  if ((uMsg == 78 /*WM_NOTIFY*/) && (AkelPad.MemRead(_PtrAdd(lParam, _X64 ? 16 : 8), 3 /*DT_DWORD*/) == 2076 /*AEN_MODIFY*/))
  {
    AkelPad.WindowNextProc(hSubClassFrame, hWnd, uMsg, wParam, lParam);
    SetMainTitle();
    AkelPad.WindowNoNextProc(hSubClassFrame);
  }
  else if (uMsg == 5 /*WM_SIZE*/)
  {
    if (wParam == 2 /*SIZE_MAXIMIZED*/)
      SetMainTitle();
    else
      RestoreFrameTitle();
  }

  return 0;
}

function SetMainTitle(bNoWindows)
{
  var hWndFrame = AkelPad.SendMessage(hMainWnd, 1223 /*AKD_GETFRAMEINFO*/, 1 /*FI_WNDEDITPARENT*/, 0 /*current frame*/);
  var bModified = AkelPad.GetEditModified(0);
  var sFile     = AkelPad.GetEditFile(0);
  var sFileBase = AkelPad.GetFilePath(sFile, 2 /*CPF_FILENAME*/);
  var sDir      = AkelPad.GetFilePath(sFile, 1 /*CPF_DIR*/);
  var sDisk     = sDir.substr(0, 2);
  var sPattern;

  if (bNoWindows)
    sPattern = sTitlePat;
  else
  {
    if ((nMDI == 1 /*WMD_MDI*/) && oSys.Call("User32::IsZoomed", hWndFrame))
      //remove frame title
      oSys.Call("User32::SetWindowTextW", hWndFrame, "");

    if (sFile)
      sPattern = sTitlePat1;
    else
      sPattern = sTitlePat0;
  }

  oSys.Call("User32::SetWindowTextW", hMainWnd, sPattern.replace(/%d\{-?(\d+)\}|%d\{(\d+)-(\d+)\}|%F\{-?(\d+)\}|%F\{(\d+)-(\d+)\}|%f|%F|%d|%D|%m|%e|%v|%b|%w|%a/g, ReplaceFunc));

  function ReplaceFunc()
  {
    var sParam = arguments[0].charAt(1);
    var aPath;
    var n1;
    var n2;

    if (arguments[1] || arguments[2] || arguments[4] || arguments[5])
    {
      if (! sFile)
        return "";

      if (arguments[1])
      {
        n1 = 0;
        n2 = parseInt(arguments[1]);
      }
      else if (arguments[2])
      {
        n1 = parseInt(arguments[2]);
        n2 = parseInt(arguments[3]);
      }
      else if (arguments[4])
      {
        n1 = 0;
        n2 = parseInt(arguments[4]);
      }
      else
      {
        n1 = parseInt(arguments[5]);
        n2 = parseInt(arguments[6]);
      }

      if ((n1 == 0) && (n2 == 0))
        return "";

      aPath = (sParam == "d") ? sDir.split("\\") : sFile.split("\\");

      if ((n1 + n2) >= aPath.length)
        return (sParam == "d") ? (sDir + "\\") : sFile;
      if (n1 == 0)
        return "...\\" + aPath.slice(aPath.length - n2).join("\\") + ((sParam == "d") ? "\\" : "");
      if (n2 == 0)
        return aPath.slice(0, n1).join("\\") + "\\...";

      return aPath.slice(0, n1).join("\\") + "\\...\\" + aPath.slice(aPath.length - n2).join("\\") + ((sParam == "d") ? "\\" : "");
    }

    if (sParam == "f")
      return sFileBase;
    if (sParam == "F")
      return sFile;
    if (sParam == "d")
      return sDir + "\\";
    if (sParam == "D")
      return sDisk;
    if (sParam == "m")
      return bModified ? sModified : "";
    if (sParam == "e")
      return sExeName;
    if (sParam == "v")
      return sAPVersion;
    if (sParam == "b")
      return sBitVersion;
    if (sParam == "w")
      return sWinMode;
    if (sParam == "a")
      return sAdmin;
  }
}

function RestoreFrameTitle()
{
  if (nMDI == 1 /*WMD_MDI*/)
  {
    var bModified   = AkelPad.GetEditModified(0);
    var bShowModify = AkelPad.SendMessage(hMainWnd, 1222 /*AKD_GETMAININFO*/, 110 /*MI_SHOWMODIFY*/, 0) & 4 /*SM_FRAMETITLE_MDI*/;

    oSys.Call("User32::SetWindowTextW",
              AkelPad.SendMessage(hMainWnd, 1223 /*AKD_GETFRAMEINFO*/, 1 /*FI_WNDEDITPARENT*/, 0 /*current frame*/),
              AkelPad.GetEditFile(0) + ((bModified && bShowModify) ? "*" : ""));
  }
}

function RestoreMainTitle()
{
  var sTitle    = "AkelPad";
  var sFile     = AkelPad.GetEditFile(0);
  var bModified = AkelPad.GetEditModified(0);
  var bShowModify;

  if (nMDI == 0 /*WMD_SDI*/)
  {
    bShowModify = AkelPad.SendMessage(hMainWnd, 1222 /*AKD_GETMAININFO*/, 110 /*MI_SHOWMODIFY*/, 0) & 2 /*SM_MAINTITLE_SDI*/;

    if (sFile)
      sTitle = ((bModified && bShowModify) ? "*" : "") + AkelPad.GetFilePath(sFile, 2 /*CPF_FILENAME*/) + " - " + sTitle;
    else if (bModified && bShowModify)
      sTitle = "* - " + sTitle;
  }
  else if (nMDI == 2 /*WMD_PMDI*/)
  {
    bShowModify = AkelPad.SendMessage(hMainWnd, 1222 /*AKD_GETMAININFO*/, 110 /*MI_SHOWMODIFY*/, 0) & 4 /*SM_FRAMETITLE_MDI*/;

    if (sFile)
      sTitle += " - [" + sFile + ((bModified && bShowModify) ? "*]" : "]");
    else if (bModified && bShowModify)
      sTitle += " - [*]";
  }

  oSys.Call("User32::SetWindowTextW", hMainWnd, sTitle);
}

function GetExeName()
{
  var lpName = AkelPad.MemAlloc(260 * 2);
  var sName;

  oSys.Call("Kernel32::GetModuleFileNameW", 0, lpName, 260);
  sName = AkelPad.MemRead(lpName, 1 /*DT_UNICODE*/);
  AkelPad.MemFree(lpName);

  return sName.replace(/.+\\(.+)\..*$/, "$1");
}

function GetAkelPadVersion()
{
  var nVer    = AkelPad.SendMessage(hMainWnd, 1225 /*AKD_PROGRAMVERSION*/, 0, 0);
  var nLoWord = nVer & 0xFFFF;
  var nHiWord = (nVer >> 16) & 0xFFFF;

  return (nLoWord & 0xFF) + "." + ((nLoWord >> 8) & 0xFF) + "." + (nHiWord & 0xFF);
}

function IsRunningAsAdmin()
{
  var bAsAdmin = false;

  if (((oSys.Call("Kernel32::GetVersion") & 0xFFFF) & 0xFF) > 5)
  {
    var lpToken = AkelPad.MemAlloc(_X64 ? 8 : 4);
    var lpInfo  = AkelPad.MemAlloc(4);
    var lpSize  = AkelPad.MemAlloc(4);
    var hToken;

    if (oSys.Call("Advapi32::OpenProcessToken", oSys.Call("Kernel32::GetCurrentProcess"), 0x0008 /*TOKEN_QUERY*/, lpToken))
    {
      hToken = AkelPad.MemRead(lpToken, 2 /*DT_QWORD*/);

      if ((oSys.Call("Advapi32::GetTokenInformation", hToken, 20 /*TokenElevation*/, lpInfo, 4, lpSize)) && AkelPad.MemRead(lpInfo, 3 /*DT_DWORD*/))
        bAsAdmin = true;

      oSys.Call("Kernel32::CloseHandle", hToken);
    }

    AkelPad.MemFree(lpToken);
    AkelPad.MemFree(lpInfo);
    AkelPad.MemFree(lpSize);
  }

  return bAsAdmin;
}
