

//Domino
import lotus.domino.*;

import java.io.File;

import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.PrintWriter;

import java.net.URLConnection;

//javax
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Source;
import javax.xml.transform.Result;
import javax.xml.transform.URIResolver;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

// FOP
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
import org.apache.fop.apps.FOURIResolver;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.Fop;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.MimeConstants;

// log4j
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

//jdom
import org.jdom.JDOMException;
import org.jdom.output.DOMOutputter;
import org.jdom.output.XMLOutputter;



/**
 * This is the main class for Printing
 */

public class JavaAgent extends AgentBase {

	
	//-------------------------------------------------------------
	//For testing documents in production set this parameters:
	
	private String servername = "domino7dev";
	
	private String databasename = "test.nsf";
	private String OverrideUsername = "";
	private String OverridePassword = "";	

	private int minDocuments = 0;
	private int maxDocuments = 1000;
	
	private boolean deletePDF = true; 
	private boolean deleteHTML = false;
	
	
	//-------------------------------------------------------------
	
	private static Logger logger = Logger.getLogger(JavaAgent.class);

	private String UriResolverServerName = "";

	private String ResourceUsername = "";

	private String ResourcePassword = "";

	private boolean useCustomErrorListener = true;

	private String errorPage = "";

	private String successPage = "";

	private boolean useTidyCleanup = true;

	private String tidyOutputFile = "";

	private String tidyErrorLog = "";

	private String fopConfigFile = "";

	private String log4jConfigFile = "";

	private boolean debugMode = false;

	private String OutDir = "";

	private String xsltfilePath = "";

	private String xsltfilePathHTML = "";

	private String baseDirOutputUrlSucc = "";

	private String dtdFile = "";

	private PrintWriter pw = null;
	private XMLOutputter xmlout = null;
	private ZDocumentFactory zDocFactory = null;


