Unit repair;

{$mode objfpc}{$H+}

Interface

Uses
  Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
  CheckLst, StdCtrls, Buttons, ComCtrls, Grids, ExtCtrls, CADEngine, ShlepsUtils;

Type

  { TRepairForm }

  TRepairForm = Class(TForm)
    CancelBitBtn: TBitBtn;
    ExtraDrawingCommandCheckBox: TCheckBox;
    DelSamePortConnsCheckBox: TCheckBox;
    RemoveEmptyPortsCheckBox: TCheckBox;
    LogMemo: TMemo;
    Obj2ConnMismatchCheckBox: TCheckBox;
    Conn2ObjMismatchCheckBox: TCheckBox;
    CheckPageControl: TPageControl;
    ListTabSheet: TTabSheet;
    LogTabSheet: TTabSheet;
    ToggleAllSpeedButton: TSpeedButton;
    UpdateDisplayListCheckBox: TCheckBox;
    FixAllObjectsCheckBox: TCheckBox;
    CurrentItemLabel: TLabel;
    Panel1: TPanel;
    NoCalloutConnectionsCheckBox: TCheckBox;
    ProceedBitBtn: TBitBtn;
    ProgressBar: TProgressBar;
    FixStringGrid: TStringGrid;
    Procedure CancelBitBtnClick(Sender: TObject);
    Procedure FormResize(Sender: TObject);
    Procedure NoCalloutConnectionsCheckBoxChange(Sender: TObject);
    Procedure ProceedBitBtnClick(Sender: TObject);
    procedure ToggleAllSpeedButtonClick(Sender: TObject);
  Private
    { private declarations }
  Public
    { public declarations }
  End;

Var
  RepairForm: TRepairForm;

Implementation
Uses Unit1;
{ TRepairForm }

Procedure TRepairForm.ProceedBitBtnClick(Sender: TObject);
Label NextObj;
Var I,J,K,Index,Index2,Index3,FixCount,TotalFixes:Longint;
    Obj,Obj2:TVObject;
    Callout:TVCallout;
    Connection,Connection2:TVConnection;
    Port,Port2:TVPort;
    ConnPort,ConnPort2:TVConnectionPort;
    ObjName,ConnName,Buf,ParsedBuf,Cmd:String;
