unit Project;

interface
uses IniFiles, SysUtils, Dialogs, windows, ComCtrls, MDIEDit, Utils, Classes, Controls;

var ProjectOpen : Boolean;

const MAXUNIT = 400;   // Maximum number of units in a project

type TUnit =  record
                FileName : string;
                Node     : TTreeNode;
                Modified : boolean;
                FileTime : LongInt;
              end;

type TProject = class;

     TProject = class(TObject)
     constructor Create(nFileName, nName : string);
     procedure Free;
     function AddUnit(nFileName : string; OpenProject : boolean; CreateNodes : boolean) : TEditForm;
     function  FileAlreadyExists(s : string) : boolean;
     procedure CreateNewResFile(nFileName : string);
     function ShowUnit(nFileName : string): TEditForm;
     function AllObjFilesExist : boolean;
     function GetUnit(s : string) : TUnit;
     function GetUnitIndex(s : string) : integer;
     procedure SetMainUnit(s : string);

     public
       Name      : string;
       FileName  : string;
       Units     : array [0..MAXUNIT] of TUnit;
       UnitCount : integer;
       Icon      : string;
       ObjFile   : string;
       CompilerOptions : string;
       IncludeDirs : string;
       MainUnit : string;

       ResFiles  : string;
       ResFileModified : boolean;

       NoConsole : boolean;
       IsDll     : boolean;

     private
       IniFile : TIniFile;
       CountUnitCreated : integer;
     end;

implementation
uses Main, NewProject;

constructor TProject.Create(nFileName, nName: string);
var i, tmpCount : integer;
    tmp : string;
begin
  inherited Create;
  FileName := nFileName;

  MainForm.CloseAll;

  IniFile := TIniFile.Create(Filename);
  ProjectOpen := True;

  IniFile.WriteString('Project','FileName',FileName);

  if nName = '__FileOpen' then
  begin
    Name := IniFile.ReadString('Project','Name',Name);
    MainForm.ProjectNode := MainForm.MakeProjectNode(Name);
    UnitCount := IniFile.ReadInteger('Project','UnitCount',UnitCount);
    IsDll := IniFile.ReadBool('Project','IsDll', False);

    tmpCount := UnitCount;
    UnitCount := 0;
    for i := 0 to tmpCount-1
    do begin
        tmp := IniFile.ReadString('Unit'+IntToStr(i+1),'FileName',tmp);
        if not FileExists(tmp)
        then begin
           if FileExists(ExtractFilePath(FileName)+ExtractFileName(tmp))
           then begin
              IniFile.WriteString('Unit'+IntToStr(i+1),'FileName',ExtractFilePath(FileName)+ExtractFileName(tmp));
              AddUnit(ExtractFilePath(FileName)+ExtractFileName(tmp),True, True);
           end
           else begin
              MessageDlg('File '+tmp+' not found. Please check your unit filenames in Project menu.',MtError,[mbOK],0);
              AddUnit(tmp, True, True);
           end
        end
        else AddUnit(tmp, True, True);
    end;
    ObjFile := IniFile.ReadString('Project','ObjFile',ObjFile);

    ResFiles := IniFile.ReadString('Project','ResFiles',ResFiles);

    CompilerOptions := IniFile.ReadString('Project', 'CompilerOptions', '');
    IncludeDirs := IniFile.ReadString('Project', 'IncludeDirs', '');
    NoConsole := IniFile.ReadBool('Project','NoConsole',NoConsole);
    Icon := IniFile.ReadString('Project','Icon','Mainicon.ico');
    MainUnit := IniFile.ReadString('Project','MainUnit','');
  end
  else begin
    Name := nName;
    MainForm.ProjectNode := MainForm.MakeProjectNode(Name);
    IniFile.WriteString('Project','Name',Name);

    UnitCount := 0;

    AddUnit('Untitled', False, True);
    Name := nName;

    ResFiles := ExtractFilePath(nFileName)+'rsrc.rc';
    IniFile.WriteString('Project','ResFiles',ResFiles);

    if not FileExists(ExtractFilePath(nFilename) + 'rsrc.rc') then
       CreateNewResFile(MainForm.DevPasPath+'Icon\MAINICON.ICO');

    ObjFile := '';

    NoConsole := not NewProjForm.Console;

    if (ProjectType = TDll) then
        IsDll := True
    else
        IsDll := False;

    IniFile.WriteBool('Project','NoConsole',NoConsole);
    IniFile.WriteBool('Project','IsDll',IsDll);
    IniFile.WriteString('Project','Icon',MainForm.BinDir+'Mainicon.ico');
    Icon := MainForm.BinDir+'Mainicon.ico';
  end;

  if nName = '__FileOpen' then
     Name := IniFile.ReadString('Project','Name',Name);

  FileName := nFileName;

  MainForm.SaveFileHistory(FileName);
