package ua.be.wee.model;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.json.JSONException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import ua.be.wee.model.nodes.Activity;
import ua.be.wee.model.nodes.Artifact;
import ua.be.wee.model.nodes.AutomatedActivity;
import ua.be.wee.model.nodes.AutomatedStatus;
import ua.be.wee.model.nodes.ports.ControlInputPort;
import ua.be.wee.model.nodes.ports.ControlOutputPort;
import ua.be.wee.model.nodes.ports.DataInputPort;
import ua.be.wee.model.pm.PM;
import ua.be.wee.model.pt.EndActivityEvent;
import ua.be.wee.model.pt.Event;
import ua.be.wee.model.pt.PT;
import ua.be.wee.model.pt.StartActivityEvent;
import ua.be.wee.model.pt.TraceArtifact;
import ua.be.wee.model.repository.NodeRespository;
import ua.be.wee.model.repository.PMRepository;
import ua.be.wee.model.repository.PTRepository;
import ua.be.wee.model.util.AsyncHttpClientService;
import ua.be.wee.model.util.Pair;
import ua.be.wee.service.FileStorageService;

@Component
public class EnactmentController {

	@Autowired
	private PMRepository pmRepo;
	
	@Autowired
	private NodeRespository nodeRepo;
	
	@Autowired
	private PTRepository traceRepo;
	
	@Autowired
	private FileStorageService storageService;
	
	public List<PM> getAllPMs() {
		return pmRepo.getAllPMs();
	}

	public PM getPM(String pmid) throws Exception {
		PM pm = pmRepo.getPM(pmid);
		pm.setNodes(nodeRepo.getNodes(pm.getIri()));
		return pm;
	}

	public List<Pair<String,String>> findNextNodes(String iri, String trace) throws Exception {
		return pmRepo.findNextNodes(iri, trace); 
	}

	public PT createTrace(PM pm) throws Exception {
		return traceRepo.createTrace(pm);
	}

	public void addStartEvent(PT pt, ControlInputPort port, Activity act, List<TraceArtifact> arts) throws Exception {
		traceRepo.createStartEvent(pt,port,act,arts);
		pmRepo.checkJoinSync(port.getIri(),pt.getIri());
	}

	public void addEndEvent(PT pt, List<TraceArtifact> arts, ControlOutputPort p) throws Exception {
		traceRepo.createEndEvent(pt,arts,p);	
	}

	public Event addEndTraceEvent(String iri, String previous, String pmIRI) throws Exception {
		return traceRepo.createEndTraceEvent(iri,previous, pmIRI);
		
	}

	public void updatePT(PT pt) throws Exception {
		traceRepo.updatePT(pt);
		
	}

	public void callAutomatedActivity(PT pt, AutomatedActivity aut, ControlInputPort port, List<TraceArtifact> arts) throws JSONException, IOException {
		Map<String,Pair<String,String>> params = createParamsMap(aut, arts);
		AsyncHttpClientService.asyncHTTPClient(pt, aut, port, params,this);
		
	}

	private Map<String,Pair<String,String>> createParamsMap(AutomatedActivity aut, List<TraceArtifact> arts) {
		Map<String,Pair<String,String>> params = new HashMap<String, Pair<String,String>>();
		List<DataInputPort> datalInPorts = aut.getDatalInPorts();
		
		for (DataInputPort dataInputPort : datalInPorts) {
			for (TraceArtifact traceArtifact : arts) {
				Artifact relatesTo = traceArtifact.getRelatesTo();
				if (dataInputPort.getArtifact().getIri().equals(relatesTo.getIri())) {
					traceArtifact.getLocation();
					//TODO Instead of this, send both the inline and url to the services
					if (traceArtifact.getFileExtension().equals("txt") || 
							traceArtifact.getFileExtension().equals("csv") ||
							traceArtifact.getFileExtension().equals("xopp")||
							traceArtifact.getFileExtension().equals("drawio")) {
						String content = storageService.load(traceArtifact.getLocation());
						params.put(dataInputPort.getName(), new Pair<String, String>(traceArtifact.getFileExtension(), content));
					} else {
						String content = storageService.getURL(traceArtifact.getLocation());
						params.put(dataInputPort.getName(), new Pair<String, String>(traceArtifact.getFileExtension(), content));
					}
					
				}
			}
		}
		return params;
	}

	public void uploadArtifact(InputStream is, String filename) throws IOException {
		storageService.save(is,filename);	
	}

	public List<AutomatedActivity> getAutomatedActivities(PT trace) {
		trace.getPmEnacted();
		List<AutomatedActivity> result = new ArrayList<AutomatedActivity>();
		List<Event> events = trace.getEvents();
		for (Event event : events) {
			if (event instanceof StartActivityEvent) {
				Activity activity = ((StartActivityEvent) event).getRelatesTo().getActivity();
				if (activity instanceof AutomatedActivity) {
					boolean found = false;
					for (Event event2 : events) {
						if (event2 instanceof EndActivityEvent) {
							if (checkMatchingActivityEvents((StartActivityEvent)event, (EndActivityEvent)event2)) {
								AutomatedActivity aut =(AutomatedActivity)activity;
								aut.setAutomatedStatus(AutomatedStatus.COMPLETED);
								result.add(aut);
								found = true;
								break;
							}
							
						}
					}
					if (!found) {
						AutomatedActivity aut =(AutomatedActivity)activity;
						aut.setAutomatedStatus(AutomatedStatus.IN_PROGRESS);
						result.add(aut);	
					}
				}
			} 
		}
		return result;
	}
	
	public boolean checkMatchingActivityEvents(StartActivityEvent ev1, EndActivityEvent ev2) {
		String ir = ev1.getIri();
		String ir2= ev2.getIri();
		String[] split = ir.split("#");
		String[] split2 = ir2.split("#");
		String sub1 = split[1].substring(split[1].indexOf('_'));
		String sub2 = split2[1].substring(split2[1].indexOf('_'));
		return split[0].equals(split2[0]) && sub1.equals(sub2);
	}
	
}