Begin
  For I:=1 To FixStringGrid.RowCount-1 Do
    FixStringGrid.Cells[1,I]:='';
  LogMemo.Clear;
  TotalFixes:=0;
  If FixAllObjectsCheckBox.Checked Then Begin
    FixCount:=0;
    For I:=0 To Scene.VObjectList.Count-1 Do Begin
      ProgressBar.Position:=Round(I/Scene.VObjectList.Count*1000);
      Obj:=Scene.VObjectList.Objects[I] As TVObject;
      Scene.MoveObjectTo(Obj,Obj.X,Obj.Y,'');
      Inc(FixCount);
      FixStringGrid.Cells[1,1]:=IntToStr(FixCount)+' items processed';
      CurrentItemLabel.Caption:='Now checking:'+Obj.Name;
      Application.ProcessMessages;
    End;
  End;
  If UpdateDisplayListCheckBox.Checked Then Begin
    FixCount:=0;
    If Scene.VObjectList.Count>0 Then
      For I:=0 To Scene.VObjectList.Count-1 Do Begin
        ProgressBar.Position:=Round(I/Scene.VObjectList.Count*1000);
        Obj:=Scene.VObjectList.Objects[I] As TVObject;
        Scene.UpdateObjectDisplayList(Obj);
        Inc(FixCount);
        FixStringGrid.Cells[1,2]:=IntToStr(FixCount)+' items processed';
        CurrentItemLabel.Caption:='Now checking:'+Obj.Name;
        Application.ProcessMessages;
      End;
    FixCount:=0;
    If Scene.VCalloutList.Count>0 Then
      For I:=0 To Scene.VCalloutList.Count-1 Do Begin
        ProgressBar.Position:=Round(I/Scene.VCalloutList.Count*1000);
        Callout:=Scene.VCalloutList.Objects[I] As TVCallout;
        Scene.UpdateCalloutDisplayList(Callout);
        Inc(FixCount);
        FixStringGrid.Cells[1,2]:=IntToStr(FixCount)+' items processed';
        CurrentItemLabel.Caption:='Now checking:'+Callout.Name;
        Application.ProcessMessages;
      End;
    FixCount:=0;
    If Scene.VConnectionList.Count>0 Then
      For I:=0 To Scene.VConnectionList.Count-1 Do Begin
        ProgressBar.Position:=Round(I/Scene.VConnectionList.Count*1000);
        Connection:=Scene.VConnectionList.Objects[I] As TVConnection;
        Scene.UpdateConnectionDisplayList(Connection);
        Inc(FixCount);
        FixStringGrid.Cells[1,2]:=IntToStr(FixCount)+' items processed';
        CurrentItemLabel.Caption:='Now checking:'+Connection.Name;
        Application.ProcessMessages;
      End;
  End;

  If DelSamePortConnsCheckBox.Checked Then begin
    FixCount:=0;
    If Scene.VConnectionList.Count>0 Then
      For I:=Scene.VConnectionList.Count-1 DownTo 0 Do Begin
        Connection:=Scene.VConnectionList.Objects[I] As TVConnection;
        If Connection.PortList.Count>0 Then
          For J:=Connection.PortList.Count-1 DownTo 0 Do Begin
            ConnPort:=Connection.PortList.Objects[J] As TVConnectionPort;
            If ConnPort.PortType='Start' Then Begin
              ConnName:=ConnPort.ConnectedObject+':'+ConnPort.ConnectedPort;
              Break;
            End;
          End;
        For J:=Connection.PortList.Count-1 DownTo 0 Do Begin
          ConnPort:=Connection.PortList.Objects[J] As TVConnectionPort;
          If ConnPort.PortType='End' Then
            If (ConnPort.ConnectedObject+':'+ConnPort.ConnectedPort)=(ConnName) Then Begin
              Inc(FixCount);
              FixStringGrid.Cells[1,3]:=IntToStr(FixCount)+' loop connections removed';
              LogMemo.Lines.Add('Problem: loop connection: '+Connection.Name+' '+
              ConnName+' -> '+ConnName+' Action: remove connection.');
              Scene.DeleteConnection(Connection);
            end;
        End;

      end;
  End;
  TotalFixes:=TotalFixes+FixCount;

  If RemoveEmptyPortsCheckBox.Checked Then Begin
    FixCount:=0;
    If Scene.VObjectList.Count>0 Then
      For I:=0 To Scene.VObjectList.Count-1 Do Begin
        Obj:=Scene.VObjectList.Objects[I] As TVObject;
        If Obj.PortList.Count>0 Then
          For J:=Obj.PortList.Count-1 DownTo 0 Do Begin
            Port:=Obj.PortList.Objects[J] As TVPort;
            ConnName:=Port.Connection;
            If Port.Connection='' Then Begin
              Inc(FixCount);
              FixStringGrid.Cells[1,4]:=IntToStr(FixCount)+' empty ports removed';
              LogMemo.Lines.Add('Problem: no connections to port: '+
              Obj.Name+':'+Port.Name+' Action: remove port.');
              Obj.PortList.Delete(J);
              Scene.UpdateObjectDisplayList(Obj);
              Port.Free;
            end;
          end;
      end;
  end;
  TotalFixes:=TotalFixes+FixCount;


  If Obj2ConnMismatchCheckBox.Checked Then Begin
    FixCount:=0;
    If Scene.VObjectList.Count>0 Then
      For I:=0 To Scene.VObjectList.Count-1 Do Begin
        Obj:=Scene.VObjectList.Objects[I] As TVObject;
        If Obj.PortList.Count>0 Then
          For J:=0 To Obj.PortList.Count-1 Do Begin
            Port:=Obj.PortList.Objects[J] As TVPort;
            ConnName:=Port.Connection;
            If Port.Connection='' Then Continue;
            Index:=Scene.VConnectionList.IndexOf(ConnName);
            If Index<0 Then Begin
              // в объекте ссылка на несуществующее соединение
              // освободить порт
              LogMemo.Lines.Add('Problem: object referenced to unexisting connection: '+
              Obj.Name+':'+Port.Name+ '->'+ConnName+':'+Port.ConnectionPort+' Action: reference cleared.');
              Port.Connection:='';
              Port.ConnectionPort:='';
              Inc(FixCount);
            End Else Begin
              // порт соединения должен показывать на этот объект
              Connection:=Scene.VConnectionList.Objects[Index] As TVConnection;
              If Connection.PortList.Count<0 Then Begin
                //соединение без портов - не знаю, бывает ли такое и как чинить
                LogMemo.Lines.Add('Problem: connection has no ports: '+Connection.Name+' Action: don''t know what to do. Leaving as is.');
              end Else Begin
                For K:=0 To Connection.PortList.Count-1 Do Begin
                  ConnPort:=Connection.PortList.Objects[K] As TVConnectionPort;
                  If ConnPort.PortType=Port.ConnectionPort Then Begin
                    // нашли нужный порт
                    If ConnPort.ConnectedObject<>Obj.Name Then Begin
                      // указывает на другой объект
                      Inc(FixCount);
                      FixStringGrid.Cells[1,5]:=IntToStr(FixCount)+' items added';
                      LogMemo.Lines.Add('Problem: referenced connection reference another object: '+
                      Obj.Name+':'+Port.Name+'->'+Connection.Name+':'+Port.ConnectionPort+'->'+
                      ConnPort.ConnectedObject+':'+ConnPort.ConnectedPort+
                      ' Action: Linking connection to first object.');
                      ConnPort.ConnectedObject:=Obj.Name;
                      ConnPort.ConnectedPort:=Port.Name;
                    end;
                    If ConnPort.ConnectedPort<>Port.Name Then Begin
                      // указывает на другой порт этого объекта
                      Inc(FixCount);
                      FixStringGrid.Cells[1,5]:=IntToStr(FixCount)+' items added';
                      LogMemo.Lines.Add('Problem: referenced connection reference another port of this object: '+
                      Obj.Name+':'+Port.Name+'->'+Connection.Name+':'+Port.ConnectionPort+'->'+
                      ConnPort.ConnectedObject+':'+ConnPort.ConnectedPort+
                      ' Action: Linking connection to original port.');
                      ConnPort.ConnectedObject:=Obj.Name;
                      ConnPort.ConnectedPort:=Port.Name;
                    end;
                  end;
                end;
              end;
            End;
          End;
