package jfractionlab.officeMachine;


import java.io.File;

import javax.swing.JOptionPane;

import jfractionlab.JFractionLab;
import jfractionlab.exerciseGenerator.ExerciseGenerator;
import jfractionlab.exerciseGenerator.Exercises;

import com.sun.star.beans.PropertyValue;
import com.sun.star.beans.PropertyVetoException;
import com.sun.star.beans.UnknownPropertyException;
import com.sun.star.beans.XPropertySet;
import com.sun.star.comp.helper.Bootstrap;
import com.sun.star.comp.helper.BootstrapException;
import com.sun.star.container.NoSuchElementException;

import com.sun.star.container.XNameAccess;
import com.sun.star.document.XEmbeddedObjectSupplier2;
import com.sun.star.frame.XComponentLoader;
import com.sun.star.frame.XDesktop;

import com.sun.star.lang.IllegalArgumentException;
import com.sun.star.lang.IndexOutOfBoundsException;
import com.sun.star.lang.WrappedTargetException;
import com.sun.star.lang.XComponent;
import com.sun.star.lang.XMultiComponentFactory;
import com.sun.star.lang.XMultiServiceFactory;
import com.sun.star.table.XCell;
import com.sun.star.table.XCellRange;
import com.sun.star.text.XText;
import com.sun.star.text.XTextContent;
import com.sun.star.text.XTextDocument;
import com.sun.star.text.XTextRange;
import com.sun.star.text.XTextTable;
import com.sun.star.text.XTextTablesSupplier;
import com.sun.star.uno.Exception;
import com.sun.star.uno.UnoRuntime;
import com.sun.star.uno.XComponentContext;


public class OfficeMachine{

	private XComponent xComponent = null;
	private XTextDocument xTextDocument = null;
	private XMultiServiceFactory xMultiServiceFactory = null;
	
	private String[] arAllTextTables;
	private int nb_of_exercises;
	static XMultiComponentFactory xMCF = null;

	private XTextTablesSupplier xTextTablesSupplier;
	private XNameAccess xNameAccess_TextTables;
	private XTextTable xTextTable;
	private XCellRange xCellRange;
	private XCell xCell;
	private XText xText;
	private XTextContent xTextContent;
	private XPropertySet xPS;
	private XTextRange xRange;
	private XEmbeddedObjectSupplier2 xEmbeddedObjectSupplier;
	private XComponent xEmbeddedObjectModel;
	private XPropertySet xFormulaProperties;

	
	
	
	Exercises ex;
	
	public OfficeMachine(
			File file,
			int type,
			int max1,
			int max2
	){
		if(openDocumentAsTemplate(file)){
			if(checkDocument()){
				ex = new ExerciseGenerator().getOneTypeExercises(
						type,
						max1,
						max2,
						nb_of_exercises
				);
				fillTables();
			}
		}
	}
	
