/*
 * Created on 26.09.2005
 */
package org.ganttproject.impex.htmlpdf;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamSource;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobManager;
import org.eclipse.core.runtime.jobs.Job;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;

import net.sourceforge.ganttproject.IGanttProject;
import net.sourceforge.ganttproject.chart.Chart;
import net.sourceforge.ganttproject.export.ExportFinalizationJob;
import net.sourceforge.ganttproject.gui.UIFacade;
import net.sourceforge.ganttproject.gui.options.model.DefaultEnumerationOption;
import net.sourceforge.ganttproject.gui.options.model.EnumerationOption;
import net.sourceforge.ganttproject.gui.options.model.GPOption;
import net.sourceforge.ganttproject.gui.options.model.GPOptionGroup;

abstract class ExporterBase {
    private IGanttProject myProject;
    private Chart myGanttChart;
    private GPOptionGroup myOptions;
    private Chart myResourceChart;
    private SAXTransformerFactory myFactory = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
	private UIFacade myUIFacade;
    
    protected EnumerationOption createStylesheetOption(String optionID, final Stylesheet[] stylesheets) {
        String[] names = new String[stylesheets.length];
        for (int i = 0; i < stylesheets.length; i++) {
            names[i] = stylesheets[i].getLocalizedName();
        }
        EnumerationOption stylesheetOption = new DefaultEnumerationOption(optionID, names) {
            public void commit() {
                super.commit();
                String value = getValue();
                for (int i=0; i<stylesheets.length; i++) {
                    if (stylesheets[i].getLocalizedName().equals(value)) {
                        setSelectedStylesheet(stylesheets[i]);
                    }
                }
            }

        };
        return stylesheetOption;
    }
    protected abstract void setSelectedStylesheet(Stylesheet stylesheet);
    protected abstract Stylesheet[] getStylesheets();
    protected abstract String getStylesheetOptionID();
	static Object EXPORT_JOB_FAMILY = new String("Export job family");
    
    public void run(final File outputFile, final ExportFinalizationJob finalizationJob)
    throws Exception {
        final IJobManager jobManager = Platform.getJobManager();
        final List resultFiles = new ArrayList();
        final Job[] jobs = createJobs(outputFile, resultFiles);
        final IProgressMonitor monitor = jobManager.createProgressGroup();
        final IProgressMonitor familyMonitor = new IProgressMonitor() {
			public void beginTask(String name, int totalWork) {
				monitor.beginTask(name, totalWork);
			}
			public void done() {
				monitor.done();
			}
			public void internalWorked(double work) {
				monitor.internalWorked(work);
			}
			public boolean isCanceled() {
				return monitor.isCanceled();
			}
			public void setCanceled(boolean value) {
				monitor.setCanceled(value);
				if (value) {
					System.err.println("ExporterBase: canceling value="+EXPORT_JOB_FAMILY);
					jobManager.cancel(EXPORT_JOB_FAMILY);
				}
			}
			public void setTaskName(String name) {
				monitor.setTaskName(name);
			}
			public void subTask(String name) {
				monitor.subTask(name);
			}
			public void worked(int work) {
				monitor.worked(work);
			}
        };
        Job starting = new Job("starting") {
			protected IStatus run(IProgressMonitor monitor) {
		        monitor.beginTask("Running export", jobs.length);
		        for (int i=0; i<jobs.length; i++) {
		        	if (monitor.isCanceled()) {
		        		return Status.CANCEL_STATUS;
		        	}
		            jobs[i].setProgressGroup(monitor, 1);
		            jobs[i].schedule();
		            try {
						jobs[i].join();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
		        }
		        Job finishing = new Job("finishing") {
					protected IStatus run(IProgressMonitor monitor) {
						monitor.done();
				        finalizationJob.run((File[]) resultFiles.toArray(new File[0]));
						return Status.OK_STATUS;
					}
		        };
		        finishing.setProgressGroup(monitor, 0);
		        finishing.schedule();
		        try {
					finishing.join();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				return Status.OK_STATUS;
			}
        };
        starting.setProgressGroup(familyMonitor, 0);
        starting.schedule();
    }
    
    protected abstract Job[] createJobs(File outputFile, List resultFiles);
  
    public void setContext(IGanttProject project, UIFacade uiFacade) {
        myGanttChart= uiFacade.getGanttChart();
        myResourceChart = uiFacade.getResourceChart();
        myProject = project;
        myUIFacade = uiFacade;
        final Stylesheet[] stylesheets = getStylesheets();
        EnumerationOption stylesheetOption= createStylesheetOption(getStylesheetOptionID(), stylesheets);
        stylesheetOption.lock();
        stylesheetOption.setValue(stylesheets[0].getLocalizedName());
        stylesheetOption.commit();
        myOptions = new GPOptionGroup("exporter.html", new GPOption[] {stylesheetOption});
        myOptions.setTitled(false);
        
    }
    
    protected UIFacade getUIFacade() {
    	return myUIFacade;
    }
    protected IGanttProject getProject() {
        return myProject;
    }
    protected Chart getGanttChart() {
        return myGanttChart;
    }
    public GPOptionGroup getOptions() {
        return myOptions;
    }
    protected Chart getResourceChart() {
        return myResourceChart;
    }
    
    protected void startElement(String name, AttributesImpl attrs,
            TransformerHandler handler) throws SAXException {
        handler.startElement("", name, name, attrs);
        attrs.clear();
    }

    protected void startPrefixedElement(String name, AttributesImpl attrs,
            TransformerHandler handler) throws SAXException {
        handler.startElement("http://ganttproject.sf.net/", name, "ganttproject:"+name, attrs);
        attrs.clear();
    }
    protected void endElement(String name, TransformerHandler handler)
            throws SAXException {
        handler.endElement("", name, name);
    }
    protected void endPrefixedElement(String name, TransformerHandler handler)
        throws SAXException {
        handler.endElement("http://ganttproject.sf.net/", name, "ganttproject:"+name);
    }

    protected void addAttribute(String name, String value, AttributesImpl attrs) {
        if (value != null) {
            attrs.addAttribute("", name, name, "CDATA", value);
        } else {
            System.err.println("[GanttOptions] attribute '" + name
                    + "' is null");
        }
    }

    protected void emptyElement(String name, AttributesImpl attrs,
            TransformerHandler handler) throws SAXException {
        startElement(name, attrs, handler);
        endElement(name, handler);
        attrs.clear();
    }
    
    protected void textElement(String name, AttributesImpl attrs, String text, TransformerHandler handler) throws SAXException {
        startElement(name, attrs, handler);
        handler.startCDATA();
        handler.characters(text.toCharArray(), 0, text.length());
        handler.endCDATA();
        endElement(name, handler);
        attrs.clear();
    }

    protected SAXTransformerFactory getTransformerFactory() {
        return myFactory;
    }
    
    protected TransformerHandler createHandler(String xsltPath) {
        try {
            TransformerHandler result = getTransformerFactory().newTransformerHandler(new StreamSource(xsltPath));
            Transformer transformer = result.getTransformer();
            transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.setOutputProperty(
                    "{http://xml.apache.org/xslt}indent-amount", "4");
            return result;
            
        } catch (TransformerConfigurationException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
    
}
