unit ShadowHelper;

//==============================================================================
//  INTERFACE
//==============================================================================
interface

function Run(sinput:string):string;
//procedure Run(const f1:string; const f2:string);overload;

//==============================================================================
//  IMPLEMENTATION
//==============================================================================
implementation
uses StringHash, TextOnly, TextCommon, JHInput, JASSerException, Constants,
     SysUtils, vxFileSys, Translate, JHInterface;


var
    ShadowHelper_GlobalsHash: TStringHash;


//==============================================================================
procedure ShadowHelper_ReadGlobal(const s:string);
var
   x:integer;
   word:string;

begin
    //[constant] <type> [array] <name> [=value]

    GetLineWord(s,word,x);

    if(word='constant') then GetLineWord(s,word,x,x);
    GetLineToken(s,word,x,x);
    if(word='array') then GetLineToken(s,word,x,x);
    ShadowHelper_GlobalsHash.Add(word,1);

end;

//==============================================================================
function ShadowHelper_HelpIt(const ModHash:TstringHash; const s:string):String;
var
   tem:string;
   tok:string;
   i,j,k,L:integer;
begin
    if( (ModHash=nil) or IsWhiteSpace(s) )  then begin
         Result:=s;
         exit;
    end;
    i:=1;
    k:=0;
    L:=Length(s);

    while(i<=L+1) do begin
        if( i>L)  or (s[i] in SEPARATORS) then begin
            if(i-k > 0) then begin
                tok:=Copy(s, k+1, i-k-1);
                if( ModHash.ValueOf(tok) <> -1 ) then Swrite(tem, 'l__'+tok)
                else Swrite(tem, tok );
            end;
            k:=i;

            if(i>L) then else if( s[i] = '"' ) then begin
                j:=i+1;
                 while(j<=L) do begin
                    if(s[j]='\') then j:=j+1
                    else if(s[j]='"') then break;
                    j:=j+1;
                end;

                Swrite(tem,Copy(s,i,j-i+1) );
                i:=j;
                k:=i;
            end else if(s[i]='''') then begin
                j:=i+1;
                while(s[j]<>'''') do j:=j+1;
                Swrite(tem,Copy(s,i,j-i+1) );
                i:=j;
                k:=i;

            end else if (s[i]='/') and (i<L) and (s[i+1]='/') then begin
                Swrite(tem,Copy(s, i, L-i+1) );
                break;
            end else Swrite(tem, s[i]);

        end;
        i:=i+1;



    end;
    result:=tem;


end;

//==============================================================================
procedure ShadowHelper_HandleFunction( const fstart:integer; var Result:string);
var
    tem, lname, ltype, name,returntype: string;
    constant:boolean;
    i,argn,x:integer;
    ModHash: TStringHash;

       procedure addLocal(const s:string);
       begin
           if(ModHash = nil) then begin
               ModHash := TStringHash.create;
           end;
           ModHash.Add(s,1);
       end;
begin
   ParseFunctionSignature(JHInput.Get(fstart), constant, name, argn, returntype);
   ModHash:= nil;
   for i := 0 to argn - 1 do begin
       lname:=ParseFunctionSignature_ArgNamesBuf[i];
       if (ShadowHelper_GlobalsHash.ValueOf(lname ) <> -1) then
           addLocal(lname);
   end;
   if(ModHash<>nil) then begin
       if(constant) then tem:='constant function '
       else tem:='function ';
       tem:= tem+name+' takes ';
       if(argn=0) then tem:='nothing '
       else for i := 0 to argn - 1 do begin
               lname:=ParseFunctionSignature_ArgNamesBuf[i];
               ltype:=ParseFunctionSignature_ArgTypesBuf[i];
               if(ShadowHelper_GlobalsHash.ValueOf(lname) <> -1) then lname:='l__'+lname;
               if(i=0) then
                   tem:=tem+ltype+' '+lname
               else
                   tem:=tem+','+ltype+' '+lname
            end;
       tem := tem + ' returns '+returntype;
       SWriteLn(Result, tem);

   end else SWriteLn(Result, JHInput.Get(fstart));

   i:=fstart + 1;
   while(true) do begin
       if(IsWhiteSpace(JHInput.Get(i)) ) then begin
           SWriteLn(Result, JHInput.Get(i));
           JHInput.Rewrite(i, '#');
           i:=i+1;
           continue;
       end
       else if (not CompareLineWord('local', JHInput.Get(i), x)) then break;
       GetLineWord(JHInput.Get(i),ltype,x,x);
       GetLineToken(JHInput.Get(i),lname,x,x);
       if(lname = 'array') then begin
           ltype := ltype+' array';
           GetLineToken(JHInput.Get(i),lname,x,x);
       end;
       if (ShadowHelper_GlobalsHash.ValueOf(lname ) <> -1) then
           addLocal(lname);

       SWriteLn( Result, ShadowHelper_HelpIt(ModHash, JHInput.Get(i)) );
       JHInput.Rewrite(i, '#');
       i:=i+1;
   end;
   while(not CompareLineWord('endfunction' , JHInput.Get(i), x) ) do begin
        SWriteLn( Result, ShadowHelper_HelpIt(ModHash, JHInput.Get(i)) );
        JHInput.Rewrite(i, '#');
        i:=i+1;
   end;



   if(ModHash<>nil) then ModHash.destroy;
end;


//==============================================================================
procedure ShadowHelperDo( var Result:string);
// var inlinefunc
 var i,j:integer;
     word:string;
     printit:boolean;
     globals:boolean;

begin


 try
        //ProMax(ln);
        //ProPosition(0);
        //ProStatus('  Processing: ');


    Result:='';
    // final script rumble, normalized! There are only two things we can expect, the first globals block
    // and a bunch of functions, everything else is probably a syntax error, but it might be a better idea
    // to let PJASS handle it, so we try to ignore it.

    //by this time, unclosed function/globals errors should have been caught by libraries or struct parser
    i:=0;
    globals:=false;
    ShadowHelper_GlobalsHash:= TStringHash.Create;
    while(i<inputN) do begin
        //ProPosition(i/inputN);

        printit:=true;
        if(not IsWhitespace(JHInput.Get(i))) then begin
            GetLineWord(JHInput.Get(i),word,j);
            if(globals) then begin

                if(word='endglobals') then begin
                    globals:=false ;
                end else begin
                    ShadowHelper_ReadGlobal(JHInput.Get(i));
                end;
            end else if(word='globals') then begin
                globals:=true ;
            end else begin
                //[constant] function?
                if((word='constant') and (compareLineWord('function',JHInput.Get(i),j,j))) or (word='function') then begin

                    ShadowHelper_HandleFunction(i, Result);
                    printit:=false;
                end;
            end;

        end;

        if(printit and (JHInput.Get(i)<>'#') ) then SWriteLn(Result,JHInput.Get(i));
        i:=i+1;
    end;
    //ProEnd();


 finally
     ShadowHelper_GlobalsHash.Destroy;
 end;


end;


//==============================================================================
function Run(sinput:string):string;
begin
    ProStatus('Shadow Helper: ');

    Result:='ERROR';
    JHInput.Reset2();
    JHInput.Load(sinput); 
    if (inputN<2) then raise Exception.Create('Input file seems too small / unclosed string issues');

    JHinput.ClearOffsets();

    ShadowHelperDo(Result);
    ProEnd();
end;

end.
