/*******************************************************************************
 * Copyright (c) 2015, 2016 CNRS, IRIT, IRT AESE (IRT Saint Exupéry).
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the LGPL 3.0
 * which accompanies this distribution, and is available at
 * https://www.gnu.org/licenses/lgpl-3.0-standalone.html
 *
 * Contributors:
 *     Faiez Zalila - initial API and implementation and/or initial documentation
 *     Jorge Enrique Gutierrez Zuluaga
 *******************************************************************************/
package com.irtsaintexupery.fiacre.simulator.core;

import java.lang.reflect.InvocationTargetException;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.emf.edit.domain.IEditingDomainProvider;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import org.eclipse.xtext.resource.XtextResource;
import org.json.simple.JSONObject;

import com.irtsaintexupery.fiacre.simulator.perspective.ViewsController;
import com.irtsaintexupery.fiacre.simulator.staticjson.extractor.DynamicJsonExtractor;
import com.irtsaintexupery.fiacre.simulator.staticjson.extractor.StaticJsonExtractor;

import fr.laas.libtts.LibTTS;

public class FiacreSimulator {
	private static LibTTS libtts;
	private static XtextResource fiacreResource;
	private static JSONObject fiacreStaticJson;
	private static Resource instanceResource;
	private static Resource mscResource;
	private static StaticJsonExtractor sje;
	private static DynamicJsonExtractor dje;
	
	
	
	public FiacreSimulator(final IFile file){
//		/*
//		 * If a current libtts exists and the user forgets to kill it, we kill
//		 * it automatically
//		 */
//		
//		
//		if (libtts != null) {
//			ViewsController.INSTANCE.clearAllViews();
//			ViewsController.INSTANCE.deleteMarkers();
//			libtts.quit();
//			FiacreSimulator.setLibtts(null);
//		}
//		
//		// Compile Fiacre model
//		Utils.compileFiacreModel(file);
//		Utils.callPythonCommand(file);
//
//		// initialize libtts
//		libtts = new LibTTS(Utils.getTTSFilePath(file));
//		/*
//		 * This condition allows to catch whether an exception was thrown during instantiating 
//		 * LibTTS. We can't do a try catch block because libTTS is a static field. 
//		 */
//		if (libtts.getTTSSimulator() != null) {
//			// Get the static json file
//			String static_json_file_path = Utils.getStaticJsonFilePath(file);
//			fiacreStaticJson = Utils.getStaticJsonObject(static_json_file_path);
//
//			// get the fiacre xtext resource
//			fiacreResource = Utils.getFiacreXtextResource(file);
//
//			// create fiacre instance model
//			setInstanceResource(Utils.createInstanceModel(file));
//			sje = new StaticJsonExtractor(fiacreResource, fiacreStaticJson, instanceResource);
//			sje.extract();
//			dje = new DynamicJsonExtractor(fiacreResource, instanceResource, libtts.getTTSSimulator(), fiacreStaticJson, sje.getMapping());
//			simulate();
//		}
//		else{
//			// It set LibTTS to null in order to check the first condition in this constructor 
//			// in the next simulation. 
//			// We do it here because we can't do it in the LibTTS initialize_tts_model method
//			FiacreSimulator.setLibtts(null);
//		}
//					
//		//Jorge Gutierrez 05/08/2016
//		ViewsController.INSTANCE.setFile(file);
		
		
		//Progress bar       
		Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow()
				.getActivePage().getActivePart().getSite().getShell();
         IRunnableWithProgress runnable = new IRunnableWithProgress()
         {

            @Override
            public void run(final IProgressMonitor monitor) throws InvocationTargetException, InterruptedException
            {
               monitor.beginTask("Loading", 6);
               monitor.subTask("part 1");
               monitor.worked( 2 );
               part1(file);
               
               monitor.subTask("part 2");
               monitor.worked( 2 );
               part2(file);
               
               monitor.subTask("part 3");
               monitor.worked( 1 );
               part3(file);
               
               
               monitor.subTask("finished");
               monitor.worked( 1 );
               	
               
               monitor.done();
            }
         };


         ProgressMonitorDialog dialog = new ProgressMonitorDialog(shell);
         try
         {
            dialog.run(true, true, runnable);
         }
         catch (InvocationTargetException e)
         {
            e.printStackTrace();
         }
         catch (InterruptedException e)
         {
            e.printStackTrace();
         }
         
         
         
		
	}
	
