package nota.oxygen.common.notes;
import ro.sync.ecss.extensions.api.ArgumentDescriptor;
import ro.sync.ecss.extensions.api.ArgumentsMap;
import ro.sync.ecss.extensions.api.AuthorDocumentController;
import ro.sync.ecss.extensions.api.AuthorOperationException;
import ro.sync.ecss.extensions.api.access.AuthorEditorAccess;
import ro.sync.ecss.extensions.api.node.AuthorElement;
import ro.sync.ecss.extensions.api.node.AuthorNode;
import nota.oxygen.common.BaseAuthorOperation;
/**
* Finds and marks up noterefs for the current note
* @author OHA
*
*/
public class FindNoterefOperation extends BaseAuthorOperation {
@Override
public String getDescription() {
String res = "Find note references";
if (noteIdentifier!=null) res += " for "+noteIdentifier;
return res;
}
private AuthorNode findNextCandidate() throws AuthorOperationException {
AuthorNode[] res = getAuthorAccess().getDocumentController().findNodesByXPath(noterefCandidateXPath, false, true, true);
int currentCaretPos = getAuthorAccess().getEditorAccess().getBalancedSelectionStart();
if (res.length==0) return null;
for (int i=res.length-1; i>=0; i--) {
if (currentCaretPos>res[i].getEndOffset()) {
return res[i];
}
}
return res[res.length-1];
}
@Override
protected void doOperation() throws AuthorOperationException {
try {
AuthorDocumentController docCtrl = getAuthorAccess().getDocumentController();
AuthorEditorAccess edtAcc = getAuthorAccess().getEditorAccess();
AuthorNode[] noteCandts = docCtrl.findNodesByXPath(noteXPath, getCurrentElement(), true, true, true, true);
AuthorElement note = null;
if (noteCandts.length>0) {
if (noteCandts[0] instanceof AuthorElement) note = (AuthorElement)noteCandts[0];
}
if (note==null) {
throw new AuthorOperationException("Could not find an ancestor note element");
}
String noteId = null;
if (note.getAttribute("id")!=null) noteId = note.getAttribute("id").getValue();
if (noteId == null) throw new AuthorOperationException("Ancestor note element has no id");
noterefFragment = noterefFragment.replace("$idref", noteId);
noteIdentifier = null;
AuthorNode[] noteIdentifierCandts = docCtrl.findNodesByXPath(noteIdentifierXPath, note, true, true, true, true);
if (noteIdentifierCandts.length>0) {
noteIdentifier = noteIdentifierCandts[0].getTextContent();
}
if (noteIdentifier==null) throw new AuthorOperationException("Fould no note identifier");
noterefCandidateXPath = noterefCandidateXPath.replace("$noteident", noteIdentifier);
boolean found = false;
edtAcc.select(note.getStartOffset(), note.getEndOffset()+1);
int offset = note.getStartOffset();
AuthorNode next = findNextCandidate();
boolean hasTurned = false;//flag indicating if the search has reached the start of the document and continued from the end (searching backwards)
while (next != null) {
found = true;
if ((offset<next.getStartOffset())) {
if (hasTurned) break;
hasTurned = true;
}
offset = next.getStartOffset();
if (hasTurned && (offset < note.getStartOffset())) break;
if (next.getTextContent().indexOf(noteIdentifier)==-1) continue;
offset += next.getTextContent().indexOf(noteIdentifier);
edtAcc.setCaretPosition(next.getStartOffset());
edtAcc.select(offset, offset+noteIdentifier.length());
int answer = showYesNoCancelMessage(getDescription(), "Is the current selection a reference to the note?\n(Note: "+note.getTextContent()+")", 1);
if (answer == -1) break;
if (answer == 1) {
docCtrl.surroundInFragment(noterefFragment, offset, offset+noteIdentifier.length());
}
next = findNextCandidate();
}
if (!found) showMessage("Found no suitable candidates for note identifier '"+noteIdentifier+"'");
edtAcc.setCaretPosition(note.getEndOffset()-2);
}
catch (AuthorOperationException e) {
throw e;
}
catch (Exception e) {
throw new AuthorOperationException(
"Unexpected "+e.getClass().getName()+"occured: "+e.getMessage(),
e);
}
}
private String noteIdentifier;
private static String ARG_NOTEREF_FRAGMENT = "noteref fragment";
private String noterefFragment;
private static String ARG_NOTE_XPATH = "note xpath";
private String noteXPath;
private static String ARG_NOTE_IDENTIFIER_XPATH = "note identifier xpath";
private String noteIdentifierXPath;
private static String ARG_NOTEREF_CANDIDATE_XPATH = "noteref candidate xpath";
private String noterefCandidateXPath;
@Override
public ArgumentDescriptor[] getArguments() {
return new ArgumentDescriptor[] {
new ArgumentDescriptor(ARG_NOTEREF_FRAGMENT, ArgumentDescriptor.TYPE_FRAGMENT, "The noteref fragment - $idref is placeholder for the id of the referenced note"),
new ArgumentDescriptor(ARG_NOTE_XPATH, ArgumentDescriptor.TYPE_XPATH_EXPRESSION, "The XPath used to find the ancestor note"),
new ArgumentDescriptor(ARG_NOTE_IDENTIFIER_XPATH, ArgumentDescriptor.TYPE_XPATH_EXPRESSION, "The XPath used to find the note identifier"),
new ArgumentDescriptor(ARG_NOTEREF_CANDIDATE_XPATH, ArgumentDescriptor.TYPE_XPATH_EXPRESSION, "The XPath used to find noteref candidates - $noteident is placeholder for the note identifier")
};
}
@Override
protected void parseArguments(ArgumentsMap args)
throws IllegalArgumentException {
noterefFragment = (String)args.getArgumentValue(ARG_NOTEREF_FRAGMENT);
noteXPath = (String)args.getArgumentValue(ARG_NOTE_XPATH);
noteIdentifierXPath = (String)args.getArgumentValue(ARG_NOTE_IDENTIFIER_XPATH);
noterefCandidateXPath = (String)args.getArgumentValue(ARG_NOTEREF_CANDIDATE_XPATH);
}
}