//        FixStringGrid.Cells[1,3]:=IntToStr(FixCount)+' items processed';
        CurrentItemLabel.Caption:='Now checking:'+Obj.Name;
        Application.ProcessMessages;
      End;
    TotalFixes:=TotalFixes+FixCount;
  End;

  If Conn2ObjMismatchCheckBox.Checked Then Begin
    FixCount:=0;
    If Scene.VConnectionList.Count>0 Then Begin
      I:=Scene.VConnectionList.Count-1;
      Repeat
        If I<0 Then Break;
        Connection:=Scene.VConnectionList.Objects[I] As TVConnection;
        If Connection.PortList.Count>0 Then
          For J:=0 To Connection.PortList.Count-1 Do Begin
            ConnPort:=Connection.PortList.Objects[J] As TVConnectionPort;
            If ConnPort.PortType='Text' Then Continue;
            If ConnPort.PortType='Node' Then Continue;
            ObjName:=ConnPort.ConnectedObject;
            If ObjName='' Then Continue;
            Index:=Scene.VObjectList.IndexOf(ObjName);
            If Index<0 Then Begin
              // в соединении ссылка на несуществующий объект
              LogMemo.Lines.Add('Problem: connection referenced to unexisting object: '+
              Connection.Name+':'+ConnPort.PortType+'->'+ConnPort.ConnectedObject+':'+ConnPort.ConnectedPort+' Action: reference cleared.');
              ConnPort.ConnectedObject:='';
              ConnPort.ConnectedPort:='';
              Inc(FixCount);
            End Else Begin
              // порт объекта должен показывать на это соединение
              Obj:=Scene.VObjectList.Objects[Index] As TVObject;
              If Obj.PortList.Count<0 Then Begin
                // объект без портов - не знаю, как чинить создавать порт или валить соединение?
                LogMemo.Lines.Add('Problem: connection references to object with no ports: '+Connection.Name+':'+ConnPort.PortType+'->'+
                ConnPort.ConnectedObject+':'+ConnPort.ConnectedPort+
                ' Action: don''t know what to do. Leaving as is.');
              end Else Begin
                If Obj.PortList.Count>0 Then
                For K:=0 To Obj.PortList.Count-1 Do Begin
                  Port:=Obj.PortList.Objects[K] As TVPort;
                  If Port.Name=ConnPort.ConnectedPort Then Begin
                    // нашли нужный порт
                    If Port.Connection<>Connection.Name Then Begin
                      // указывает на другое соединение
                      Inc(FixCount);
                      FixStringGrid.Cells[1,6]:=IntToStr(FixCount)+' items fixed';
                      //проверим другое соединение
                      Index2:=Scene.VConnectionList.IndexOf(Port.Connection);
                      If Index2<0 Then Begin
                        // другого на самом деле не существует
                        LogMemo.Lines.Add('Problem: referenced object references to unexisting connection: '+
                        Connection.Name+':'+ConnPort.PortType+'->'+Obj.Name+':'+Port.Name+'->'+
                        Port.Connection+':'+Port.ConnectionPort+
                        ' Action: enforce linking connection to the designated port.');
                        Port.Connection:=Connection.Name;
                        Port.ConnectionPort:=ConnPort.PortType;
                      End Else Begin
                        // другое существует
                        Connection2:=Scene.VConnectionList.Objects[Index2] As TVConnection;
                        Index3:=Connection2.PortList.IndexOf(Port.ConnectionPort);
                        If Index3<0 Then Break;
                        ConnPort2:=Connection2.PortList.Objects[Index3] As TVConnectionPort;
                        If (ConnPort2.ConnectedObject=Obj.Name) And (ConnPort2.ConnectedPort=Port.Name) Then Begin
                          // другое соединение более корректно - оставляем его, это дропаем
                          LogMemo.Lines.Add('Problem: referenced object references to another, more correct connection: '+
                          Connection.Name+':'+ConnPort.PortType+'->'+Obj.Name+':'+Port.Name+'->'+
                          Port.Connection+':'+Port.ConnectionPort+
                          ' Action: delete current connection.');

   //                     Scene.DeleteConnection(Connection);
   //                     почему закомментарено?
                          Scene.VConnectionList.Delete(Scene.VConnectionList.IndexOfObject(Connection));
                          Scene.CleanConnectionObjs(Connection);
                          Connection.Free;
                          I:=Scene.VConnectionList.Count;
                          {Break;} Goto NextObj;
                        End Else Begin
                          // другое соединение тоже не айс - нафиг его
                          LogMemo.Lines.Add('Problem: referenced object references to another, also incorrect connection: '+
                          Connection.Name+':'+ConnPort.PortType+'->'+Obj.Name+':'+Port.Name+'->'+
                          Port.Connection+':'+Port.ConnectionPort+
                          ' Action: delete another connection, enforce this connection.');
                          Port.Connection:=Connection.Name;
                          Port.ConnectionPort:=ConnPort.PortType;
