package nxm.sys.net;

import java.awt.Frame;
import java.io.ByteArrayOutputStream;
import java.net.HttpURLConnection;

import nxm.sys.lib.Midas;
import nxm.sys.lib.OS;
import nxm.sys.lib.Parser;
import nxm.sys.lib.Query;
import nxm.sys.lib.Results;
import nxm.sys.lib.StringUtil;
import nxm.sys.lib.Table;
import nxm.sys.libg.GLabel;
import nxm.sys.libg.GWidget;
import nxm.sys.prim.panel;

/**
  A class to control a Midas service from a mobile client.

  @author Jeff Schoen

*/
public class HMobile extends HSource {

  private Midas M;
  private panel panel;

  /** HMobile Constructor
   *  @param name the name of the HMobile
   *  @param M    the Midas context
   */
  public HMobile (String name, Midas M) {
    this.M = M;
    this.name = name+"/";
  }

  @Override
  public void handleRequest (String uri, HPage hp) {

    String option = uri.substring(name.length()+1);
//System.out.println("Handle="+uri);

    if (option.equals("Home")) {
      homePage (hp);
    }
    else if (option.equals("TopCPU")) {
      topPage (hp);
    }
    else if (option.equals("LogAll")) {
      logPage (hp);
    }
    else if (option.equals("Registry")) {
      queryPage (hp, "REG");
    }
    else if (option.equals("Controls")) {
      queryPage (hp, "THIS.CONTROLS");
    }
    else if (option.equals("Results")) {
      queryPage (hp, "*");
    }
    else if (option.equals("Pipes")) {
      queryPage (hp, "RAM");
    }
    else if (option.equals("Files")) {
      queryPage (hp, "AUX");
    }
    else if (option.startsWith("Displays")) {
      panelPage (hp, "Configuration");
    }
    else if (option.startsWith("Query/")) {
      queryPage (hp, option.substring(6));
    }
    else if (option.startsWith("Panel/")) {
      panelPage (hp, option.substring(6));
    }
    else if (option.startsWith("Disks")) {
      disksPage (hp);
    }
    else if (option.startsWith("DiskStats?")) {
      diskPage (hp,option.substring(10));
    }
    else {
      optPage (hp, option);
    }
  }

  /** Begins the html page
   *  @param hp the HPage output socket
   */
  public void openPage (HPage hp) {
    hp.open();
    hp.writeln ("<html>");
    hp.writeln ("<body bgcolor=black text=grey>");
  }
  /** Finishes the html page
   *  @param hp the HPage output socket
   */
  public void closePage (HPage hp) {
    hp.writeln ("</body>");
    hp.writeln ("</html>");
    hp.close();
  }

  /** Display system log information if available
   *  @param hp HPage to use in displaying system log information */
  public void logPage (HPage hp) {
    openPage(hp);
    hp.writeln ("<h3><a href='' onClick=\"location.reload(); return false;\">System Log</a></h3>");
    hp.writeln ("<br><pre>");
    hp.writeln ("Log File not opened");
    hp.writeln ("</pre>");
    closePage(hp);
  }

  /** Display Top CPU/Memory Usage by process
   *  @param hp Hapge to use in displaying Top CPU/Memory Usage by process
   */
  public void topPage (HPage hp) {
    byte[] buf = new byte[8192];
    int bytes = OS.getStats(0,buf);
    openPage(hp);
    hp.writeln ("<h3><a href='' onClick=\"location.reload(); return false;\">System Top</a></h3>");
    hp.writeln ("<br><pre>");
    hp.write(buf,0,bytes);
    hp.writeln ("</pre>");
    closePage(hp);
  }

