package nota.oxygen.epub.figures;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import de.schlichtherle.truezip.file.TArchiveDetector;
import de.schlichtherle.truezip.file.TFile;
import de.schlichtherle.truezip.file.TVFS;
import de.schlichtherle.truezip.fs.FsSyncException;
import de.schlichtherle.truezip.fs.archive.zip.JarDriver;
import de.schlichtherle.truezip.socket.sl.IOPoolLocator;
import nota.oxygen.common.BaseAuthorOperation;
import nota.oxygen.common.Utils;
import nota.oxygen.epub.EpubUtils;
import ro.sync.ecss.extensions.api.ArgumentDescriptor;
import ro.sync.ecss.extensions.api.ArgumentsMap;
import ro.sync.ecss.extensions.api.AuthorAccess;
import ro.sync.ecss.extensions.api.AuthorDocumentController;
import ro.sync.ecss.extensions.api.AuthorOperationException;
import ro.sync.ecss.extensions.api.node.AuthorElement;
public class InsertFigureOperation extends BaseAuthorOperation {
private static String ARG_IMAGE_FRAGMENT = "image fragment";
private String imageFragment;
private static String ARG_IMAGE_COMTAINER_FRAGMENT = "image container fragment";
private String imageContainerFragment;
private static String ARG_FROM_ARCHIVE = "from archive";
private static String[] YES_NO = new String[]{"yes", "no"};
private boolean fromArchive;
private String epubFilePath;
@Override
public ArgumentDescriptor[] getArguments() {
return new ArgumentDescriptor[] {
new ArgumentDescriptor(ARG_IMAGE_FRAGMENT, ArgumentDescriptor.TYPE_FRAGMENT, "Image fragment - use $image as placeholder for image url"),
new ArgumentDescriptor(ARG_IMAGE_COMTAINER_FRAGMENT, ArgumentDescriptor.TYPE_FRAGMENT, "Image container fragment - use $images as placeholder for images"),
new ArgumentDescriptor(ARG_FROM_ARCHIVE, ArgumentDescriptor.TYPE_CONSTANT_LIST, "From archive", YES_NO, YES_NO[1])
};
}
@Override
protected void parseArguments(ArgumentsMap args) throws IllegalArgumentException {
imageFragment = (String)args.getArgumentValue(ARG_IMAGE_FRAGMENT);
imageContainerFragment = (String)args.getArgumentValue(ARG_IMAGE_COMTAINER_FRAGMENT);
String temp = (String)args.getArgumentValue(ARG_FROM_ARCHIVE);
fromArchive = YES_NO[0].equals(temp);
}
@Override
public String getDescription() {
return "Inserts figure(s), with the side-effect of updating the ePub navigation documents";
}
@Override
protected void doOperation() throws AuthorOperationException {
epubFilePath = Utils.getZipPath(getAuthorAccess().getEditorAccess().getEditorLocation().toString());
if (epubFilePath == null) epubFilePath = "";
File[] imageFiles = null;
if (fromArchive) {
List<File> files = new ArrayList<File>();
while (true) {
URL imageURL = getAuthorAccess()
.getWorkspaceAccess()
.chooseURL(
"Select image file",
new String[] { "jpg" },
"JPEG",
EpubUtils
.getEpubUrl(
EpubUtils
.getPackageUrl(getAuthorAccess()),
"images/").toString());
if (imageURL == null) {
break;
}
if (!imageURL.toString().contains("zip:file:")) {
showMessage("The choosen file is not contained in an archive");
continue;
}
if (!epubFilePath.equals(Utils.getZipPath(imageURL.toString()))) {
showMessage("The choosen file is from another archive");
continue;
}
String relImageURL = getAuthorAccess().getUtilAccess()
.makeRelative(
getAuthorAccess().getDocumentController()
.getAuthorDocumentNode()
.getXMLBaseURL(), imageURL);
if (relImageURL == null) {
break;
}
files.add(new File(relImageURL));
}
if (files.size() == 0) {
return;
}
imageFiles = files.toArray(new File[0]);
} else {
imageFiles = getAuthorAccess().getWorkspaceAccess().chooseFiles(new File(""), "Select image file", new String[] {"jpg"}, "JPEG");
if (imageFiles == null) {
return;
}
}
if (imageFragment == null) {
throw new AuthorOperationException(ARG_IMAGE_FRAGMENT + " argument is null");
}
String fragmentXml = "";
for (File imageFile : imageFiles) {
if (!fromArchive) {
insertImageToArchive(imageFile);
}
fragmentXml += imageFragment.replace("$imageUrl", "images/"+imageFile.getName());
}
if (imageContainerFragment == null) imageContainerFragment = "";
if (imageContainerFragment.length()>0 && imageFiles.length>1) {
fragmentXml = imageContainerFragment.replace("$images", fragmentXml);
}
int caretPosition = getAuthorAccess().getEditorAccess().getCaretOffset();
getAuthorAccess().getDocumentController().insertXMLFragment(fragmentXml, caretPosition);
addToOpf(imageFiles);
Utils.bringFocusToDocumentTab(getAuthorAccess());
}
public void insertImageToArchive(File imageFile) throws AuthorOperationException {
TArchiveDetector myDetector = new TArchiveDetector("epub", new JarDriver(IOPoolLocator.SINGLETON));
TFile source = new TFile(imageFile);
TFile destination = new TFile(epubFilePath + "/EPUB/images", myDetector);
try {
TVFS.umount();
} catch (FsSyncException e) {
throw new AuthorOperationException(e.getMessage(), e);
}
try {
destination = new TFile(destination, source.getName());
source.cp_rp(destination);
} catch (IOException e) {
throw new AuthorOperationException(e.getMessage(), e);
}
try {
TVFS.umount();
} catch (FsSyncException e) {
throw new AuthorOperationException(e.getMessage(), e);
}
}
public void addToOpf(File[] imageFiles) throws AuthorOperationException {
URL opfUrl = EpubUtils.getPackageUrl(getAuthorAccess());
if (opfUrl == null) {
showMessage("Could not find pagkage file for document");
return;
}
AuthorAccess opfAccess = EpubUtils.getAuthorDocument(getAuthorAccess(), opfUrl);
if (opfAccess == null) {
throw new AuthorOperationException("Could not access pagkage file for document");
}
AuthorDocumentController opfCtrl = opfAccess.getDocumentController();
opfCtrl.beginCompoundEdit();
try {
AuthorElement manifest = getFirstElement(opfCtrl.findNodesByXPath("/package/manifest", true, true, true));
if (manifest == null) {
throw new AuthorOperationException("Found no manifest in package file");
}
for (int i = 0; i < imageFiles.length; i++) {
String fileName = imageFiles[i].getName();
AuthorElement item = getFirstElement(opfCtrl.findNodesByXPath(String.format("/package/manifest/item[@href='images/%s']", fileName), true, true, true));
if (item == null) {
String itemXml = "<item xmlns='" + EpubUtils.OPF_NS + "' media-type='image/jpeg' href='images/" + fileName + "'/>";
opfCtrl.insertXMLFragment(itemXml, manifest.getEndOffset());
}
}
opfCtrl.getUniqueAttributesProcessor().assignUniqueIDs(manifest.getStartOffset(), manifest.getEndOffset(), true);
}
catch (Exception e) {
opfCtrl.cancelCompoundEdit();
throw e;
}
opfCtrl.endCompoundEdit();
}
}