	public boolean checkDocument(){
		boolean isWithTitle = false;
		boolean numeration_is_ok = true;
		String wrongString = "";
		int nbnb = 0;
		int nbcl = 0;
		int nbsl = 0;
		
		XTextTablesSupplier xTextTablesSupplier = (XTextTablesSupplier)UnoRuntime.queryInterface(
				XTextTablesSupplier.class, xComponent
		);
		
		XNameAccess xNameAccess_TextTables = xTextTablesSupplier.getTextTables();
		arAllTextTables = xNameAccess_TextTables.getElementNames();
		try {
			String str = "";
			//walk through all texttables
			for(int x = 0; x< arAllTextTables.length; x++){
					//connect to the texttable
					XTextTable xTextTable = (XTextTable)UnoRuntime.queryInterface(
							XTextTable.class,
							xNameAccess_TextTables.getByName(arAllTextTables[x])
					);
					//walk through all columns
					for(int y = 0; y < xTextTable.getColumns().getCount(); y++){
						//walk through all rows
						for(int z = 0; z < xTextTable.getRows().getCount(); z++){
							XCellRange xCellRange = (XCellRange) UnoRuntime.queryInterface(
									XCellRange.class, xTextTable
							);
							XCell xCell = xCellRange.getCellByPosition(y,z); // cols, rows
							XText xText = (XText) UnoRuntime.queryInterface(XText.class, xCell);
							str = xText.getString();
							if(str.equals("ti")){
								isWithTitle = true;
							}else if(str.startsWith("nb")){
								nbnb++;
								try {
									Integer.valueOf(str.substring(2));
								} catch (NumberFormatException e) {
									numeration_is_ok = false;
									wrongString = str;
								}
							}else if(str.startsWith("cl")){
								nbcl++;
								try {
									Integer.valueOf(str.substring(2));
								} catch (NumberFormatException e) {
									numeration_is_ok = false;
									wrongString = str;
								}
							}else if(str.startsWith("sl")){
								nbsl++;
								try {
									Integer.valueOf(str.substring(2));
								} catch (NumberFormatException e) {
									numeration_is_ok = false;
									wrongString = str;
								}
							}
						}
					}
			}
		} catch (NoSuchElementException e) {
			e.printStackTrace();
			JFractionLab.worksheetProcessIsOK = false;
		} catch (WrappedTargetException e) {
			e.printStackTrace();
			JFractionLab.worksheetProcessIsOK = false;
		} catch (IndexOutOfBoundsException e) {
			e.printStackTrace();
			JFractionLab.worksheetProcessIsOK = false;
		}
		
		nb_of_exercises = nbnb;
		
		if(!isWithTitle){
			JFractionLab.worksheetProcessIsOK = false;
			JOptionPane.showMessageDialog(null,
					lang.Messages.getString("template_has_no_title_bookmark")+"\n"+
					lang.Messages.getString("please_correct_save_and_try_again")
			);
		}
		if(nbsl > 0){
			if(nb_of_exercises != nbsl){
				JFractionLab.worksheetProcessIsOK = false;
				JOptionPane.showMessageDialog(null,
						lang.Messages.getString("template_wrong_nb_of_sl_marker")+"\n"+
						lang.Messages.getString("please_correct_save_and_try_again")
				);
			}
		}
		if(nbcl > 0){
			if(nb_of_exercises != nbcl){
				JFractionLab.worksheetProcessIsOK = false;
				JOptionPane.showMessageDialog(null,
						lang.Messages.getString("template_wrong_nb_of_cl_marker")+"\n"+
						lang.Messages.getString("please_correct_save_and_try_again")
				);
			}
		}
		if(!numeration_is_ok){
			JFractionLab.worksheetProcessIsOK = false;
			JOptionPane.showMessageDialog(null,
					lang.Messages.getString("numeration_is_not_ok")+"\n"+
					lang.Messages.getString("wrong_marker")+" = "+wrongString+"\n"+
					lang.Messages.getString("please_correct_save_and_try_again")
			);
		}
		return JFractionLab.worksheetProcessIsOK;
	}

	private void fillTables(){
		xTextTablesSupplier = (XTextTablesSupplier)UnoRuntime.queryInterface(
				XTextTablesSupplier.class, xComponent
		);
		xNameAccess_TextTables = xTextTablesSupplier.getTextTables();
		arAllTextTables = xNameAccess_TextTables.getElementNames();
		try {
			String strCell = "";
			//walk through all texttables
			for(int tables = 0; tables< arAllTextTables.length; tables++){
				//connect to the texttable
				xTextTable = (XTextTable)UnoRuntime.queryInterface(
						XTextTable.class,
						xNameAccess_TextTables.getByName(arAllTextTables[tables])
				);
				//walk through all columns
				for(int columns = 0; columns < xTextTable.getColumns().getCount(); columns++){
					//walk through all rows
					for(int rows = 0; rows < xTextTable.getRows().getCount(); rows++){
						xCellRange = (XCellRange) UnoRuntime.queryInterface(
								XCellRange.class, xTextTable
						);
						xCell = xCellRange.getCellByPosition(columns,rows); // cols, rows
						xText = (XText) UnoRuntime.queryInterface(XText.class, xCell);
						strCell = xText.getString();

						if(strCell.equals("ti")){
							xText.setString(ex.getTitle());
						}else if(strCell.startsWith("nb")){
							insertObject(
								ex.getAlExercises().get(
									Integer.valueOf(
										strCell.trim().substring(2)
									)-1
								)
							);
						}else if(strCell.startsWith("cl")){
							insertObject(
								ex.getAlCalculations().get(
									Integer.valueOf(
										strCell.trim().substring(2)
									)-1
								)
								);
						}else if(strCell.startsWith("sl")){
							insertObject(
								ex.getAlSolutions().get(
									Integer.valueOf(
										strCell.trim().substring(2)
									)-1
								)
							);
						}
					}
				}
			}
		} catch (NumberFormatException e) {
			e.printStackTrace();
		} catch (NoSuchElementException e) {
			e.printStackTrace();
		} catch (WrappedTargetException e) {
			e.printStackTrace();
		} catch (IndexOutOfBoundsException e) {
			e.printStackTrace();
		}
	}
	