  /** Display disk stats for a given Auxiliary
   *  @param hp  HPage to use in displaying disk stats
   *  @param aux The Auxiliary for which to display disk stats
   */
  public void diskPage (HPage hp, String aux) {
    openPage(hp);
    hp.writeln ("<h3><a href='' onClick=\"location.reload(); return false;\">Aux="+aux+" Disk Stats</a></h3>");
    String list = aux;
    if (aux.equals("ALL")) list = M.results.getS("AUX.READ");
    String[] auxes = StringUtil.cleanSplit(list, "|");
    for (int i=0; i<auxes.length; i++) {
    aux = auxes[i];
    String path = M.io.getAuxPath(aux);
    Table tab = OS.getStatFS(path);
    hp.writeln ("<ul>");
    hp.writeln ("<li>Aux   = "+aux+"</li>");
    hp.writeln ("<li>Path  = "+path+"</li>");
    if (tab!=null) {
      hp.writeln ("<li>Files = "+tab.getL("FILES")+"</li>");
      hp.writeln ("<li>Total = "+tab.getL("TMBY")+" Mby</li>");
      hp.writeln ("<li>Free  = "+tab.getL("FMBY")+" Mby</li>");
      hp.writeln ("<li>Used  = "+tab.getL("USED")+"%</li>");
    }
    hp.writeln ("</ul>");
    }
    closePage(hp);
  }

  /** Display menu of all available display pages
   *  @param hp   HPage to use in displaying a menu of all available display pages
   *  @param path path to display
   */
  public void optPage (HPage hp, String path) {
    openPage(hp);
    hp.writeln ("<div style=\"text-align:center;\"><h2>Mobile NeXtMidas Server</h2>");
    hp.writeln ("<h2>Unrecognized path</h2>");
    hp.writeln ("<h2>"+path+"</h2></div>");
    closePage(hp);
  }

  private void disksPage (HPage hp) {
    String hostaddr = server.getHost();
    int hostport = server.getPort();
    String appname = M.macro.args.name;
    openPage(hp);
    hp.writeln ("<div style=\"text-align:center;\"><h3>Mobile NextMidas Server</h3>");
    hp.writeln ("<b>HostAddress="+hostaddr+"</b>");
    hp.writeln ("<b>HostPort="+hostport+"</b>");
    hp.writeln ("<b>APPName= "+appname+"</b></div>");
    hp.writeln ("<br>");
    Table taux = M.results.getTable("AUX");
    String raux = taux.getString("READ");
    Parser auxes = new Parser (raux,'|');
    for (auxes.reset();  auxes.more(); ) {
      String aux = auxes.next();
      String path = M.io.getAuxPath(aux);
      hp.writeln ("<a href='DiskStats/"+aux+"'>Disk Aux="+aux+" Stats</a>");
    }
    hp.writeln("</div>");
    closePage(hp);
  }

  private String sp7 = "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
  private String sp8 = "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
  private String sp9 = "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";

  private void homePage (HPage hp) {
    String hostaddr = server.getHost();
    int hostport = server.getPort();
    String appname = M.macro.args.name;
    openPage(hp);
    hp.writeln ("<br>");
    hp.writeln ("<div style=\"text-align:center;\"><h3>Mobile NextMidas Server</h3>");
    hp.writeln ("<b>HostAddress="+hostaddr+"</b>");
    hp.writeln ("<b>HostPort="+hostport+"</b>");
    hp.writeln ("<b>APPName= "+appname+"</b>");
    hp.writeln ("<br>");
    hp.writeln ("a href='Displays'>Displays</a>"+sp9+"<a href='Files'>Files</a>");
    hp.writeln ("<br>");
    hp.writeln ("<a href='Registry'>Registry</a>"+sp9+"<a href='Disks'>Disks</a>");
    hp.writeln ("<br>");
    hp.writeln ("<a href='Results'>Results</a>  "+sp7+"<a href='LogAll'>SysLog</a>");
    hp.writeln ("<br>");
    hp.writeln ("<a href='Pipes'>Pipes</a>      "+sp8+"<a href='TopCPU'>TopCPU</a>");
    hp.writeln ("<br>");
    hp.writeln ("<a href='Controls'>Controls</a></div>");
    closePage(hp);
  }