//                          Scene.DeleteConnection(Connection2);
                          Scene.VConnectionList.Delete(Scene.VConnectionList.IndexOfObject(Connection2));
                          Scene.CleanConnectionObjs(Connection2);
                          Connection2.Free;
                          I:=Scene.VConnectionList.Count;
                          {Break;} Goto NextObj;
                        End;
                      End;
                    end Else Begin
                      If Port.ConnectionPort<>ConnPort.PortType Then Begin
                        // указывает на другой порт этого соединения
                        Inc(FixCount);
                        FixStringGrid.Cells[1,6]:=IntToStr(FixCount)+' items fixed';
                        LogMemo.Lines.Add('Problem: referenced object references to another port of this connection: '+
                        Connection.Name+':'+ConnPort.PortType+'->'+Obj.Name+':'+Port.Name+'->'+
                        Port.Connection+':'+Port.ConnectionPort+
                        ' Action: adjust object port to connection.');
                        Port.Connection:=Connection.Name;
                        Port.ConnectionPort:=ConnPort.PortType;
                      End;
                    end;
                  end;//Port.name=Connection.Name
                end; //For each port  of object
              end;// object with ports
            End;  //object exists
          End; // for eact connection port
        CurrentItemLabel.Caption:='Now checking:'+Connection.Name;
        Application.ProcessMessages;
