/*
* Created on 06-Mar-2008
* Copyright (C) 2008 by Andrea Vacondio.
*
*
* This library is provided under dual licenses.
* You may choose the terms of the Lesser General Public License version 2.1 or the General Public License version 2
* License at your discretion.
*
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*
*
* 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.
*
* 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.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.pdfsam.console.business.pdf.handlers;
import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.pdfsam.console.business.ConsoleServicesFacade;
import org.pdfsam.console.business.dto.Transition;
import org.pdfsam.console.business.dto.WorkDoneDataModel;
import org.pdfsam.console.business.dto.commands.AbstractParsedCommand;
import org.pdfsam.console.business.dto.commands.SlideShowParsedCommand;
import org.pdfsam.console.business.pdf.handlers.interfaces.AbstractCmdExecutor;
import org.pdfsam.console.exceptions.console.ConsoleException;
import org.pdfsam.console.exceptions.console.SlideShowException;
import org.pdfsam.console.utils.FileUtility;
import org.pdfsam.console.utils.perfix.PrefixParser;
import com.lowagie.text.pdf.PdfReader;
import com.lowagie.text.pdf.PdfStamper;
import com.lowagie.text.pdf.PdfTransition;
import com.lowagie.text.pdf.PdfWriter;
import com.lowagie.text.pdf.RandomAccessFileOrArray;
/**
* Command executor for the slideshow command
* @author Andrea Vacondio
*/
public class SlideShowCmdExecutor extends AbstractCmdExecutor {
private static final Logger LOG = Logger.getLogger(SlideShowCmdExecutor.class.getPackage().getName());
private Hashtable transitionsMappingMap = null;
private PdfReader pdfReader = null;
private PdfStamper pdfStamper = null;
public void execute(AbstractParsedCommand parsedCommand) throws ConsoleException {
if((parsedCommand != null) && (parsedCommand instanceof SlideShowParsedCommand)){
SlideShowParsedCommand inputCommand = (SlideShowParsedCommand) parsedCommand;
PrefixParser prefixParser;
setPercentageOfWorkDone(0);
Transitions transitions = new Transitions();
transitions.setDefaultTransition(inputCommand.getDefaultTransition());
transitions.setTransitions(inputCommand.getTransitions());
transitions = parseXmlInput(inputCommand.getInputXmlFile(), transitions);
try{
prefixParser = new PrefixParser(inputCommand.getOutputFilesPrefix(), inputCommand.getInputFile().getFile().getName());
File tmpFile = FileUtility.generateTmpFile(inputCommand.getOutputFile());
pdfReader = new PdfReader(new RandomAccessFileOrArray(inputCommand.getInputFile().getFile().getAbsolutePath()),inputCommand.getInputFile().getPasswordBytes());
pdfReader.removeUnusedObjects();
pdfReader.consolidateNamedDestinations();
//version
LOG.debug("Creating a new document.");
Character pdfVersion = inputCommand.getOutputPdfVersion();
if(pdfVersion != null){
pdfStamper = new PdfStamper(pdfReader, new FileOutputStream(tmpFile), inputCommand.getOutputPdfVersion().charValue());
}else{
pdfStamper = new PdfStamper(pdfReader, new FileOutputStream(tmpFile), pdfReader.getPdfVersion());
}
//creator
HashMap meta = pdfReader.getInfo();
meta.put("Creator", ConsoleServicesFacade.CREATOR);
//compression
setCompressionSettingOnStamper(inputCommand, pdfStamper);
pdfStamper.setMoreInfo(meta);
//fullscreen
if(inputCommand.isFullScreen()){
pdfStamper.setViewerPreferences(PdfWriter.PageModeFullScreen);
}
//sets transitions
if(transitions.getDefaultTransition()==null){
setTransitionsWithoutDefault(transitions);
}else{
int totalPages = pdfReader.getNumberOfPages();
setTransitionsWithDefault(transitions, totalPages);
}
pdfStamper.close();
pdfReader.close();
File outFile = new File(inputCommand.getOutputFile() ,prefixParser.generateFileName());
FileUtility.renameTemporaryFile(tmpFile, outFile, inputCommand.isOverwrite());
LOG.debug("File "+outFile.getCanonicalPath()+" created.");
LOG.info("Slide show options set.");
}catch(Exception e){
throw new SlideShowException(e);
}finally{
setWorkCompleted();
}
}else{
throw new ConsoleException(ConsoleException.ERR_BAD_COMMAND);
}
}
/**
* sets the transitions on the stamper setting the default value if no transition has been set for the page.
* @param defaultTransition
* @param totalPages
* @param transitions
*/
private void setTransitionsWithDefault(Transitions transitions, int totalPages){
LOG.debug("Setting transitions with a default value.");
Transition[] trans = transitions.getTransitions();
Hashtable transitionsMap = new Hashtable(0) ;
if(trans!=null){
transitionsMap = new Hashtable(trans.length);
for(int i=0; i<trans.length; i++){
transitionsMap.put(new Integer(trans[i].getPageNumber()), trans[i]);
}
}
for(int j=1; j<=totalPages; j++){
Object rawTransition = transitionsMap.get(new Integer(j));
if(rawTransition != null){
Transition transition = (Transition) rawTransition;
pdfStamper.setDuration(transition.getDuration(), transition.getPageNumber());
pdfStamper.setTransition(new PdfTransition(getITextTransition(transition.getTransition()),transition.getTransitionDuration()), transition.getPageNumber());
}else{
pdfStamper.setDuration(transitions.getDefaultTransition().getDuration(), j);
pdfStamper.setTransition(new PdfTransition(getITextTransition(transitions.getDefaultTransition().getTransition()),transitions.getDefaultTransition().getTransitionDuration()), j);
}
setPercentageOfWorkDone(((j)*WorkDoneDataModel.MAX_PERGENTAGE)/totalPages);
}
}
/**
* sets the transitions on the stamper when no default transition is set
* @param defaultTransition
* @param transitions
*/
private void setTransitionsWithoutDefault(Transitions transitions){
LOG.debug("Setting transitions without a default value.");
Transition[] trans = transitions.getTransitions();
if(trans!=null && trans.length>0){
for(int i=0; i<trans.length; i++){
pdfStamper.setDuration(trans[i].getDuration(), trans[i].getPageNumber());
pdfStamper.setTransition(new PdfTransition(getITextTransition(trans[i].getTransition()),trans[i].getTransitionDuration()), trans[i].getPageNumber());
setPercentageOfWorkDone(((i+1)*WorkDoneDataModel.MAX_PERGENTAGE)/trans.length);
}
}else{
LOG.warn("No transition to set.");
}
}
/**
* Maps a pdfsam transition to a iText transition.
* If an error occur the PdfTransition.BLINDH is the default transition.
* @param transition
* @return
*/
private int getITextTransition(String transition){
int retVal = PdfTransition.BLINDH;
if(transitionsMappingMap == null){
transitionsMappingMap = new Hashtable(20);
transitionsMappingMap.put(Transition.T_BLINDH, new Integer(PdfTransition.BLINDH));
transitionsMappingMap.put(Transition.T_BLINDV, new Integer(PdfTransition.BLINDV));
transitionsMappingMap.put(Transition.T_BTWIPE, new Integer(PdfTransition.BTWIPE));
transitionsMappingMap.put(Transition.T_DGLITTER, new Integer(PdfTransition.DGLITTER));
transitionsMappingMap.put(Transition.T_DISSOLVE, new Integer(PdfTransition.DISSOLVE));
transitionsMappingMap.put(Transition.T_INBOX, new Integer(PdfTransition.INBOX));
transitionsMappingMap.put(Transition.T_LRGLITTER, new Integer(PdfTransition.LRGLITTER));
transitionsMappingMap.put(Transition.T_LRWIPE, new Integer(PdfTransition.LRWIPE));
transitionsMappingMap.put(Transition.T_OUTBOX, new Integer(PdfTransition.OUTBOX));
transitionsMappingMap.put(Transition.T_RLWIPE, new Integer(PdfTransition.RLWIPE));
transitionsMappingMap.put(Transition.T_SPLITHIN, new Integer(PdfTransition.SPLITHIN));
transitionsMappingMap.put(Transition.T_SPLITHOUT, new Integer(PdfTransition.SPLITHOUT));
transitionsMappingMap.put(Transition.T_SPLITVIN, new Integer(PdfTransition.SPLITVIN));
transitionsMappingMap.put(Transition.T_SPLITVOUT, new Integer(PdfTransition.SPLITVOUT));
transitionsMappingMap.put(Transition.T_TBGLITTER, new Integer(PdfTransition.TBGLITTER));
transitionsMappingMap.put(Transition.T_TBWIPE, new Integer(PdfTransition.TBWIPE));
}
Object iTextTransition = transitionsMappingMap.get(transition);
if(iTextTransition != null){
retVal = ((Integer)iTextTransition).intValue();
}
return retVal;
}
/**
* Parse the input xml file adding the informations to the Transitions object
* @param inputFile
* @param transitions
* @return
*/
private Transitions parseXmlInput(File inputFile, Transitions transitions) throws SlideShowException{
Transitions retVal = transitions;
if(inputFile!=null){
try{
LOG.debug("Parsing xml transitions file "+inputFile.getAbsolutePath());
SAXReader reader = new SAXReader();
Document document = reader.read(inputFile);
Node rootNode = document.selectSingleNode("/transitions");
if(rootNode != null){
Node defType = rootNode.selectSingleNode("@defaulttype");
Node defTransDur = rootNode.selectSingleNode("@defaulttduration");
Node defDur = rootNode.selectSingleNode("@defaultduration");
if(defType != null && defTransDur != null && defDur != null){
if(transitions.getDefaultTransition() != null){
throw new SlideShowException(SlideShowException.ERR_DEFAULT_TRANSITION_ALREADY_SET);
}else{
transitions.setDefaultTransition(new Transition(Transition.EVERY_PAGE, new Integer(defTransDur.getText().trim()).intValue(), defType.getText().trim(), new Integer(defDur.getText().trim()).intValue()));
}
}
List transitionsList = document.selectNodes("/transitions/transition");
for (int i = 0; transitionsList != null && i < transitionsList.size(); i++) {
Node transitionNode = (Node) transitionsList.get(i);
Node type = transitionNode.selectSingleNode("@type");
Node transDuration = transitionNode.selectSingleNode("@tduration");
Node duration = transitionNode.selectSingleNode("@duration");
Node page = transitionNode.selectSingleNode("@pagenumber");
if(type != null && transDuration != null && duration != null && page != null){
transitions.addTransition(new Transition(new Integer(page.getText().trim()).intValue(), new Integer(transDuration.getText().trim()).intValue(), type.getText().trim(), new Integer(duration.getText().trim()).intValue()));
}else{
throw new SlideShowException(SlideShowException.ERR_READING_TRANSITION, new String[] {i+""});
}
}
}else{
throw new SlideShowException(SlideShowException.ERR_READING_XML_TRANSITIONS_FILE);
}
}
catch(Exception e){
throw new SlideShowException(SlideShowException.ERR_READING_XML_TRANSITIONS_FILE, e);
}
}
return retVal;
}
public void clean(){
closePdfReader(pdfReader);
closePdfStamper(pdfStamper);
}
/**
* Model for the transitions set
* @author Andrea Vacondio
*
*/
private static class Transitions {
private Transition defaultTransition;
private List transitions;
public Transitions() {
this.defaultTransition = null;
this.transitions = null;
}
/**
* @return the defaultTransition
*/
public Transition getDefaultTransition() {
return defaultTransition;
}
/**
* @param defaultTransition the defaultTransition to set
*/
public void setDefaultTransition(Transition defaultTransition) {
this.defaultTransition = defaultTransition;
}
/**
* @return the transitions
*/
public Transition[] getTransitions() {
Transition[] retVal = null;
if(transitions != null){
retVal = (Transition[]) transitions.toArray(new Transition[transitions.size()]);
}
return retVal;
}
/**
* @param transitions the transitions to set. If transitions is null nothing happen.
*/
public void setTransitions(Transition[] transitions) {
if(transitions != null){
this.transitions = Arrays.asList(transitions);
}
}
/**
* add the transition to the list if not null
* @param transition
* @return
*/
public boolean addTransition(Transition transition){
boolean retVal = false;
if(transition!= null){
if (transitions == null){
this.transitions = new ArrayList();
}
retVal = this.transitions.add(transition);
}
return retVal;
}
}
}