	private static void part1(final IFile file){
		Display.getDefault().asyncExec(new Runnable()
	    {
	        @Override
	        public void run()
	        {
	        	/*
	   			 * If a current libtts exists and the user forgets to kill it, we kill
	   			 * it automatically
	   			 */
	   			if (libtts != null) {
	   				ViewsController.INSTANCE.deleteMarkers();
	   				ViewsController.INSTANCE.clearAllViews();
	   				libtts.quit();
	   				FiacreSimulator.setLibtts(null);
	   			}
	   			
	   			// Compile Fiacre model
	   			Utils.compileFiacreModel(file);
	   			Utils.callPythonCommand(file);

	   			
	        }
	    });
	}
	
	private static void part2(final IFile file){
		Display.getDefault().asyncExec(new Runnable()
	    {
	        @Override
	        public void run()
	        {
	        	// initialize libtts
	   			libtts = new LibTTS(Utils.getTTSFilePath(file));
	        	
	        }
	    });
	}
	
	private static void part3(final IFile file){
		Display.getDefault().asyncExec(new Runnable()
	    {
	        @Override
	        public void run()
	        {
	        	/*
	   			 * This condition allows to catch whether an exception was thrown during instantiating 
	   			 * LibTTS. We can't do a try catch block because libTTS is a static field. 
	   			 */
	   			if (libtts.getTTSSimulator() != null) {
	   				// Get the static json file
	   				String static_json_file_path = Utils.getStaticJsonFilePath(file);
	   				fiacreStaticJson = Utils.getStaticJsonObject(static_json_file_path);

	   				// get the fiacre xtext resource
	   				fiacreResource = Utils.getFiacreXtextResource(file);

	   				// create fiacre instance model
	   				setInstanceResource(Utils.createInstanceModel(file));
	   				mscResource= Utils.createMSCModel(file);
	   				
	   				sje = new StaticJsonExtractor(fiacreResource, fiacreStaticJson, instanceResource, mscResource);
	   				sje.extract();
	   				dje = new DynamicJsonExtractor(fiacreResource, instanceResource, libtts.getTTSSimulator(), fiacreStaticJson, sje.getMapping(), mscResource);
	   				ViewsController.INSTANCE.setFile(file);
	   				simulate(file);
	   			}
	   			else{
	   				// It set LibTTS to null in order to check the first condition in this constructor 
	   				// in the next simulation. 
	   				// We do it here because we can't do it in the LibTTS initialize_tts_model method
	   				FiacreSimulator.setLibtts(null);
	   			}
	        }
	    });
	}	

	public static LibTTS getLibTTS() {
		return libtts;
	}

	public static DynamicJsonExtractor sendDje() {
		return dje;
	}

	public static void simulate(IFile file) {
		// try {
		
		dje.extractStates();
		dje.extractExecutableStatements();
				
		dje.extractValues();
		dje.saveInstanceResource();
		
        try {
			file.getParent().refreshLocal(1, null);
		} catch (CoreException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//msc
		dje.mscFirstStepExtract();
		//launch perspective 
		ViewsController.INSTANCE.openPespective();
				
		//libtts.getTTSSimulator().printCurrent();
	}

	public LibTTS getLibtts() {
		return libtts;
	}

	public static void setLibtts(LibTTS _libtts) {
		libtts = _libtts;
	}

	public XtextResource getXtextResource() {
		return fiacreResource;
	}

	public void setXtextResource(XtextResource xtextResource) {
		FiacreSimulator.fiacreResource = xtextResource;
	}

	public JSONObject getStatic_json() {
		return fiacreStaticJson;
	}

	public void setStatic_json(JSONObject static_json) {
		FiacreSimulator.fiacreStaticJson = static_json;
	}

	public Resource getInstanceResource() {
		return instanceResource;
	}

	public static void setInstanceResource(Resource instanceResource) {
		FiacreSimulator.instanceResource = instanceResource;
	}

	static public EditingDomain getEditingDomainFor(EObject object) {
		Resource resource = object.eResource();
		if (resource != null) {
			IEditingDomainProvider editingDomainProvider =

					(IEditingDomainProvider) EcoreUtil.getExistingAdapter(resource, IEditingDomainProvider.class);
			if (editingDomainProvider != null) {
				return editingDomainProvider.getEditingDomain();
			} else {
				ResourceSet resourceSet = resource.getResourceSet();
				if (resourceSet instanceof IEditingDomainProvider) {
					EditingDomain editingDomain = ((IEditingDomainProvider) resourceSet).getEditingDomain();
					return editingDomain;
				} else if (resourceSet != null) {
					editingDomainProvider = (IEditingDomainProvider) EcoreUtil.getExistingAdapter(resourceSet,
							IEditingDomainProvider.class);
					if (editingDomainProvider != null) {
						return editingDomainProvider.getEditingDomain();
					}
				}
			}
		}
		// todO
		return null;
	}
	
}
