/*
......... 2015 Ivan Mahonin
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
using System;
namespace Contours {
public class Circuit where Parent: class where Child: class {
public class Entry {
readonly Child owner;
Circuit circuit;
Entry previous;
Entry next;
public Entry(Child owner) { this.owner = owner; }
public Child getOwner() { return owner; }
public Circuit getCircuit() { return circuit; }
public Parent getParent() {
Circuit circuit = getCircuit();
return circuit == null ? null : circuit.getOwner();
}
public Entry getPreviousEntry() { return previous; }
public Entry getNextEntry() { return next; }
public Entry getPreviousEntryLinear() {
Entry e = getPreviousEntry();
return e == null || e == circuit.last ? null : e;
}
public Entry getNextEntryLinear() {
Entry e = getNextEntry();
return e == null || e == circuit.first ? null : e;
}
public Child getPrevious() {
Entry e = getPreviousEntry();
return e == null ? null : e.getOwner();
}
public Child getNext() {
Entry e = getNextEntry();
return e == null ? null : e.getOwner();
}
public Child getPreviousLinear() {
Entry e = getPreviousEntryLinear();
return e == null ? null : e.getOwner();
}
public Child getNextLinear() {
Entry e = getNextEntryLinear();
return e == null ? null : e.getOwner();
}
public void unlink() {
if (previous != null) previous.next = next;
if (next != null) next.previous = previous;
if (circuit != null) {
if (circuit.first == this) {
circuit.first = next != this ? next : null;
circuit.last = previous != this ? previous : null;
}
--circuit.count;
circuit = null;
}
previous = null;
next = null;
}
public void insertBack(Circuit circuit) {
unlink();
if (circuit != null) {
if (circuit.empty()) {
this.circuit = circuit;
previous = next = this;
circuit.first = circuit.last = this;
++circuit.count;
} else {
insertAfterOf(circuit.getLastEntry());
}
}
}
public void insertFront(Circuit circuit) {
unlink();
if (circuit != null) {
if (circuit.empty()) {
this.circuit = circuit;
previous = next = this;
circuit.first = circuit.last = this;
++circuit.count;
} else {
insertBeforeOf(circuit.getFirstEntry());
}
}
}
public void insertAfterOf(Entry entry) {
if (entry == this) return;
unlink();
if (entry == null || entry.getCircuit() == null) return;
previous = entry;
next = entry.next;
previous.next = this;
if (next != null) next.previous = this;
circuit = entry.getCircuit();
if (circuit != null) {
if (circuit.getLastEntry() == entry)
circuit.last = this;
++circuit.count;
}
}
public void insertBeforeOf(Entry entry) {
if (entry == this) return;
unlink();
if (entry == null || entry.getCircuit() == null) return;
previous = entry.previous;
next = entry;
if (previous != null) previous.next = this;
next.previous = this;
circuit = entry.getCircuit();
if (circuit != null) {
if (circuit.getFirstEntry() == entry)
circuit.first = this;
++circuit.count;
}
}
public void swapWith(Entry other) {
if (other == this || other == null) return;
if (this.next == other || other.previous == this) {
this.next = other.next;
other.next.previous = this;
other.previous = this.previous;
this.previous.next = other;
this.previous = other;
other.next = this;
return;
}
if (other.next == this || this.previous == other) {
other.next = this.next;
this.next.previous = other;
this.previous = other.previous;
other.previous.next = this;
other.previous = this;
this.next = other;
return;
}
if (other.circuit != null) {
if (other.circuit.first == other)
other.circuit.first = this;
if (other.circuit.last == other)
other.circuit.last = this;
}
if (this.circuit != null) {
if (this.circuit.first == this)
this.circuit.first = other;
if (this.circuit.last == this)
this.circuit.last = other;
}
Circuit otherCircuit = other.circuit;
Entry otherPrevious = other.previous;
Entry otherNext = other.next;
other.circuit = this.circuit;
other.previous = this.previous;
other.next = this.next;
this.circuit = otherCircuit;
this.previous = otherPrevious;
this.next = otherNext;
if (other.previous != null) other.previous.next = other;
if (other.next != null) other.next.previous = other;
if (this.previous != null) this.previous.next = this;
if (this.next != null) this.next.previous = this;
}
public static void swapChains(Circuit a, Circuit b) {
for(Entry e = a.getFirstEntry(); e != null; e = e.getNextEntryLinear())
e.circuit = b;
for(Entry e = b.getFirstEntry(); e != null; e = e.getNextEntryLinear())
e.circuit = a;
}
}
readonly Parent owner;
Entry first;
Entry last;
int count = 0;
public Circuit(Parent owner) { this.owner = owner; }
public Parent getOwner() { return owner; }
public int getCount() { return count; }
public Entry getFirstEntry() { return first; }
public Entry getLastEntry() { return last; }
public Child getFirst() {
Entry e = getFirstEntry();
return e == null ? null : e.getOwner();
}
public Child getLast() {
Entry e = getLastEntry();
return e == null ? null : e.getOwner();
}
public bool empty() { return getFirstEntry() == null; }
public void clear() {
while(!empty()) getFirstEntry().unlink();
}
public void swapWith(Circuit other) {
Entry.swapChains(this, other);
}
}
}