end;

procedure TProject.Free;
begin
  ProjectOpen := False;
  ProjectType := TOther;
end;

procedure TProject.CreateNewResFile(nFileName : string);
var F1 : TextFile;
    s : string;
    j : integer;
begin
  AssignFile(F1,ExtractFilePath(FileName)+'Rsrc.rc');
  Rewrite(F1);
  s := nFileName;
  while Pos('\', s)<>0 do begin
    j := Pos('\', s);
    Delete(s,j,1);
    Insert('/', s, j);
  end;

  Writeln(F1,'500 ICON MOVEABLE PURE LOADONCALL DISCARDABLE "'+s+'"');
  CloseFile(F1);

  ResFileModified := True;
end;

function TProject.AddUnit(nFileName : string; OpenProject : boolean; CreateNodes : boolean) : TEditForm;
var
  ProjectName: string;
begin
  Inc(UnitCount);

  if nFileName = 'Untitled' then begin
     Inc(CountUnitCreated);
     nFileName := 'Untitled' + IntToStr(CountUnitCreated);
  end;

  if UnitCount = 1 then
     SetMainUnit(nFileName);

  Units[UnitCount-1].FileName := nFileName;
  Units[UnitCount-1].Modified := False;
  Units[UnitCount-1].FileTime := IniFile.ReadInteger('Unit'+IntToStr(UnitCount),'FileTime',0);

  if OpenProject = False then
     IniFile.WriteString('Unit'+IntToStr(UnitCount),'FileName',nFileName);

  IniFile.WriteInteger('Project','UnitCount',UnitCount);

  if CreateNodes then
     Units[UnitCount-1].Node := MainForm.MakeNewFileNode(nFileName);

  if OpenProject and MainForm.IniFile.ReadBool('Options','NoOpen', False) then begin
     Result := nil;
     exit;
  end;

  Result := TEditForm.Create(MainForm);

  ProjectName := Name;
  if Pos(':\',nFileName)<>0 then begin
     with Result do begin
       Caption := ExtractFileName(nFileName);
       PathName := nFileName;
       try
         Editor.Lines.LoadFromFile(nFileName);
       except
         Messagedlg('Could not open file '+nFileName, mtWarning, [mbOK],0);
       end;

       GetIndex := UnitCount;
     end
  end
  else with Result do begin
       Caption := ExtractFileName(nFileName);

       PathName := '';
       GetIndex := UnitCount;

       Editor.CaretX := 0;

       if (nFileName = 'Untitled' + IntToStr(CountUnitCreated)) and (NewProjForm <> nil) and (NewProjForm.ModalResult = mrOK) then
       begin
          Editor.Lines.Text := NewProjForm.Text;
          if NewProjForm.X < 300 then begin
             Editor.CaretX := NewProjForm.X;
             Editor.CaretY := NewProjForm.Y;
          end;
       end;
  end;
end;

function TProject.FileAlreadyExists(s : string) : boolean;
var i : integer;
begin
  Result := False;
  for i := 0 to UnitCount-1 do
      if lowercase(ExtractFileName(s)) = lowercase(ExtractFileName(Units[i].FileName)) then
         Result := True;
end;

function TProject.ShowUnit(nFileName : string) : TEditForm;
var i : integer;
begin
  Result := TEditForm.Create(MainForm);
  with Result do begin
    Caption := ExtractFileName(nFileName);

    if pos(':\',nFileName) = 0 then
       exit;

    PathName := nFileName;

    for i := 0 to UnitCount-1 do
        if lowercase(ExtractFileName(nFileName)) = lowercase(ExtractFileName(Units[i].FileName)) then begin
           GetIndex := i;
           Open(Units[i].FileName);

           exit;
        end;
  end
end;

function TProject.AllObjFilesExist : boolean;
var i : integer;
begin
  Result := True;
  for i := 0 to UnitCount-1 do
      if FileExists(ChangeFileExt(GetShortName(Units[i].FileName),'.ow')) then begin
           Result := False;
           Exit;
      end;
end;

function TProject.GetUnit(s : string) : TUnit;
var i : integer;
begin
  for i := 0 to UnitCount-1 do
      if lowercase(s) = lowercase(ExtractFileName(Units[i].FileName)) then begin
         Result := Units[i];
         exit;
      end;
end;

function TProject.GetUnitIndex(s : string) : integer;
var i : integer;
begin
  Result := -1;
  for i := 0 to UnitCount-1 do
      if lowercase(s) = lowercase(ExtractFileName(Units[i].FileName)) then begin
         Result := i;
         exit;
      end;
end;

procedure TProject.SetMainUnit(s : string);
begin
  MainUnit := s;
  IniFile.WriteString('Project','MainUnit',s);
end;

end.