	public void NotesMain() {

		try {
			Session session = getSession();
			AgentContext agentContext = session.getAgentContext();

			Database currentdb = agentContext.getCurrentDatabase();
			logger.debug("Current database: " + currentdb.getTitle());

			this.pw = getAgentOutput();
						
			Agent agent = agentContext.getCurrentAgent();
			readProperties(currentdb);
			
			Database db = session.getDatabase(servername, databasename);
			logger.info("------ DB name: " + db.getFileName() + " servername: "
					+ servername + " ------ ");
			System.out.println("------ DB name: " + db.getFileName()
					+ " servername: " + servername + " ------ ");
			if (!db.isOpen()) {
				db.open();
			}

			View view = db.getView("forPDF");
			logger.info("entry count: " + view.getEntryCount());
			System.out.println("entry count: " + view.getEntryCount());
			Document doc = view.getFirstDocument();
			
			int index = 0;
			while ((doc != null)&&(index < maxDocuments)) {
				System.out.println("INDEX: "+index);
				if (index >= minDocuments) {
					logger.info(index + ": Document printing: "
							+ doc.getItemValueString("Naziv") + " UNIID: "
							+ doc.getUniversalID());

					// Get project properties

					System.out.println("FOP ExampleFO2PDF\n");
					System.out.println("Preparing...");

					if(zDocFactory == null) zDocFactory = new ZDocumentFactory(doc,
							session, dtdFile);
					else {
						zDocFactory.setDoc(doc);
						zDocFactory.setZoblika(doc.getItemValueString("Z_Oblika"));
					}
					ZDokument zDocObj = zDocFactory.newInstance();
					org.jdom.Document domDoc = zDocObj.createDocument();
					if(xmlout == null) xmlout = new XMLOutputter();
					if (debugMode) {
						FileOutputStream fos = new FileOutputStream(OutDir
								+ "/" + doc.getUniversalID() + ".xml");
						xmlout.escapeElementEntities("rtf");
						xmlout.output(domDoc, fos);
						fos = null;
					}
					try {
						if (zDocObj.isTidyValidationSuccess()
								&& (zDocObj.validateDocument(domDoc))) {
							File pdffile = new File(OutDir + "/", doc
									.getUniversalID()
									+ ".pdf");
							File xsltfile = new File(xsltfilePath);
							convertXML2PDF(domDoc, xsltfile, pdffile);

							successPage = baseDirOutputUrlSucc + "/"
									+ doc.getUniversalID() + ".pdf";

							System.out.println("successPage " + successPage);
							this.pw.println("[" + successPage + "]");
							logger
									.info("FopTest "+ index + ": PDF generated "
											+ successPage);
							if (deletePDF) {
								logger.info("DELETED: " + pdffile.getName());
								pdffile.delete();
							}
							zDocObj = null;
							pdffile = null;
							xsltfile = null;
						}
					} catch (JDOMException e) {

						logger.info(index + ": receiving JDOMException: "
								+ doc.getUniversalID() + " "
								+ e.getLocalizedMessage());
						

						File xsltfile = new File(xsltfilePathHTML);
						File htmlfile = new File(OutDir + "/", doc
								.getUniversalID()
								+ ".html");
						convertXML2HTML(domDoc, xsltfile, pw, htmlfile);
						logger
						.info("FopTest "+ index + ": HTML generated "
								+ successPage);
						if (deleteHTML) {
							logger.debug("DELETED: " + htmlfile.getName());
							htmlfile.delete();
						}
						try {
							Document newdoc = doc.copyToDatabase(currentdb);
							newdoc.appendItemValue("pdfFlag", "DTDError");
							newdoc.save();
							logger.info("Copied document " + doc.getUniversalID() + " to current database");
						} catch (NotesException ne) {
							logger.warn("Could not copy document "+ doc.getUniversalID()+" to current database . Error " + ne.getLocalizedMessage());
							
						}
						

					} catch (TransformerException e2) {

						logger.warn(index + ":receiving TransformerException: "
								+ doc.getUniversalID() + " "
								+ e2.getLocalizedMessage());

						File xsltfile = new File(xsltfilePathHTML);
						// convertXML2HTML(domDoc, xsltfile, htmlfile);
						File htmlfile = new File(OutDir + "/", doc
								.getUniversalID()
								+ ".html");
						convertXML2HTML(domDoc, xsltfile, pw, htmlfile);
						logger
						.info("FopTest "+ index + ": HTML generated "
								+ successPage);
						if (deleteHTML) {
							logger.info("DELETED: " + htmlfile.getName());
							htmlfile.delete();
						}
						try {
							Document newdoc = doc.copyToDatabase(currentdb);
							newdoc.appendItemValue("pdfFlag", "DTDError");
							newdoc.save();
							logger.info("Copied document " + doc.getUniversalID() + " to current database");
						} catch (NotesException ne) {
							logger.warn("Could not copy document "+ doc.getUniversalID()+" to current database . Error " + ne.getLocalizedMessage());
							
						}

					} catch (Exception e3) {
						logger
								.error(index
										+ " : receiving unhandeled Exception for document : "
										+ doc.getUniversalID() + " "
										+ e3.getLocalizedMessage());
						logger
						.info("FopTest "+ index + ": Unhandeled Exception "
								+ doc
								.getUniversalID());
						try {
							Document newdoc = doc.copyToDatabase(currentdb);
							newdoc.appendItemValue("pdfFlag", "UnknownError");
							newdoc.save();
							logger.info("Copied document " + doc.getUniversalID() + " to current database");
						} catch (NotesException ne) {
							logger.warn("Could not copy document "+ doc.getUniversalID()+" to current database . Error " + ne.getLocalizedMessage());
							
						}
					}
					domDoc = null;
					zDocObj = null;
				}
				
				doc = view.getNextDocument(doc);
				index++;
				
			}
			
		} catch (Exception e) {
			logger.fatal("Exception v Notes Main " + e.getMessage());
			e.printStackTrace(System.err);
			// Error -> print error for user
			this.pw.println("[" + errorPage + "]");
			System.exit(-1);
		}

	}