NextObj:Dec(I);
      Until I<0;
    End;
  End;
  TotalFixes:=TotalFixes+FixCount;

  If NoCalloutConnectionsCheckBox.Checked Then Begin
    FixCount:=0;
    For I:=0 To Scene.VCalloutList.Count-1 Do Begin
      ProgressBar.Position:=Round(I/Scene.VCalloutList.Count*1000);
      Callout:=Scene.VCalloutList.Objects[I] As TVCallout;
      If Scene.View.IndexOf('DrawCallout '+Callout.Name)<0 Then Begin
        Scene.View.Add('DrawCallout '+Callout.Name);
        Inc(FixCount);
        FixStringGrid.Cells[1,7]:=IntToStr(FixCount)+' items added';
      End;
      CurrentItemLabel.Caption:='Now checking:'+Callout.Name;
    End;

    For I:=0 To Scene.VConnectionList.Count-1 Do Begin
      ProgressBar.Position:=Round(I/Scene.VConnectionList.Count*1000);
      Connection:=Scene.VConnectionList.Objects[I] As TVConnection;
      If Scene.View.IndexOf('DrawConnection '+Connection.Name)<0 Then Begin
         Scene.View.Add('DrawConnection '+Connection.Name);
         Inc(FixCount);
         FixStringGrid.Cells[1,7]:=IntToStr(FixCount)+' items added';
         Application.ProcessMessages;
      end;
      CurrentItemLabel.Caption:='Now checking:'+Connection.Name;
    End;
    Unit1.Scene2GUI;
    Scene.DetectLastItems;
    TotalFixes:=TotalFixes+FixCount;
  End;

  If ExtraDrawingCommandCheckBox.Checked Then Begin
     FixCount:=0;
     For I:=Scene.View.Count-1 Downto 0 Do Begin
       ProgressBar.Position:=Round(I/Scene.View.Count*1000);
       Buf:=Scene.View[I];
       Cmd:=GetNextToken(Buf,ParsedBuf,' ');
       Buf:=ParsedBuf;
       Case Cmd Of
         'DrawCurl': Begin
            Index:=Scene.VCurlList.IndexOf(Buf);
            If Index<0 Then Begin
              Scene.View.Delete(I);
              Inc(FixCount);
              FixStringGrid.Cells[1,8]:=IntToStr(FixCount)+' items removed';
            End;
         End;
         'DrawObject': Begin
            Index:=Scene.VObjectList.IndexOf(Buf);
            If Index<0 Then Begin
              Scene.View.Delete(I);
              Inc(FixCount);
              FixStringGrid.Cells[1,8]:=IntToStr(FixCount)+' items removed';
            End;
         End;
         'DrawCallout': Begin
            Index:=Scene.VCalloutList.IndexOf(Buf);
            If Index<0 Then Begin
              Scene.View.Delete(I);
              Inc(FixCount);
              FixStringGrid.Cells[1,8]:=IntToStr(FixCount)+' items removed';
            End;
         End;
         'DrawConnection': Begin
            Index:=Scene.VConnectionList.IndexOf(Buf);
            If Index<0 Then Begin
              Scene.View.Delete(I);
              Inc(FixCount);
              FixStringGrid.Cells[1,8]:=IntToStr(FixCount)+' items removed';
            End;
         End;
       End;
       CurrentItemLabel.Caption:='Now checking:'+Buf;
     End;
     Unit1.Scene2GUI;
     Scene.DetectLastItems;
     TotalFixes:=TotalFixes+FixCount;
   End;


  CurrentItemLabel.Caption:='Scan completed. Total fixes: '+IntToStr(TotalFixes);
  Unit1.Drawer.Updated:=True;
  Unit1.RepaintView;
