/********************************************************************
                         SmartTab

  Description: Tabs to the first non-whitespace character in the preceding line.
  Syntax:      SmartTab

  To map this script to a shortcut key:

  1. Save this script in the GwdTextEditor\script directory.
  2. From the Macro menu, choose Macro command.
  3. Choose the New button.
  4. In the New Macro Name input box, type a name for the macro. For
     example Script_SmartTab. In this dialog you can also define
     Tab as shortcut key for this macro.
  5. Choose the OK button.
  6. In the Edit Macro dialog box edit box enter the following two
     lines:
        Param1 "SmartTab"
        ExecScript
  7. Choose the Close button.
  8. You can now define shortcut key for the Script_SmartTab macro
     in the Key Mapping dialog box.

  Author: Vedran Gaco
********************************************************************/

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <editor/doc.h>
#include <editor/macros.h>
#include <editor/options.h>
#include <editor/string.h>


// function prototypes
void ScriptMain(HDOC);


/*-------------------------------------------------------------------
                    main function
-------------------------------------------------------------------*/

int main(int argc, char *argv[])
{
   HDOC hDoc;

   hDoc = Gte_GetActiveDocument();
   if(hDoc == NULL) {
      MsgBox("Cannot get handle of the active document!", MB_OK);
      return 1;
   }
   // check if document is read only
   if(Gte_IsReadOnly(hDoc)) {
      MsgBox("Document is read only!", MB_OK);
      return 1;
   }
   // turn off line drawing and/or selecting mode
   GM_EndLineDraw(hDoc);
   GM_EndSelect(hDoc);

   {
      BOOL bOverwriteMode;
      BOOL bCursorBeyondEOL;
      BOOL bCursorThroughtTabs;

      // save original editor options
      bOverwriteMode = Gte_IsOverwriteMode();
      bCursorBeyondEOL = Gte_IsCursorBeyondEOL();
      bCursorThroughtTabs = Gte_IsCursorThroughtTabs();

      // set new editor options
      Gte_SetOverwriteMode(FALSE);
      Gte_SetCursorBeyondEOL(TRUE);
      Gte_SetCursorThroughtTabs(TRUE);

      // call main script function
      ScriptMain(hDoc);

      // restore original editor options
      Gte_SetOverwriteMode(bOverwriteMode);
      Gte_SetCursorBeyondEOL(bCursorBeyondEOL);
      Gte_SetCursorThroughtTabs(bCursorThroughtTabs);
   }

   return 0;
}


/*-------------------------------------------------------------------
                         ScriptMain

  Main script function.

  PARAMETERS

     hDoc - Handle of the active document.
-------------------------------------------------------------------*/

void ScriptMain(HDOC hDoc)
{
   long nColumn, nLine;
   char szLine[2048];
   long  i;

   // If the Use Tab Character option is on, we will insert normal tab
   if(Gte_IsUseTabChar())
   {
      GM_Tab(hDoc);
      return;
   }

   // Get current column and line position
   Gte_GetCursorPos(hDoc, &nColumn, &nLine);

   // Determine tab size from maximally 20 preceding lines
   for(i = nLine-1; i > 0 && nLine - i < 20; i--)
   {
      char *psz;
      int  nTabSize;

      Gte_GetLine(hDoc, i, szLine, sizeof(szLine));
      // remove trailing blanks
      if(__GWDC__ >= 0x102)
         strrtrim(szLine);
      // get pointer to character in the preceding line for nColumn position
      psz = Gte_GetCharPtr(szLine, nColumn);
      // if this line is longer than current
      if(*psz != 0)
      {
         int nInsertSpaces;

         // if we inside white characters
         if(isspace((unsigned char)*psz))
         {
            while(isspace((unsigned char)*psz))
               psz++;
         }
         else
         {
            while(*psz && isspace((unsigned char)*psz) == FALSE)
               psz++;
            while(isspace((unsigned char)*psz))
               psz++;
         }
         nTabSize = Gte_GetCharColumnPos(szLine, psz) - nColumn;
         if(nTabSize <= 1)
         {
            // Impossible
            // ASSERT(FALSE);
            GM_Tab(hDoc);
         }
         else
         {
            // insert nTabSize spaces at the current cursor position
            if((psz = malloc(nTabSize+1)) != NULL)
            {
               memset(psz, ' ', nTabSize);
               psz[nTabSize] = 0;
               Gte_InsertText(hDoc, psz);
               free(psz);
            }
         }
         return;
      }
   }

   // Normal tab
   GM_Tab(hDoc);
}
