A game about forced loneliness, made by TACStudios
1using System.Collections.Generic;
2using System.Linq;
3
4namespace Unity.VisualScripting
5{
6 public abstract class UnitPort<TValidOther, TInvalidOther, TExternalConnection> : IUnitPort
7 where TValidOther : IUnitPort
8 where TInvalidOther : IUnitPort
9 where TExternalConnection : IUnitConnection
10 {
11 protected UnitPort(string key)
12 {
13 Ensure.That(nameof(key)).IsNotNull(key);
14
15 this.key = key;
16 }
17
18 public IUnit unit { get; set; }
19
20 public string key { get; }
21
22 public IGraph graph => unit?.graph;
23
24 public IEnumerable<IUnitRelation> relations =>
25 LinqUtility.Concat<IUnitRelation>(unit.relations.WithSource(this),
26 unit.relations.WithDestination(this)).Distinct();
27
28 public abstract IEnumerable<TExternalConnection> validConnections { get; }
29
30 public abstract IEnumerable<InvalidConnection> invalidConnections { get; }
31
32 public abstract IEnumerable<TValidOther> validConnectedPorts { get; }
33
34 public abstract IEnumerable<TInvalidOther> invalidConnectedPorts { get; }
35
36 IEnumerable<IUnitConnection> IUnitPort.validConnections => validConnections.Cast<IUnitConnection>();
37
38 public IEnumerable<IUnitConnection> connections => LinqUtility.Concat<IUnitConnection>(validConnections, invalidConnections);
39
40 public IEnumerable<IUnitPort> connectedPorts => LinqUtility.Concat<IUnitPort>(validConnectedPorts, invalidConnectedPorts);
41
42 public bool hasAnyConnection => hasValidConnection || hasInvalidConnection;
43
44 // Allow for more efficient overrides
45
46 public virtual bool hasValidConnection => validConnections.Any();
47
48 public virtual bool hasInvalidConnection => invalidConnections.Any();
49
50 private bool CanConnectTo(IUnitPort port)
51 {
52 Ensure.That(nameof(port)).IsNotNull(port);
53
54 return unit != null && // We belong to a unit
55 port.unit != null && // Port belongs to a unit
56 port.unit != unit && // that is different than the current one
57 port.unit.graph == unit.graph; // but is on the same graph.
58 }
59
60 public bool CanValidlyConnectTo(IUnitPort port)
61 {
62 return CanConnectTo(port) && port is TValidOther && CanConnectToValid((TValidOther)port);
63 }
64
65 public bool CanInvalidlyConnectTo(IUnitPort port)
66 {
67 return CanConnectTo(port) && port is TInvalidOther && CanConnectToInvalid((TInvalidOther)port);
68 }
69
70 public void ValidlyConnectTo(IUnitPort port)
71 {
72 Ensure.That(nameof(port)).IsNotNull(port);
73
74 if (!(port is TValidOther))
75 {
76 throw new InvalidConnectionException();
77 }
78
79 ConnectToValid((TValidOther)port);
80 }
81
82 public void InvalidlyConnectTo(IUnitPort port)
83 {
84 Ensure.That(nameof(port)).IsNotNull(port);
85
86 if (!(port is TInvalidOther))
87 {
88 throw new InvalidConnectionException();
89 }
90
91 ConnectToInvalid((TInvalidOther)port);
92 }
93
94 public void Disconnect()
95 {
96 while (validConnectedPorts.Any())
97 {
98 DisconnectFromValid(validConnectedPorts.First());
99 }
100
101 while (invalidConnectedPorts.Any())
102 {
103 DisconnectFromInvalid(invalidConnectedPorts.First());
104 }
105 }
106
107 public abstract bool CanConnectToValid(TValidOther port);
108
109 public bool CanConnectToInvalid(TInvalidOther port)
110 {
111 return true;
112 }
113
114 public abstract void ConnectToValid(TValidOther port);
115
116 public abstract void ConnectToInvalid(TInvalidOther port);
117
118 public abstract void DisconnectFromValid(TValidOther port);
119
120 public abstract void DisconnectFromInvalid(TInvalidOther port);
121
122 public abstract IUnitPort CompatiblePort(IUnit unit);
123
124 protected void ConnectInvalid(IUnitOutputPort source, IUnitInputPort destination)
125 {
126 var connection = unit.graph.invalidConnections.SingleOrDefault(c => c.source == source && c.destination == destination);
127
128 if (connection != null)
129 {
130 return;
131 }
132
133 unit.graph.invalidConnections.Add(new InvalidConnection(source, destination));
134 }
135
136 protected void DisconnectInvalid(IUnitOutputPort source, IUnitInputPort destination)
137 {
138 var connection = unit.graph.invalidConnections.SingleOrDefault(c => c.source == source && c.destination == destination);
139
140 if (connection == null)
141 {
142 return;
143 }
144
145 unit.graph.invalidConnections.Remove(connection);
146 }
147 }
148}