	private void readProperties(Database db) throws NotesException {
		Document pDoc = db.getProfileDocument("Nastavitve", "");

		log4jConfigFile = pDoc.getItemValueString("log4jConfigFile");
		logger.debug("log4J Config file: " + log4jConfigFile);

		try {
			File log4jConfig = new File(log4jConfigFile);
			if (log4jConfig.length() > 0) {
				logger.debug("Loading Log4J configuration");
				PropertyConfigurator.configure(log4jConfigFile);
			}
		} catch (Exception e) {
			logger
					.warn("Log4J configuration file incorrect! using default config settings");
		}

		// This is needed for getting image resources from notes database
		UriResolverServerName = pDoc
				.getItemValueString("UriResolverServerName");
		logger.debug("UriResolverServerName: " + UriResolverServerName);

		ResourceUsername = pDoc.getItemValueString("ResourceUsername");
		logger.debug("ResourceUsername: " + ResourceUsername);

		ResourcePassword = pDoc.getItemValueString("ResourcePassword");
		logger.debug("ResourcePassword: " + ResourcePassword);

		String usemylistener = pDoc
				.getItemValueString("useCustomErrorListener");
		if (usemylistener.equalsIgnoreCase("Yes")) {
			useCustomErrorListener = true;
			logger.debug("using Custom Error Listener");
		} else {
			useCustomErrorListener = false;
			logger
					.warn("NOT using Custom Error Listener. The system might behave incorrect");
		}

		String useTidy = pDoc.getItemValueString("useTidyCleaner");

		if (useTidy.equalsIgnoreCase("Yes")) {
			useTidyCleanup = true;
			logger.debug("using Tidy Cleaner");
		} else {
			useTidyCleanup = false;
			logger.warn("NOT using Tidy Cleaner");
		}
		String isDebug = pDoc.getItemValueString("DebugMode");

		if (isDebug.equalsIgnoreCase("Yes")) {
			debugMode = true;
			logger.debug("Using debugMode : Yes");
		} else {
			debugMode = false;
			logger.warn("Using debugMode : No");
		}
		tidyOutputFile = pDoc.getItemValueString("TidyOutputFile");
		logger.debug("useTidyCleanup = " + tidyOutputFile);

		tidyErrorLog = pDoc.getItemValueString("TidyErrorLog");
		logger.debug("tidyErrorLog = " + tidyErrorLog);

		fopConfigFile = pDoc.getItemValueString("fopConfigFile");
		logger.debug("fopConfigFile = " + fopConfigFile);

		errorPage = pDoc.getItemValueString("ErrorPage");
		logger.debug("errorPage = " + errorPage);

		xsltfilePath = pDoc.getItemValueString("InputXsl");
		logger.debug("xsltfilePath = " + xsltfilePath);
		xsltfilePathHTML = pDoc.getItemValueString("InputXslHTML");
		logger.debug("xsltfilePathHTML = " + xsltfilePathHTML);
		OutDir = pDoc.getItemValueString("OutDir");
		logger.debug("OutDir = " + OutDir);

		baseDirOutputUrlSucc = pDoc.getItemValueString("SuccessPage");
		logger.debug("baseDirOutputUrlSucc = " + baseDirOutputUrlSucc);

		dtdFile = pDoc.getItemValueString("DTDFile");
		logger.debug("dtdFile = " + dtdFile);

	}

	public void convertXML2HTML(org.jdom.Document domDoc, File xsltfile,
			PrintWriter pw, File htmlfile) throws JDOMException, TransformerException {

		// Setup input for XSLT transformation
		DOMOutputter output = new DOMOutputter();

		// Create dom from jdom
		org.w3c.dom.Document dom = output.output(domDoc);
		Source xmlSource = new DOMSource(dom);
		// JAXP reads data using the Source interface
		// Source xmlSource = new StreamSource(xmlFile);
		Source xsltSource = new StreamSource(xsltfile);

		// the factory pattern supports different XSLT processors
		TransformerFactory transFact = TransformerFactory.newInstance();
		Transformer trans = transFact.newTransformer(xsltSource);

		// Result res = new SAXResult(htmlfile);
		if(htmlfile != null){
			trans.transform(xmlSource, new StreamResult(htmlfile));
		}
		else trans.transform(xmlSource, new StreamResult(pw));
		
		

	}
	private URIResolver myResolver = null;
	private FopFactory fopFactory = null;
	private DefaultConfigurationBuilder cfgBuilder = null;
	private FOUserAgent foUserAgent = null;
	
