/*
Copyright (C) 2009 Rachel Engel
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 2
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, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package com.isecpartners.gizmo;
import java.awt.Color;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JTextPane;
import javax.swing.text.AbstractDocument;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultHighlighter;
import javax.swing.text.Highlighter;
import javax.swing.text.StyledDocument;
public class BlobScreenUpdater implements Runnable {
private static int numScreen = 0;
private int thisScreen = numScreen++;
private JTextPane pane;
private LinkedBlockingQueue<UpdateRequest> queue = new LinkedBlockingQueue<UpdateRequest>();
private BlobScroller scroller;
private Highlighter highLight;
private Highlighter.HighlightPainter myHighlightPainter = new MyHighlightPainter(new Color(134, 255, 134));
private Highlighter.HighlightPainter editHighlightPainter = new MyHighlightPainter(new Color(255, 255, 255));
private ArrayList<TextBlob> blobs = new ArrayList<TextBlob>();
private boolean cleared = false;
private String savedScreen;
private boolean search = false;
private int editting_pos = -1;
private TextBlob default_edit_highlight = null;
private List<Prefix> prefixes = new LinkedList<Prefix>();
private List<UpdateRequest> saved_requests = new LinkedList<UpdateRequest>();
public BlobScreenUpdater(JTextPane pane, BlobScroller scroller) {
this.pane = pane;
this.scroller = scroller;
highLight = new DefaultHighlighter();
pane.setHighlighter(highLight);
}
public void addUpdate(UpdateRequest update) {
queue.add(update);
}
void clearBlobs() {
this.blobs.clear();
this.pane.setText("");
}
void restore() {
try {
StyledDocument doc = pane.getStyledDocument();
AbstractDocument aDoc = (AbstractDocument) doc;
aDoc.insertString(0, this.savedScreen, null);
highLight = new DefaultHighlighter();
pane.setHighlighter(highLight);
while(saved_requests.size() > 0) {
disassembleAndDispatch(saved_requests.remove(0));
}
} catch (BadLocationException ex) {
Logger.getLogger(BlobScreenUpdater.class.getName()).log(Level.SEVERE, null, ex);
}
}
private void disassembleAndDispatch(UpdateRequest ur) {
if (ur instanceof AggregateRequest) {
AggregateRequest ar = (AggregateRequest) ur;
for (UpdateRequest req : ar.getRequests()) {
dispatch(req);
}
} else {
dispatch(ur);
}
}
private void upOneLine(int pos) {
int delta = 0;
String text = pane.getText();
int prev_endl = text.substring(0, pos).lastIndexOf("\n");
if (prev_endl == -1) {
return;
}
delta = text.substring(prev_endl, pos).length();
int prev_prev_endl = text.substring(0, prev_endl).lastIndexOf("\n");
if (prev_prev_endl == -1) {
return;
}
if (text.substring(prev_prev_endl, prev_endl).length() >= delta) {
delta = (text.substring(prev_prev_endl, prev_endl).length() - delta) + delta;
} else {
editting_pos = prev_endl - 1;
}
moveEditHighlight(pos - delta);
editting_pos -= delta;
}
private int downOneLine(int pos) {
return -1;
}
private void move(MoveRequest moveRequest) {
if (moveRequest.isUp()) {
upOneLine(editting_pos);
} else if (moveRequest.isDown()) {
} else if (moveRequest.isLeft()) {
if (editting_pos - 1 >= default_edit_highlight.getBegin()) {
moveEditHighlight(--editting_pos);
}
} else if (moveRequest.isRight()) {
if (editting_pos + 1 <= default_edit_highlight.getEnd()) {
moveEditHighlight(++editting_pos);
}
}
}
private void moveCaret(int where) {
try {
if (where == MoveCaretRequest.GET_END) {
pane.setCaretPosition(length());
} else {
pane.setCaretPosition(where);
}
} catch (IllegalArgumentException e) {
System.out.println(e);
}
}
public int numBlobs() {
return blobs.size();
}
private int length() {
final int len = pane.getStyledDocument().getLength();
return len;
}
public void add(AddRequest req) {
Prefix prefix = null;
if (req.getPrefix() != null) {
try {
prefix = new Prefix(req.getPrefix().length());
pane.getStyledDocument().insertString(length(), req.getPrefix(), null);
} catch (BadLocationException ex) {
Logger.getLogger(BlobScreenUpdater.class.getName()).log(Level.SEVERE, null, ex);
}
}
HTTPMessage msg = req.getMessage();
int end;
StyledDocument doc = pane.getStyledDocument();
if (req.getBlob() != null) {
end = req.getBlob().getEnd() + 1;
} else {
end = length();
}
TextBlob blob = new TextBlob(end, msg);
blob.setPrefix(prefix);
if (req.getBlob() != null) {
int indx = blobs.indexOf(req.getBlob());
blobs.add(indx + 1, blob);
} else {
blobs.add(blob);
}
int where = blobs.indexOf(blob);
try {
doc.insertString(end, blob.getMsg().header() + req.addendum(), null);
} catch (Exception ex) {
System.out.println(ex);
}
if (req.getBlob() != null) {
for (Iterator<TextBlob> ii = iterator(where + 1); ii.hasNext();) {
(ii.next()).increment(blob.getEnd() - blob.getBegin() + 2);
}
}
req.setEnd(blob.getEnd());
if (req.moveTo()) {
scroller.setCurrent(where);
// expand(blob);
}
if (blobs.size() == 1 || req.moveTo()) {
highlightBlob(blob, true);
}
}
private void moveEditHighlight(int pos) {
try {
highlightBlob(default_edit_highlight, true);
highLight.removeAllHighlights();
highLight.addHighlight(default_edit_highlight.getBegin(), pos, myHighlightPainter);
highLight.addHighlight(pos + 1, default_edit_highlight.getEnd(), myHighlightPainter);
} catch (BadLocationException ex) {
Logger.getLogger(BlobScreenUpdater.class.getName()).log(Level.SEVERE, null, ex);
}
}
public TextBlob get(int index) {
return blobs.get(index);
}
public Iterator<TextBlob> iterator(int ii) {
return blobs.listIterator(ii);
}
public Iterator<TextBlob> iterator() {
return blobs.listIterator();
}
private void print(PrintRequest req) {
StyledDocument doc = pane.getStyledDocument();
try {
doc.insertString(length(), req.getWhat(), null);
req.setEnd(length());
if (blobs.size() == 1) {
highlightBlob(blobs.get(0), true);
}
} catch (Exception ex) {
System.out.println(ex);
}
}
private void highlightBlob(TextBlob blob, boolean down) {
try {
if (blob.getEnd() > length()) {
return;
}
int begin = blob.getBegin();
int end = blob.getEnd();
if (highLight.getHighlights().length > 0) {
highLight.removeAllHighlights();
}
highLight.addHighlight(begin, end, myHighlightPainter);
if (down) {
pane.setCaretPosition(end);
} else {
pane.setCaretPosition(begin);
}
} catch (Exception e) {
System.out.println(e);
}
}
private void remove(RemoveRequest req) {
StyledDocument doc = pane.getStyledDocument();
AbstractDocument aDoc = (AbstractDocument) doc;
int blob_ndx = Integer.MAX_VALUE;
try {
int difference = 0;
for (int ii = 0; ii < blobs.size(); ii++) {
if (ii > blob_ndx) {
blobs.get(ii).increment(-difference);
}
if (blobs.get(ii).getBlobIndex() == req.getBlob().getBlobIndex()) {
TextBlob blob = blobs.get(ii);
if (blob.getPrefix() != null) {
difference = blob.getEnd() - blob.getBegin() + 2 + blob.getPrefix().getLength();
} else {
difference = blob.getEnd() - blob.getBegin() + 2;
}
/* if (length() < (blob.getBegin() + difference)) {
System.out.println("argh");
} else {*/
int begin = blob.getBegin();
if (blob.getPrefix() != null) {
begin -= blob.getPrefix().getLength();
}
aDoc.remove(begin, difference);
// }
blob_ndx = ii;
}
}
} catch (Exception ex) {
Logger.getLogger(BlobScroller.class.getName()).log(Level.SEVERE, null, ex);
}
req.removeBlob();
blobs.remove(req.getBlob());
if (blob_ndx == Integer.MAX_VALUE) {
highlightBlob(scroller.getCurrent(), true);
} else {
if (blob_ndx > 0) {
highlightBlob(blobs.get(blob_ndx - 1), true);
} else {
highlightBlob(blobs.get(0), true);
}
}
}
public void clear() {
try {
StyledDocument doc = pane.getStyledDocument();
AbstractDocument aDoc = (AbstractDocument) doc;
this.savedScreen = aDoc.getText(0, aDoc.getLength());
aDoc.remove(0, aDoc.getLength());
cleared = true;
} catch (Exception e) {
}
}
public void toggleSearch() {
if (search == true) {
search = false;
} else {
search = true;
}
}
public boolean isSearch() {
return search;
}
public void contract(TextBlob blob) {
try {
if (!blob.isExpanded()) {
return;
}
int before_size = blob.text().length();
blob.toggleExpansion();
int after_size = blob.text().length();
AbstractDocument aDoc = (AbstractDocument) pane.getStyledDocument();
int sizeToRemove = before_size - after_size;
aDoc.remove(blob.getBegin() + after_size, sizeToRemove);
for (Iterator<TextBlob> ii = iterator(scroller.getBlobIndex() + 1); ii.hasNext();) {
(ii.next()).increment(-sizeToRemove);
}
highlightBlob(scroller.getCurrent(), true);
} catch (Exception e) {
System.out.println(e);
}
}
public void expand(TextBlob blob) {
try {
if (blob.isExpanded()) {
return;
}
int before_size = blob.text().length();
int before_end = blob.getEnd();
blob.toggleExpansion();
int after_size = blob.text().length();
AbstractDocument aDoc = (AbstractDocument) pane.getStyledDocument();
String contents = blob.text();
contents = contents.substring(contents.indexOf("\r\n") + 2);
aDoc.insertString(before_end, "\r\n" + contents, null);
// need to get the index of the blob here
for (Iterator<TextBlob> ii = iterator(scroller.getBlobIndex() + 1); ii.hasNext();) {
(ii.next()).increment(after_size - before_size);
}
highlightBlob(scroller.getCurrent(), true);
} catch (Exception e) {
System.out.println(e);
}
}
private void dispatch(UpdateRequest ur) {
if (ur instanceof PrintRequest) {
print((PrintRequest) ur);
} else if (ur instanceof RemoveRequest) {
remove(((RemoveRequest) ur));
} else if (ur instanceof HighlightRequest) {
HighlightRequest hr = (HighlightRequest) ur;
highlightBlob(hr.getBlob(), hr.isBool());
} else if (ur instanceof ContractRequest) {
ContractRequest cr = (ContractRequest) ur;
contract(cr.getBlob());
} else if (ur instanceof ExpandRequest) {
ExpandRequest er = (ExpandRequest) ur;
expand(er.getBlob());
} else if (ur instanceof MoveCaretRequest) {
moveCaret(((MoveCaretRequest) ur).getWhere());
} else if (ur instanceof AddRequest) {
add((AddRequest) ur);
} else if (ur instanceof MoveRequest) {
move((MoveRequest) ur);
}
}
public void run() {
while (true) {
try {
UpdateRequest ur = queue.take();
if (!this.search) {
disassembleAndDispatch(ur);
} else {
saved_requests.add(ur);
}
} catch (Exception e) {
System.out.println(e);
}
}
}
}