/*******************************************************************************
* Copyright (c) 2012-present Jakub Kováč, Jozef Brandýs, Katarína Kotrlová,
* Pavol Lukča, Ladislav Pápay, Viktor Tomkovič, Tatiana Tóthová
*
* 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 <http://www.gnu.org/licenses/>.
******************************************************************************/
package algvis.ds.suffixtree;
import java.awt.Color;
import java.awt.geom.Point2D;
import java.util.Hashtable;
import java.util.Stack;
import algvis.core.DataStructure;
import algvis.core.Node;
import algvis.core.history.HashtableStoreSupport;
import algvis.ds.trie.TrieNode;
import algvis.ui.Fonts;
import algvis.ui.view.View;
public class SuffixTreeNode extends TrieNode {
private SuffixTreeNode suffixLink = null; // also called suffixNode
private boolean packed;
static boolean implicitNodes = false;
public SuffixTreeNode(DataStructure D, int key, int x, int y, boolean packed) {
super(D, key, x, y);
setPacked(packed);
}
public SuffixTreeNode(DataStructure D, int key, char ch, boolean packed) {
super(D, key, ch);
setPacked(packed);
}
public SuffixTreeNode(DataStructure D, int key, boolean packed) {
super(D, key);
setPacked(packed);
}
public SuffixTreeNode(DataStructure D, char ch, int x, int y, boolean packed) {
super(D, ch, x, y);
setPacked(packed);
}
private SuffixTreeNode(DataStructure D, char ch, boolean packed) {
super(D, ch);
setPacked(packed);
}
public SuffixTreeNode(DataStructure D, boolean packed) {
super(D);
setPacked(packed);
}
public SuffixTreeNode(DataStructure D) {
super(D);
setPacked(false);
}
@Override
public SuffixTreeNode getParent() {
return (SuffixTreeNode) super.getParent();
}
@Override
public SuffixTreeNode getChild() {
return (SuffixTreeNode) super.getChild();
}
@Override
public SuffixTreeNode getRight() {
return (SuffixTreeNode) super.getRight();
}
@Override
public SuffixTreeNode getChildWithCH(char ch) {
return (SuffixTreeNode) super.getChildWithCH(ch);
}
public boolean isPacked() {
return packed;
}
public void setPacked(boolean packed) {
this.packed = packed;
}
@Override
protected void drawBg(View v) {
if (implicitNodes) {
super.drawBg(v);
if (isPacked()) {
v.setColor(Color.WHITE);
v.fillCircle(x, y, radius - 1);
}
} else {
if (!isPacked()) {
super.drawBg(v);
}
}
}
SuffixTreeNode addRight(char ch, int x, int y, boolean packed) {
if (getLabel() > ch) {
final SuffixTreeNode u = new SuffixTreeNode(D, ch, packed);
u.setParent(getParent());
u.setRight(this);
getParent().setChild(u);
return u;
} else if (getLabel() == ch) {
return this;
} else {
final SuffixTreeNode v = getRight();
if ((v == null)) {
final SuffixTreeNode u = new SuffixTreeNode(D, ch, packed);
u.setParent(getParent());
setRight(u);
return u;
} else {
if (v.getLabel() > ch) {
final SuffixTreeNode u = new SuffixTreeNode(D, ch, packed);
u.setRight(getRight());
u.setParent(getParent());
setRight(u);
return u;
} else if (v.getLabel() < ch) {
return v.addRight(ch, x, y, packed);
} else {
// if (v.getLabel() == ch)
return v;
}
}
}
}
public TrieNode addChild(char ch, int x, int y, boolean packed) {
final SuffixTreeNode v = getChild();
if (v == null) {
final SuffixTreeNode u = new SuffixTreeNode(D, ch, x, y, packed);
setChild(u);
u.setParent(this);
return u;
} else {
return v.addRight(ch, x, y, packed);
}
}
public SuffixTreeNode getSuffixLink() {
return suffixLink;
}
public void setSuffixLink(SuffixTreeNode suffixLink) {
this.suffixLink = suffixLink;
}
@Override
public void draw(View v) {
if (state == Node.INVISIBLE || getKey() == NULL) {
return;
}
drawBg(v);
drawLabel(v);
drawArrow(v);
drawArc(v);
if (isLeaf() && !isRoot()) {
v.setColor(Color.WHITE);
v.fillCircle(x, y + 11, 7);
v.setColor(Color.BLACK);
if (marked) {
v.drawCircle(x, y + 11, 7);
}
v.drawString(String.valueOf(getKey()), x, y + 10, Fonts.TYPEWRITER);
}
}
void drawSuffixLinks(View v) {
SuffixTreeNode child = getChild();
while (child != null) {
child.drawSuffixLinks(v);
child = child.getRight();
}
if (getSuffixLink() != null) {
if (isPacked()) {
v.setColor(new Color(0xffaaaa));
} else {
v.setColor(new Color(0xcccccc));
}
final SuffixTreeNode w = getSuffixLink();
final Point2D p = v.cut(x, y, w.x, w.y + 1, 10);
v.drawArrow(x, y, (int) p.getX(), (int) p.getY());
v.setColor(Color.BLACK);
}
}
@Override
public void drawTree(View v) {
drawSuffixLinks(v);
super.drawTree(v);
}
@Override
public void drawLabel(View v) {
if (implicitNodes) {
super.drawLabel(v);
} else {
if (getParent() == null) {
return;
}
TrieNode u = this;
final StringBuilder s = new StringBuilder("");
final Stack<Color> col = new Stack<Color>();
if (getChild() == null || getChild().getRight() != null) {
while (u != null && u.getParent() != null
&& u.getParent().getChild() == u && u.getRight() == null) {
s.append(u.ch);
col.add(u.getBgColor());
u = u.getParent();
}
if (u != null && u.getParent() != null) {
s.append(u.ch);
col.add(u.getBgColor());
}
if (u == null) {
System.out.println("Something went wrong at [" + x + ","
+ y + "]");
return;
}
int py = u.y;
if (u.getParent() == null) {
py += 30;
}
s.reverse();
final int fonth = Fonts.TYPEWRITER.fm.getHeight(), len = s
.length();
final int midy = (py + y) / 2, w = 6, h = len * fonth / 2;
final int xx = x;
int yy = midy - fonth * len / 2 - 4;
Color cc = col.pop();
v.setColor(cc);
if (col.empty()) {
v.fillRoundRectangle(xx, yy, 6, fonth / 2.0, 6, 10);
} else {
v.fillRoundRectangle(xx, yy - 3, 6, fonth / 2.0 - 3, 6, 10);
v.fillRect(xx, yy + 3, 6, fonth / 2.0 - 3);
yy += fonth;
while (col.size() > 1) {
cc = col.pop();
v.setColor(cc);
v.fillRect(xx, yy, 6, fonth / 2.0);
//v.setColor(Color.BLACK);
//v.drawRoundRectangle(xx, yy, 6, fonth / 2.0, 0, 0);
yy += fonth;
}
cc = col.pop();
v.setColor(cc);
v.fillRect(xx, yy - 3, 6, fonth / 2.0 - 3);
v.fillRoundRectangle(xx, yy + 3, 6, fonth / 2.0 - 3, 6, 10);
}
v.setColor(Color.BLACK);
v.drawRoundRectangle(x, midy - 12, w, h, 6, 10);
v.setColor(getFgColor());
v.drawVerticalString(s.toString(), x - 3, midy - 1,
Fonts.TYPEWRITER);
// System.out.println(u.y + " " + py + " " + midy + " " + y);
}
}
}
@Override
public void storeState(Hashtable<Object, Object> state) {
super.storeState(state);
HashtableStoreSupport.store(state, hash + "suffixLink", suffixLink);
HashtableStoreSupport.store(state, hash + "packed", packed);
}
@Override
public void restoreState(Hashtable<?, ?> state) {
super.restoreState(state);
final Object suffixLink = state.get(hash + "suffixLink");
if (suffixLink != null) {
this.suffixLink = (SuffixTreeNode) HashtableStoreSupport
.restore(suffixLink);
}
final Object packed = state.get(hash + "packed");
if (packed != null) {
this.packed = (Boolean) HashtableStoreSupport.restore(packed);
}
}
}