	private TransformerFactory factory = null;
	private Transformer transformer = null;
	private DOMOutputter output = null;
	//private Result res = null;
	public void convertXML2PDF(org.jdom.Document domDoc, File xsltfile,
			File pdffile) throws Exception {

		try {

			if(myResolver == null) {
			myResolver = new FOURIResolver() {
				protected void updateURLConnection(URLConnection connection,
						String href) {
					logger.debug("In updateURLConnection. href: " + href);
					String effURL = connection.getURL().toExternalForm();
					if (effURL.startsWith(UriResolverServerName)
							&& (!UriResolverServerName.equalsIgnoreCase(""))) {

						applyHttpBasicAuthentication(connection,
								ResourceUsername, ResourcePassword);
						logger.debug("Basic authentication set for effURL:" + effURL);
					
					}else{
						logger.debug("Basic authentication not set effURL:" + effURL);
					}
					if(effURL.startsWith("http://"+servername+"/")){
						
						String newUser = (!OverrideUsername.equalsIgnoreCase(""))?OverrideUsername:ResourceUsername;
						String newPassword = (!OverridePassword.equalsIgnoreCase(""))?OverridePassword:ResourcePassword;
						applyHttpBasicAuthentication(connection,
								newUser, newPassword);
					}
					else{
						logger.debug("Basic authentication not set effURL:" + effURL);
					}
				}
			};
			}
			System.out.println("Transforming...");

			// configure fopFactory as desired
			if (fopFactory == null) {
				fopFactory = FopFactory.newInstance();
			

			if(cfgBuilder == null) {
				cfgBuilder = new DefaultConfigurationBuilder();
			}
			if (!fopConfigFile.equalsIgnoreCase("")) {
				Configuration cfg = cfgBuilder.buildFromFile(new File(fopConfigFile));
				fopFactory.setUserConfig(cfg);
				logger.debug("Custom configuration set: " + fopConfigFile);
			}}
			

			if(foUserAgent == null) {
				foUserAgent = fopFactory.newFOUserAgent();
				// configure foUserAgent as desired
				foUserAgent.setURIResolver(myResolver);
			}

			OutputStream out = new java.io.FileOutputStream(pdffile);
			out = new java.io.BufferedOutputStream(out);

			try {
				// Construct fop with desired output format

				Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF,
						foUserAgent, out);

				// Setup XSLT
				if (factory == null) factory = TransformerFactory.newInstance();

				
				 if(transformer == null) {
					 transformer = factory
				 
				
						.newTransformer(new StreamSource(xsltfile));

					transformer.setParameter("versionParam", "2.0");
				
					MyErrorListener myErrorListener = new MyErrorListener();
	
					if (useCustomErrorListener) {
						transformer.setErrorListener(myErrorListener);
						logger.debug("Setting custom ErrorListener");
					}
					System.out.println("transformer set up");
				 }
					
				

				// Setup input for XSLT transformation
				if(output == null) output = new DOMOutputter();

				// Create dom from jdom
				org.w3c.dom.Document dom = output.output(domDoc);
				Source src = new DOMSource(dom);

				// Resulting SAX events (the generated FO) must be piped through
				// to FOP
				Result res = new SAXResult(fop.getDefaultHandler());

				try {
					transformer.transform(src, res);
					// this.pw.println("[" + this.getSuccessPage() + "]");
					logger.debug("Success: " + successPage);
					fop = null;
					src = null;
					res = null;

				} catch (TransformerException e) {
					logger.debug("Transformer Exception "
							+ e.getMessageAndLocation());
					fop = null;
					src = null;
					res = null;
					throw (e);
				}

			} finally {
				out.close();
				
			}

		} catch (Exception e) {
			System.out.println("Ujel exception v convertToXML");
			logger.fatal(e);
			// System.exit(-1);
			/*
			if (e instanceof TransformerException)
				throw (e);
				*/
			throw (e);
		}

	}

}