unit StructVariables;

//==============================================================================
//  INTERFACE
//==============================================================================
interface
uses JStruct, Member, Classes, StringHash, Constants, TextOnly;

var
    structmagic_time:string;

    HookedNativeHash: TStringHash;
    HookedNatives : Tlist;

    functionLines: Tlist;
    nativeLines:Tlist;
    hookLines:Tlist;

//==============================================================================
//  FUNCTIONS
//==============================================================================
function VerifyRedeclaration(const s:string; const ignoreglobals:boolean=false):Integer;
procedure VerifyRedeclarationRaise(const ln: integer;const s:string; const ignoreglobals:boolean=false);
procedure correctArray2Size(const lnum:integer; const w:integer; const h:integer; const extended:boolean=false);
procedure correctArraySize(const lnum:integer; const arsize:integer; const extended:boolean=false);
procedure InitNewGlobals;
procedure addglobal(const s:string;const genline:integer; const fromstruct:integer=-1);
procedure generateExtraArrays(const typename:string; const pref:string; const suf:string; const indexSpace:integer; const genline:integer);
function newglobalsn:integer;
procedure getnewglobal(i:integer; var glob:string; var gl:integer; var fs:integer);

//==============================================================================
//  IMPLEMENTATION
//==============================================================================
implementation
uses SysUtils, JASSErException, Prototypes, Translate;

var
    _newglobalsn : integer;
    newglobalsgl,newglobalsfs: Array of integer;
    newglobals: Array of string;

//==============================================================================
function newglobalsn:integer;
begin
    Result := _newglobalsn;
end;

//==============================================================================
procedure getnewglobal(i:integer; var glob:string; var gl:integer; var fs:integer);
begin
    glob := newglobals[i];
    gl   := newglobalsgl[i];
    fs   := newglobalsfs[i];
end;



//==============================================================================
//  Checks to see if name has been previously defined.
//  Returns 0 on all OK.
//  Returns -1 on local redeclaration
//  Returns line number on double declaration 
//==============================================================================
function VerifyRedeclaration(const s:string; const ignoreglobals:boolean=false):Integer;
begin
    Result:=0;
    if(LocalIdentifierTypes.ValueOf(s)<>-1) then Result:=-1
    else if ( not(ignoreglobals) and (IdentifierTypes.ValueOf(s)<>-1)) then Result:=-1
    else if ( {not(ignoreglobals) and} (FunctionHash.ValueOf(s)<>-1)) then begin
        Result:=FunctionData[FunctionHash.ValueOf(s)].decl;
    end else if (StructHash.ValueOf(s)<>-1) then begin
        Result:=StructList[StructHash.ValueOf(s)].decl;
    end;
end;


//==============================================================================
//  wrapper for VerifyRedeclaration that throws exceptions
//==============================================================================
procedure VerifyRedeclarationRaise(const ln: integer;const s:string; const ignoreglobals:boolean=false);
var i:integer;
begin
    i:=VerifyRedeclaration(s,ignoreglobals);
    if(i=-1) then Raise JasserLineException(ln,'Identifier redeclared : "'+s+'"');
    if(i>0) then Raise JasserLineDoubleException(ln,'Identifier redeclared : "'+s+'"',i,'---- (previously declared here)');
end;

//==============================================================================
procedure correctArraySize(const lnum:integer; const arsize:integer; const extended:boolean=false);
begin
    if(arsize=-3) then raise JAsserLineException(lnum,'Expected [size].');
    if(arsize=-1) then raise JAsserLineException(lnum,'Wrong [size] definition.');
    if(arsize<0) then raise JasserLineException(lnum,'Negative array size?');
    if(arsize=0) then raise JasserLineException(lnum,'Zero array size?');
    if(extended) then begin
        if(arsize>VJASS_MAX_ARRAY_INDEXES) then raise JasserLineException(lnum,'Not more than '+IntToStr(VJASS_MAX_ARRAY_INDEXES)+' is supported by vJass.');
    end else begin
        //if(arsize>JASS_ARRAY_SIZE-1) then raise JasserLineException(lnum,'Size breaks internal limits.');
        if(arsize>12000) then raise JasserLineException(lnum,'Size bigger than 12000 considered impractical.');
    end;
end;

//==============================================================================
procedure correctArray2Size(const lnum:integer; const w:integer; const h:integer; const extended:boolean=false);
 var arsize:integer;
begin
    arsize:=w*h;
    if(extended) then begin
        if(arsize>VJASS_MAX_ARRAY_INDEXES) then raise JasserLineException(lnum,'Not more than '+IntToStr(VJASS_MAX_ARRAY_INDEXES)+' elements are supported by vJass, '+IntToStr(w)+'*'+IntToStr(h)+' is '+IntToStr(arsize));
    end else begin
        if(arsize>JASS_ARRAY_SIZE-1) then raise JasserLineException(lnum,'Size breaks internal limits.');
    end;
end;

//==============================================================================
procedure InitNewGlobals;
begin
    SetLength(newglobals,20);
    SetLength(newglobalsgl,20);
    SetLength(newglobalsfs,20);
    _newglobalsn:=0;
end;

//==============================================================================
// adds a specified string(containing declaration) to the map globals section
//==============================================================================
procedure addglobal(const s:string;const genline:integer; const fromstruct:integer=-1);
begin
    if( Length(newglobals)<=newglobalsn) then begin
        SetLength(newglobals,newglobalsn+20);
        SetLength(newglobalsgl,newglobalsn+20);
        SetLength(newglobalsfs,newglobalsn+20);
    end;
    newglobals[newglobalsn]:=s;
    newglobalsgl[newglobalsn]:=genline;
    newglobalsfs[newglobalsn]:=fromstruct;

    _newglobalsn:=_newglobalsn+1;
end;

//==============================================================================
// creates additional arrays for types using more than JASS_ARRAY_SIZE
// this overcomes limitation of fixed array sizes in jass.
//==============================================================================
procedure generateExtraArrays(const typename:string; const pref:string; const suf:string; const indexSpace:integer; const genline:integer);
var i,re:integer;
    tmp:string;
begin
    if (JASS_ARRAY_SIZE>indexSpace) then Exit;
    i:=2;
    re:=indexSpace-JASS_ARRAY_SIZE+1;
    while(re>=1) do begin
        Concatenate5(tmp,typename,' array ',pref,IntToStr(i),suf);
        addglobal(tmp,genline);
        i:=i+1;
        re:=re-JASS_ARRAY_SIZE;
    end;
end;

end.