  /** Searches for results based on a given key and writes them out to an HPage output socket
   *  @param hp  the HPage output socket
   *  @param key the key used to filter Midas results
   */
  public void queryPage (HPage hp, String key) {
    boolean view = true;

    //System.out.println("Query key="+key);

    // look for a set command
    String command = null;
    int qm = key.indexOf('?');
    if (qm>0) {
      command = key.substring(qm+1);
      key = key.substring(0,qm);
    }
    Results res = M.macro.getResults();
    Object obj = key.equals("*")? res : res.get(key);
    Query q = new Query(obj,null,256);
    q.parse();
    // evaluate set command
    if (command != null) {
      int es = command.indexOf('=');
      String ekey = command.substring(0,es);
      String value = command.substring(es+1);
      Object o = q.getObject(ekey);
      if (o instanceof GWidget) ((GWidget)o).setAction(value);
    }
    q.evaluate();

    openPage(hp);
    hp.writeln ("<h3><a href='' onClick=\"location.reload(); return false;\">Query</a> = "+key+"</h3>");
    if (obj==res) key = null;
    hp.writeln ("<table>");
    for (int i=0; i<q.getItems(); i++) {
      String name = q.getName(i);
      Object o = q.getObject(i);
      String ref = (key==null)? name : key+"."+name;
      Object val = q.getValue(i);
      String value = lookForChoices( key, name, val.toString() );
      if (view || o instanceof GLabel) {
        hp.writeln ("<tr>");
        hp.writeln ("<td nowrap><a href =\"/"+this.name+"Query/"+ref+"\">"+name+"</a></td>");
        hp.writeln ("<td><font size=1>"+value+"</font></td>");
        hp.writeln ("</tr>");
      }
      if (o instanceof GLabel) view = ((GLabel)o).getActive()>0;
    }
    hp.writeln ("</table>");
    closePage(hp);
  }

  private String lookForChoices (String key, String name, String value) {
    if (value==null) return value;
    int fb = value.indexOf('[');
    int rb = value.indexOf(']');
    if (fb<0 || rb<0) return value;
    int i,j;
    String selects = "";
    for (i=fb; i<rb; i=j) {
      j=value.indexOf(',',i+1);
      if (j<0) j=rb;
      String item = value.substring(i+1,j); int il=item.length()-1;
      if (il>0 && item.charAt(0)=='<' && item.charAt(il)=='>') {
        item = item.substring(1,il);
        selects += " <a href =\"/"+this.name+"Query/"+key+"?"+name+"="+item+"\"><b>"+item+"</b></a> ";
      } else {
        selects += " <a href =\"/"+this.name+"Query/"+key+"?"+name+"="+item+"\">"+item+"</a> ";
      }
      if (j!=rb) selects += ',';
    }
    return value.substring(0,fb+1)+selects+value.substring(rb);
  }

  /** Searches for Midas panels and outputs panel info to the HPage output socket
   *  @param hp   the HPage output socket
   *  @param name the name used to filter the Midas panels
   */
  public void panelPage (HPage hp, String name) {
    if (panel==null) panel = (panel)M.registry.get("PANEL");
    ByteArrayOutputStream baos = panel.handleMobileRequest(name);
    if (name.startsWith("Status")) {
      openPage(hp);
      String s; Object o;
      o = panel.MW.parent; s = (o instanceof Frame)? ((Frame)o).getTitle() : "...";
      hp.write(s+"<br>");
//      hp.write("TitleBar: "+s+"<br>");
//      o = panel.M.lastMessageString; s = (o!=null)? o.toString() : "none";
//      hp.write("StatusBar: "+s+"<br>");
      closePage(hp);
    }
    else if (name.startsWith("Configuration")) {
      boolean tbl = name.endsWith(".tbl");
      panel.Pane[] panes = panel.getPanesArray();
      if (!tbl) {
        openPage(hp);
        hp.writeln ("<br>");
        hp.writeln ("<div style=\"text-align:center;\"><h3>Mobile NextMidas Display Server </h3>");
        hp.writeln ("<b>APPName= "+M.macro.args.name+"</b></div>");
        hp.writeln ("<br>");
      }
      for (int i=0; i<panes.length; i++) {
        String key = (i==0)? "APP" : panes[i].name;
        String value = (i==0)? M.macro.args.name : panes[i].title;
        if (tbl) hp.write (value+",");
        else hp.writeln ("<div style=\"text-align:center;\">"+key+" = "+value+"</div>");
      }
      if (!tbl) closePage(hp);
    }
    else if (baos==null) {
      hp.setStatus(HttpURLConnection.HTTP_NOT_FOUND);
      hp.open();
      hp.close();
    }
    else {
//      hp.setContentType("application/octet-stream");
      hp.setContentType("image/png");
      hp.setContentLength((long)baos.size());
      hp.open();
      if (!hp.getMethod().equals("HEAD")) hp.write(baos);
      hp.close();
    }
  }

}
