/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package pl.edu.pwr.nlpengineservice;



import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.inject.Singleton;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import org.glassfish.jersey.server.mvc.Viewable;
import org.json.JSONArray;
import org.json.JSONObject;
import pl.edu.pwr.nlpengine.NLPEngine;
import pl.edu.pwr.nlpengine.NLPEngineException;
import pl.edu.pwr.nlptools.NLPTool;
import pl.edu.pwr.nlptools.NLPToolException;

/**
 * REST Web Service
 *
 * @author www_zsk
 */
@Singleton
@Path("")
public class EngineResource {

    
      ConcurrentHashMap<String, NLPEngine> tasks;
    
  
    
    
    @GET     
    @Path("admin/stop/{taskid}")
    @Produces(MediaType.TEXT_HTML)
    public String stop(@PathParam("taskid") String data) throws NLPToolException
            
    {  if (data==null) data="";
        NLPEngine task=tasks.get(data);
     if (task==null)
                throw new WebApplicationException(createResponse(new Exception("Wrong ID"), Response.Status.BAD_REQUEST));
         task.killprocessing();
     return getAdminStatus();
    }
      
   @GET     
    @Path("admin/getStatus")
    @Produces(MediaType.TEXT_HTML)
    public String getAdminStatus() 
     {   String out="Status<br><table border='1'><tr><td>Start date</td><td>Number of threads</td><td>Processing time</td><td>Finishing</td>";
       for (String id:tasks.keySet())
        { NLPEngine engine=tasks.get(id);
            String s="<tr><td>"+engine.getStartingTime()+"</td><td>"+engine.getNumberOfThreads()+"</td><td>"+engine.processingTime()+"</td>";
          if (!engine.isFinished())
          {
              s+="<td> <a href='/nlpengine/e/admin/stop/"+id +"'>stop</a></td>";
          }
          else
              s=s+"<td>finished</td>";
            out+=s+"</tr>";
        
        
      }
       out+="</table>";
     return out;     
        
     
    }
      
    
    private class TaskComparator implements Comparator<String> {
    @Override
    public int compare(String t1, String t2) {
        return tasks.get(t1).getStartingTime().compareTo(tasks.get(t2).getStartingTime());
    }
}
   @GET     
    @Path("admin/getJSONStatus")
    @Produces(MediaType.APPLICATION_JSON)
    public String getAdminJSONStatus() 
     { List<String> keys = new ArrayList<>(tasks.keySet()); 
       Collections.sort(keys,new TaskComparator());
       JSONArray result=new JSONArray();
       for (String id:keys)
        { NLPEngine engine=tasks.get(id);
          JSONObject row=new JSONObject();
          row.put("starttime",new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss").format(engine.getStartingTime()));
          row.put("numberofthreads",engine.getNumberOfThreads());
          row.put("time",engine.processingTime());
          row.put("id",id);
          row.put("finished",engine.isFinished());
          row.put("error",engine.getError());
          row.put("ip",engine.getsourceIP());
          result.put(row);
      }
       
     return result.toString();
        
     
    }
    
    
    
    /**
     * Creates a new instance of BaseResource
     */
    public EngineResource() {
        this.tasks = new ConcurrentHashMap<>(16, 0.9f, 1);
    }
    
    @Context HttpServletRequest request;
    
      @POST
    @Path("startTask")
    @Consumes(MediaType.APPLICATION_XML)
    @Produces(MediaType.TEXT_PLAIN)
    public String startTask(String data) 
    {  
        return execute(data);
    }
    
    @POST
    @Path("startTask")
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    @Produces(MediaType.TEXT_PLAIN)
    public String startTaskForm(@FormParam("file") String data) 
    {    return execute(data);
    }
    
    @POST
    @Path("execute")
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    @Produces(MediaType.TEXT_PLAIN)
    public String execute(@FormParam("file") String data) 
    {   
        String ip=request.getRemoteHost();
        if (ip.equals("127.0.0.1"))
            ip=request.getHeader("X-Forwarded-For");
        
        System.out.println(request.getHeader("X-Forwarded-For"));
        
        try {
        
         if (data==null) data=""; 
        NLPEngine engine=new NLPEngine(data,ip);
        
        String id =UUID.randomUUID().toString();
        engine.start();
        tasks.put(id, engine);
        
        return id;
    }
    
      
  
      catch (NLPEngineException ex) {
                throw new WebApplicationException(createResponse(ex, Response.Status.BAD_REQUEST));
            }
    }
    
    
    @GET
    @Path("getJSONStatus/{taskID}")
    @Produces(MediaType.APPLICATION_JSON)
    public String getJSONStatus(@PathParam("taskID") String data) throws NLPToolException
    {   if (data==null) data="";
        NLPEngine task=tasks.get(data);
        
        
        JSONObject input=new JSONObject(); 
        if (task==null)
        {  input.put("status", "ERROR");
           input.put("value","Unkonwn task id.");
        }        
        else
        if(task.isError()) 
        { input.put("status", "ERROR");
           input.put("value",task.getError());
        }
        else
        if(task.isFinished()) 
        { input.put("status", "DONE");
          input.put("value",task.getResult());
        }    
        else
        {    
          input.put("status","PROCESSING" );
          input.put("value",task.getProgress());
        }
            
        
       return input.toString();
    }
    
    @GET     
    @Path("getStatus/{taskid}")
    @Produces(MediaType.TEXT_PLAIN)
    public String getStatus(@PathParam("taskid") String data) throws NLPToolException
            
    {  if (data==null) data="";
        NLPEngine task=tasks.get(data);
     if (task==null)
                throw new WebApplicationException(createResponse(new Exception("Wrong ID"), Response.Status.BAD_REQUEST));
     
        
            if(task.isError()) return "ERROR";
            else
            if(task.isFinished()) return "DONE";
                    else return "PROCESSING";        
        
     
    }
    
     @GET     
    @Path("getError/{taskid}")
    @Produces(MediaType.TEXT_PLAIN)
    public String getError(@PathParam("taskid") String data) throws NLPToolException
            
    {  if (data==null) data="";
        NLPEngine task=tasks.get(data);
     if (task==null)
                throw new WebApplicationException(createResponse(new Exception("Wrong ID"), Response.Status.BAD_REQUEST));
          return task.getError();
        
     
    }
    
    
    @GET     
    @Path("getExtendedStatus/{taskid}")
    @Produces(MediaType.APPLICATION_XML)
    public String getExtendedStatus(@PathParam("taskid") String data) throws NLPToolException
    { NLPEngine task=tasks.get(data);
     if (task==null)
                throw new WebApplicationException(createResponse(new Exception("Wrong ID"), Response.Status.BAD_REQUEST));
     
        try {
            return task.getXMLStatus();
        } catch (NLPEngineException ex) { throw new WebApplicationException(createResponse(ex, Response.Status.INTERNAL_SERVER_ERROR));
            
        }
      
    }
    
    
    @GET     
    @Path("test")
    @Produces(MediaType.TEXT_HTML)
    public String checkBooking() 
    { int ile=10; String wynik="";
        final String[] tab=new String[ile];  
        
            final NLPTool tool=new NLPTool();
            
            for (int i=0;i<ile;i++)
            { final int id=i;/*
                Thread t=new Thread () { public void run() {
                try {
                    tab[id]=tool.booking();
                } catch (NLPToolException ex) {
                    Logger.getLogger(EngineResource.class.getName()).log(Level.SEVERE, null, ex);
                }
}};
                t.start(); */
        try {
            tab[id]=tool.booking();
        } catch (NLPToolException ex) {
            Logger.getLogger(EngineResource.class.getName()).log(Level.SEVERE, null, ex);
        }
            }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException ex) {
            Logger.getLogger(EngineResource.class.getName()).log(Level.SEVERE, null, ex);
        }
            for (int i=0;i<ile;i++)
              wynik+=tab[i]+"<br/>";
             return wynik;
       
       
      
    }
    
   
    
    
    private Response createResponse(Exception ex, Response.Status status) {
        String message = ex.getMessage();
        if (message == null) {
            message = "Internal error";
        }
        
        return Response.status(status).entity(message).type(MediaType.TEXT_PLAIN).build();
    }
}