	private void insertObject(String str){
		try {
			xTextContent = (XTextContent)UnoRuntime.queryInterface(
					XTextContent.class, 
					xMultiServiceFactory.createInstance( "com.sun.star.text.TextEmbeddedObject" )
			);
			// set class id for mathformula object to determine the type of object to be inserted
			xPS = (XPropertySet)UnoRuntime.queryInterface(XPropertySet.class, xTextContent);
			xPS.setPropertyValue("CLSID", "078B7ABA-54FC-457F-8551-6147e776a997");
			
			xText.setString("");
			//insert object in document
			xText = (XText) UnoRuntime.queryInterface(XText.class, xCell);
			xRange = (XTextRange)UnoRuntime.queryInterface(
					XTextRange.class, xCell);
			xRange.getStart();
			
			xText.insertTextContent( xRange, xTextContent, false );
			xEmbeddedObjectSupplier = 
				(XEmbeddedObjectSupplier2)UnoRuntime.queryInterface(
						XEmbeddedObjectSupplier2.class,xTextContent);

			xEmbeddedObjectModel = xEmbeddedObjectSupplier.getEmbeddedObject();

			xFormulaProperties =(XPropertySet)UnoRuntime.queryInterface(
					XPropertySet.class,xEmbeddedObjectModel);
			xFormulaProperties.setPropertyValue(
					//"Formula", "1 {5}over{9} + 3 {5}over{9} = 5 {1}over{9}");
					"Formula", str);
		} catch (UnknownPropertyException e) {
			e.printStackTrace();
		} catch (PropertyVetoException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (WrappedTargetException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	public boolean openDocumentAsTemplate(File file){
		XDesktop xDesktop = null;
		xDesktop = getDesktop();

		
		XComponentLoader xComponentLoader = (XComponentLoader)UnoRuntime.queryInterface(
				XComponentLoader.class, xDesktop);
		
		try {
			PropertyValue[] pPropValues = new PropertyValue[1];
			pPropValues[0] = new PropertyValue();
			pPropValues[0].Name = "AsTemplate";
			pPropValues[0].Value = new Boolean(true);
			
			//unter linux reicht das, unter windows reicht das nicht
//			xComponent = xComponentLoader.loadComponentFromURL(
//					file.toString(), "_blank", 0, pPropValues);
			
			xComponent = xComponentLoader.loadComponentFromURL(
					"file:///"+file.toString(), "_blank", 0, pPropValues);
			
			xTextDocument = (XTextDocument)UnoRuntime.queryInterface(
					XTextDocument.class, xComponent);
			xMultiServiceFactory =(XMultiServiceFactory) UnoRuntime.queryInterface(
					XMultiServiceFactory.class, xTextDocument);
		} catch (com.sun.star.io.IOException e) {
			JFractionLab.worksheetProcessIsOK = false;
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			JFractionLab.worksheetProcessIsOK = false;
			e.printStackTrace();
		}
		
//		if(!JFractionLab.worksheetProcessIsOK){
//			try {
//				PropertyValue[] pPropValues = new PropertyValue[1];
//				pPropValues[0] = new PropertyValue();
//				pPropValues[0].Name = "AsTemplate";
//				pPropValues[0].Value = new Boolean(true);
//				xComponent = xComponentLoader.loadComponentFromURL(
//						"file:///"+file.toString(), "_blank", 0, pPropValues);
//				xTextDocument = (XTextDocument)UnoRuntime.queryInterface(
//						XTextDocument.class, xComponent);
//				xMultiServiceFactory =(XMultiServiceFactory) UnoRuntime.queryInterface(
//						XMultiServiceFactory.class, xTextDocument);
//				JFractionLab.worksheetProcessIsOK = true;
//			} catch (com.sun.star.io.IOException e) {
//				JFractionLab.worksheetProcessIsOK = false;
//				e.printStackTrace();
//			} catch (IllegalArgumentException e) {
//				JFractionLab.worksheetProcessIsOK = false;
//				e.printStackTrace();
//			}
//		}

		if(!JFractionLab.worksheetProcessIsOK) JOptionPane.showMessageDialog(null,  
				lang.Messages.getString("error_unsupported_url"));
		
		return JFractionLab.worksheetProcessIsOK;
	}	
	
	public static XDesktop getDesktop() {
		XDesktop xDesktop = null;
		try {
			XComponentContext xContext = null;
			xContext = Bootstrap.bootstrap();
			xMCF = xContext.getServiceManager();
			if( xMCF != null ) {
				Object oDesktop = xMCF.createInstanceWithContext(
				"com.sun.star.frame.Desktop", xContext);
				xDesktop = (XDesktop) UnoRuntime.queryInterface(
						XDesktop.class, oDesktop);
			}else{
//				FIXME
				JOptionPane.showMessageDialog(null, "Can't create a desktop." +
						"No connection, no remote office servicemanager available!");
			}
		}catch (BootstrapException e) {
			e.printStackTrace();
			System.exit(1);
		}catch (com.sun.star.uno.Exception e) {
			e.printStackTrace();
			System.exit(1);
		}
		return xDesktop;
	}
}