end;

procedure TRepairForm.ToggleAllSpeedButtonClick(Sender: TObject);
begin
  FixAllObjectsCheckBox.Checked:=Not FixAllObjectsCheckBox.Checked;
  UpdateDisplayListCheckBox.Checked:=Not UpdateDisplayListCheckBox.Checked;
  DelSamePortConnsCheckBox.Checked:=Not DelSamePortConnsCheckBox.Checked;
  RemoveEmptyPortsCheckBox.Checked:=Not RemoveEmptyPortsCheckBox.Checked;
  Obj2ConnMismatchCheckBox.Checked:=Not Obj2ConnMismatchCheckBox.Checked;
  Conn2ObjMismatchCheckBox.Checked:=Not Conn2ObjMismatchCheckBox.Checked;
  NoCalloutConnectionsCheckBox.Checked:=Not NoCalloutConnectionsCheckBox.Checked;
end;

Procedure TRepairForm.CancelBitBtnClick(Sender: TObject);
Begin
  RepairForm.Close;
end;

Procedure TRepairForm.FormResize(Sender: TObject);
Begin
  FixAllObjectsCheckBox.Parent:=FixStringGrid;
  FixAllObjectsCheckBox.BoundsRect:=FixStringGrid.CellRect(0,1);
  FixStringGrid.Cells[0,1]:='     Fix all objects';

  UpdateDisplayListCheckBox.Parent:=FixStringGrid;
  UpdateDisplayListCheckBox.BoundsRect:=FixStringGrid.CellRect(0,2);
  FixStringGrid.Cells[0,2]:='     Update displaylists';

  DelSamePortConnsCheckBox.Parent:=FixStringGrid;
  DelSamePortConnsCheckBox.BoundsRect:=FixStringGrid.CellRect(0,3);
  FixStringGrid.Cells[0,3]:='     Delete connections from port to the same port';

  RemoveEmptyPortsCheckBox.Parent:=FixStringGrid;
  RemoveEmptyPortsCheckBox.BoundsRect:=FixStringGrid.CellRect(0,4);
  FixStringGrid.Cells[0,4]:='     Remove empty ports';

  Obj2ConnMismatchCheckBox.Parent:=FixStringGrid;
  Obj2ConnMismatchCheckBox.BoundsRect:=FixStringGrid.CellRect(0,5);
  FixStringGrid.Cells[0,5]:='     Objects-to-connections mismatch';

  Conn2ObjMismatchCheckBox.Parent:=FixStringGrid;
  Conn2ObjMismatchCheckBox.BoundsRect:=FixStringGrid.CellRect(0,6);
  FixStringGrid.Cells[0,6]:='     Connections-to-objects mismatch';

  NoCalloutConnectionsCheckBox.Parent:=FixStringGrid;
  NoCalloutConnectionsCheckBox.BoundsRect:=FixStringGrid.CellRect(0,7);
  FixStringGrid.Cells[0,7]:='     No callouts and connections in view';

  ExtraDrawingCommandCheckBox.Parent:=FixStringGrid;
  ExtraDrawingCommandCheckBox.BoundsRect:=FixStringGrid.CellRect(0,8);
  FixStringGrid.Cells[0,8]:='     Drawing commands without items in view';

end;

Procedure TRepairForm.NoCalloutConnectionsCheckBoxChange(Sender: TObject);
Begin

end;


Initialization
  {$I repair.lrs}

End.

