package water.api;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import water.DKV;
import water.Job;
import water.Job.JobState;
import water.Key;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.ParseException;
import java.util.Date;

public class Jobs extends Request {
  Jobs() {
  }

  public static Response redirect(JsonObject resp, Key dest) {
    JsonObject redir = new JsonObject();
    redir.addProperty(KEY, dest.toString());
    return Response.redirect(resp, Jobs.class, redir);
  }

  @Override
  protected Response serve() {
    JsonObject result = new JsonObject();
    JsonArray array = new JsonArray();
    Job[] jobs = Job.all();
    for( int i = jobs.length - 1; i >= 0; i-- ) {
      JsonObject json = new JsonObject();
      json.addProperty(KEY, jobs[i].self().toString());
      json.addProperty(DESCRIPTION, jobs[i].description);
      json.addProperty(DEST_KEY, jobs[i].dest() != null ? jobs[i].dest().toString() : "");
      json.addProperty(START_TIME, RequestBuilders.ISO8601.get().format(new Date(jobs[i].start_time)));
      long end = jobs[i].end_time;
      JsonObject jobResult = new JsonObject();
      Job job = jobs[i];

      boolean cancelled;
      if (cancelled = (job.state==JobState.CANCELLED || job.state==JobState.CRASHED)) {
        if(job.exception != null){
          jobResult.addProperty("exception", "1");
          jobResult.addProperty("val", jobs[i].exception);
        } else {
          jobResult.addProperty("val", "CANCELLED");
        }
      } else if (job.state==JobState.DONE)
        jobResult.addProperty("val", "OK");
      json.addProperty(END_TIME, end == 0 ? "" : RequestBuilders.ISO8601.get().format(new Date(end)));
      json.addProperty(PROGRESS, job.state==JobState.RUNNING || job.state==JobState.DONE ? jobs[i].progress() : -1);
      json.addProperty(PROGRESS, end == 0 ? (cancelled ? -2 : jobs[i].progress()) : (cancelled ? -2 : -1));
      json.addProperty(CANCELLED, cancelled);
      json.add("result",jobResult);
      array.add(json);
    }
    result.add(JOBS, array);

    Response r = Response.done(result);
    r.setBuilder(JOBS, new ArrayBuilder() {
      @Override
      public String caption(JsonArray array, String name) {
        return "";
      }
    });
    r.setBuilder(JOBS + "." + KEY, new ArrayRowElementBuilder() {
      @Override
      public String elementToString(JsonElement elm, String contextName) {
        String html;
        if( !Job.isRunning(Key.make(elm.getAsString())) )
          html = "<button disabled class='btn btn-mini'>X</button>";
        else {
          String keyParam = KEY + "=" + elm.getAsString();
          html = "<a href='/Cancel.html?" + keyParam + "'><button class='btn btn-danger btn-mini'>X</button></a>";
        }
        return html;
      }
    });
    r.setBuilder(JOBS + "." + DEST_KEY, new ArrayRowElementBuilder() {
      @Override
      public String elementToString(JsonElement elm, String contextName) {
        String str = elm.getAsString();
        String key = null;
        try {
          key = URLEncoder.encode(str,"UTF-8");
        } catch( UnsupportedEncodingException e ) { key = str; }
        return ("".equals(key) || DKV.get(Key.make(str)) == null) ? key : "<a href='/Inspect.html?"+KEY+"="+key+"'>"+str+"</a>";
      }
    });
    r.setBuilder(JOBS + "." + START_TIME, new ArrayRowElementBuilder() {
      @Override
      public String elementToString(JsonElement elm, String contextName) {
        return date(elm.toString());
      }
    });
    r.setBuilder(JOBS + "." + END_TIME, new ArrayRowElementBuilder() {
      @Override
      public String elementToString(JsonElement elm, String contextName) {
        return date(elm.toString());
      }
    });
    r.setBuilder(JOBS + "." + PROGRESS, new ArrayRowElementBuilder() {
      @Override
      public String elementToString(JsonElement elm, String contextName) {
        return progress(Float.parseFloat(elm.getAsString()));
      }
    });
    r.setBuilder(JOBS + "." + "result", new ElementBuilder() {
      @Override
      public String objectToString(JsonObject obj, String contextName) {
        if(obj.has("exception")){
          String rid = Key.make().toString();
          String ex = obj.get("val").getAsString().replace("'", "");
          String [] lines = ex.split("\n");
          StringBuilder sb = new StringBuilder(lines[0]);
          for(int i = 1; i < lines.length; ++i){
            sb.append("\\n" + lines[i]);
          }
//          ex = ex.substring(0,ex.indexOf('\n'));
          ex = sb.toString();
          String res =  "\n<a onClick=\"" +
              "var showhide=document.getElementById('" + rid + "');" +
              "if(showhide.innerHTML == '') showhide.innerHTML = '<pre>" + ex + "</pre>';" +
              "else showhide.innerHTML = '';" +
              "\">FAILED</a>\n<div id='"+ rid +"'></div>\n";
          return res;
        } else if(obj.has("val")){
          return obj.get("val").getAsString();
        }
        return "";
      }
      @Override
      public String build(String elementContents, String elementName) {
        return "<td>" + elementContents + "</td>";
      }
    });

    return r;
  }

  private static String date(String utc) {
    if( utc == null || utc.length() == 0 )
      return "";
    utc = utc.replaceAll("^\"|\"$","");
    if( utc.length() == 0 )
      return "";
    long ms;
    try {
      ms = RequestBuilders.ISO8601.get().parse(utc).getTime();
    } catch( ParseException e ) {
      throw new RuntimeException(e);
    }
    return "<script>document.write(new Date(" + ms + ").toLocaleTimeString())</script>";
  }

  private static String progress(float value) {
    int    pct  = (int) (value * 100);
    String type = "progress-stripped active";
    if (pct==-100) { // task is done
      pct = 100;
      type = "progress-success";
    } else if (pct==-200) {
      pct = 100;
      type = "progress-warning";
    }

    // @formatter:off
    return ""
        + "<div style='margin-bottom:0px;padding-bottom:0xp;margin-top:8px;height:5px;width:180px' class='progress "+type+"'>" //
          + "<div class='bar' style='width:" + pct + "%;'>" //
          + "</div>" //
        + "</div>";
    // @formatter:on
  }

  @Override
  public RequestServer.API_VERSION[] supportedVersions() {
    return SUPPORTS_V1_V2;
  }
}

@@ -3316,61 +3316,32 @@
 y : 
-%22%3Ca href='/Inspect.html?%22+KEY+%22=%22+key+%22'%3E%22+str+%22%3C/a%3E%22
+Inspector.link(str, str)
 ;%0A  

Fix links in job page.