#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>

#include "orcd.h"
#include "configfile.h"
#include "orcutils.h"
#include "configfile.h"
#include "ips.h"
#include "banner.h"
#include "logutils.h"

#define LOGCHANNEL "ORCDSHELL"

static void doIps(orcd_t *orcd);
static void menu(orcd_t *orcd);
static int runOption(orcd_t *orcd, Option* opt);

void *shellThreadProc(void *arg)
{
  orcd_t *orcd=(orcd_t*) arg;

  while (!orcd->quit)
    {
      bannerDraw(orcd);

      while (!orcd->quit && orcd->cmdclients!=0)
	{
	  usleep(300000);
	}

      lcdHome(orcd);
      bannerDraw(orcd);

      while (!orcd->quit && orcd->cmdclients==0)
	{
	  lcdPrint(orcd, 0, 8, 'B',"                          ");

	  /*                         0123456789012345 */
	  lcdPrint(orcd, 0, 16, 'C',"OrcShell v1.5   ");

	  /*                         0123456789012345678901234 */
	  lcdPrint(orcd, 0,24, 'A',"compiled %s %s",__DATE__,__TIME__);
	  //	  lcdPrint(orcd, 0,24, 'B',"Standing by.              ");
	  lcdPrint(orcd, 0,32, 'B',"                          ");
	  lcdPrint(orcd, 0,40, 'B',"Press menu for options.   ");
	  //	  lcdPrint(orcd, 0,48, 'B',"                          ");

	  time_t t=time(NULL);
	  //	  printf("%s\n",ctime(&t));
	  char *s=ctime(&t);
	  char *ss=strrchr(s,' ');
	  ss[0]=0;
	  lcdPrint(orcd, 50, 64-8, 'A', "%s ",s);

	  if (padPoll(orcd)&ORC_PAD_BUTTONS)
	    {
	      log(LOG_VERBOSE,LOGCHANNEL,"Entering menu");
	      menu(orcd);
	      log(LOG_VERBOSE,LOGCHANNEL,"Exiting menu");

	      if (orcd->cmdclients==0)
		lcdHome(orcd);
	    }

	  usleep(100000);
	}
    }

  return NULL;
}

void menu(orcd_t *orcd)
{
  int selected=0;
  int lines=7;

  if (orcd->cmdclients==0)
    lcdHome(orcd);

  while(orcd->cmdclients==0)
    {
      int nchoices=orcd->config->getSize();

      if (selected>(nchoices-1))
	selected=0;

      bannerDraw(orcd);

      int low,high;

      if (selected<(lines/2))
	{
	  low=0;
	  high=lines;
	}
      else if (selected>=(nchoices-lines/2))
	{
	  high=nchoices;
	  low=high-lines;
	}
      else
	{
	  low=selected-lines/2;
	  high=low+lines;
	}

      if (low<0)
	low=0;
      if (high>=nchoices)
	high=nchoices;

      for (int i=low, line=0;i<high;i++,line++)
	{
	  Option *opt=orcd->config->get(i);

	  int len=strlen(opt->label);
	  if (len>19)
	    opt->label[20]=0;

	  if (selected==i)
	    lcdPrint(orcd, 20, 8*line+8, 'b', " %-20s",opt->label);
	  else
	    lcdPrint(orcd, 20, 8*line+8, 'B', " %-20s",opt->label);

	}

      int k=padGets(orcd);

      if (orcd->cmdclients>0)
	return;

      if (k==ORC_PAD_DOWN && selected<(nchoices-1))
	selected++;

      if (k==ORC_PAD_UP && selected>0)
	selected--;

      if (k==ORC_PAD_MENU || k==ORC_PAD_STICK)
	{
	  lcdHome(orcd);
	  int v=runOption(orcd, orcd->config->get(selected));
	  if (v==-1)
	    return;
	  if (orcd->cmdclients==0)
	    lcdHome(orcd);
	}
    }
}

void doIps(orcd_t *orcd)
{
 redraw:

  lcdHome(orcd);
  bannerDraw(orcd);

  Vector<Interface*> *ifaces=ips();
  if (ifaces->getSize()==0)
    {
      lcdPrint(orcd, 10, 16, 'A', "No IPs");
    }

  for (int i=0;i<ifaces->getSize();i++)
    {
      Interface *iface=ifaces->get(i);
      lcdPrint(orcd, 10, 16+i*8, 'A', "%s : %s",
	       iface->ifname, iface->ip);
      delete iface;
    }
  delete ifaces;

  lcdPrint(orcd,70,64-8,'a'," Press a key. ");

  int v=padGets(orcd);
  if (v==ORC_PAD_MENU || v==ORC_PAD_STICK)
    return;

  goto redraw;
}


void execd(char *cmd)
{
  log(LOG_VERBOSE,LOGCHANNEL,"exec starting %s",cmd);

  FILE *f = fopen("/tmp/execd.fifo","w");
  if (!f)
    {
      log(LOG_ERROR,LOGCHANNEL,"Unable to open fifo to execd");
      return;
    }

  fputs(cmd,f);
  fputc('\n',f);
  fclose(f);

  log(LOG_VERBOSE,LOGCHANNEL,"exec started.");
}

int runOption(orcd_t *orcd, Option* opt)
{
  if (!strcmp(opt->action,"!nop"))
    return 0;

  if (!strcmp(opt->action,"!ipaddresses"))
    {
      log(LOG_VERBOSE,LOGCHANNEL,"showing ipaddresses");
      doIps(orcd);
      return 0;
    }

  if (!strcmp(opt->action, "!standby"))
    {
      return -1;
    }

  if (!strcmp(opt->action, "!consoleon"))
    {
      orcd->consoleDisabled=0;

      lcdHome(orcd);
      lcdPrint(orcd,0,8,'a',"Console turned on.");
      padGets(orcd);
    }

  if (!strcmp(opt->action, "!consoleoff"))
    {
      orcd->consoleDisabled=1;

      lcdHome(orcd);
      lcdPrint(orcd,0,8,'a',"Console turned off.");
      padGets(orcd);
    }

  if (!strcmp(opt->action, "!reload"))
    {  
      log(LOG_VERBOSE,LOGCHANNEL,"reloading config");
      orcd->config=readConfigFile(orcd->opt->getOptionString("config"));
      return 0;
    }

  if (opt->action[0]=='!')
    {
      log(LOG_ERROR,LOGCHANNEL,"Unknown target %s", opt->action);
      return 1;
    }

  lcdHome(orcd);
  lcdPrint(orcd,0,8,'a',"Executing %s:",opt->label);

  int written=0;
  int len=strlen(opt->action);
  char buf[64];
  int y=16;
  int chunksize=30;
  while (written<len)
    {
      strncpy(buf, &opt->action[written],chunksize);
      buf[chunksize]=0;
      lcdPrint(orcd,0,y,'A',buf);
      y+=8;
      written+=chunksize;
      usleep(30000);
    }

  log(LOG_OUTPUT,LOGCHANNEL,"Executing %s: %s",opt->label,opt->action);

  lcdConsoleGoto(orcd, 0, y/8+1);

  write(orcd->execpipe[1], opt->action, strlen(opt->action));
  write(orcd->execpipe[1], "\n", 1);

  lcdPrint(orcd,0,y,'a',"program launched. Press menu.");

  usleep(500000);

  while (!orcd->quit && orcd->cmdclients!=0)
    {
      usleep(300000);
    }

  while (padPoll(orcd)!=0);

  padGets(orcd);
  lcdHome(orcd);
  
  while (padPoll(orcd)!=0);
  return 0;
}
