File size: 4,850 Bytes
18a519f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
using System.Collections.Generic;
using System.Linq;

namespace Unity.VisualScripting
{
    public abstract class UnitPort<TValidOther, TInvalidOther, TExternalConnection> : IUnitPort
        where TValidOther : IUnitPort
        where TInvalidOther : IUnitPort
        where TExternalConnection : IUnitConnection
    {
        protected UnitPort(string key)
        {
            Ensure.That(nameof(key)).IsNotNull(key);

            this.key = key;
        }

        public IUnit unit { get; set; }

        public string key { get; }

        public IGraph graph => unit?.graph;

        public IEnumerable<IUnitRelation> relations =>
            LinqUtility.Concat<IUnitRelation>(unit.relations.WithSource(this),
                unit.relations.WithDestination(this)).Distinct();

        public abstract IEnumerable<TExternalConnection> validConnections { get; }

        public abstract IEnumerable<InvalidConnection> invalidConnections { get; }

        public abstract IEnumerable<TValidOther> validConnectedPorts { get; }

        public abstract IEnumerable<TInvalidOther> invalidConnectedPorts { get; }

        IEnumerable<IUnitConnection> IUnitPort.validConnections => validConnections.Cast<IUnitConnection>();

        public IEnumerable<IUnitConnection> connections => LinqUtility.Concat<IUnitConnection>(validConnections, invalidConnections);

        public IEnumerable<IUnitPort> connectedPorts => LinqUtility.Concat<IUnitPort>(validConnectedPorts, invalidConnectedPorts);

        public bool hasAnyConnection => hasValidConnection || hasInvalidConnection;

        // Allow for more efficient overrides

        public virtual bool hasValidConnection => validConnections.Any();

        public virtual bool hasInvalidConnection => invalidConnections.Any();

        private bool CanConnectTo(IUnitPort port)
        {
            Ensure.That(nameof(port)).IsNotNull(port);

            return unit != null && // We belong to a unit
                port.unit != null &&    // Port belongs to a unit
                port.unit != unit &&    // that is different than the current one
                port.unit.graph == unit.graph;    // but is on the same graph.
        }

        public bool CanValidlyConnectTo(IUnitPort port)
        {
            return CanConnectTo(port) && port is TValidOther && CanConnectToValid((TValidOther)port);
        }

        public bool CanInvalidlyConnectTo(IUnitPort port)
        {
            return CanConnectTo(port) && port is TInvalidOther && CanConnectToInvalid((TInvalidOther)port);
        }

        public void ValidlyConnectTo(IUnitPort port)
        {
            Ensure.That(nameof(port)).IsNotNull(port);

            if (!(port is TValidOther))
            {
                throw new InvalidConnectionException();
            }

            ConnectToValid((TValidOther)port);
        }

        public void InvalidlyConnectTo(IUnitPort port)
        {
            Ensure.That(nameof(port)).IsNotNull(port);

            if (!(port is TInvalidOther))
            {
                throw new InvalidConnectionException();
            }

            ConnectToInvalid((TInvalidOther)port);
        }

        public void Disconnect()
        {
            while (validConnectedPorts.Any())
            {
                DisconnectFromValid(validConnectedPorts.First());
            }

            while (invalidConnectedPorts.Any())
            {
                DisconnectFromInvalid(invalidConnectedPorts.First());
            }
        }

        public abstract bool CanConnectToValid(TValidOther port);

        public bool CanConnectToInvalid(TInvalidOther port)
        {
            return true;
        }

        public abstract void ConnectToValid(TValidOther port);

        public abstract void ConnectToInvalid(TInvalidOther port);

        public abstract void DisconnectFromValid(TValidOther port);

        public abstract void DisconnectFromInvalid(TInvalidOther port);

        public abstract IUnitPort CompatiblePort(IUnit unit);

        protected void ConnectInvalid(IUnitOutputPort source, IUnitInputPort destination)
        {
            var connection = unit.graph.invalidConnections.SingleOrDefault(c => c.source == source && c.destination == destination);

            if (connection != null)
            {
                return;
            }

            unit.graph.invalidConnections.Add(new InvalidConnection(source, destination));
        }

        protected void DisconnectInvalid(IUnitOutputPort source, IUnitInputPort destination)
        {
            var connection = unit.graph.invalidConnections.SingleOrDefault(c => c.source == source && c.destination == destination);

            if (connection == null)
            {
                return;
            }

            unit.graph.invalidConnections.Remove(connection);
        }
    }
}