#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/process.h>
#include <os_config.h>

void clear() ;
void print_status( p_stat *ps ) ;
#define MAX_PROGS_LOADED 9
char * progs_loaded[MAX_PROGS_LOADED][3] = {
  { "0x00f00000", "print1", "Print program 1"},
  { "0x00f10000", "print2", "Print program 2"},
  { "0x00f20000", "print3", "Print program 3"},
  { "0x00f30000", "shell", "Shell (this program)"},
  { "0x00f40000", "thread_ex", "Multi thread example"},
  { "0x00f50000", "llist", "Linked list example"},
  { "0x00f60000", "producer", "Producer example"},
  { "0x00f70000", "consumer", "Consumer example"},
  { "0x00f80000", "testmfs", "File system example"}
};

int main()
{
  char buf[120];
  char *cmd[6];
  char c, *str ;
  int opt, i, sep = 0 ;
  int pid ;
  p_stat ps ;
  
  clear() ;
  print("XMK System\r\n\r\n") ;	
  while(1) {
    print("shell >") ;
    opt = 0 ; 
    str = &(buf[0]) ; 
    c = inbyte() ;
    while( c != '\r' ){
      if (c == '\b') {
        if (str != &(buf[0]))
          str--;
      } else {
        *str = c ;
        str++ ;
      }
      outbyte(c) ;
      c = inbyte() ;
    }
    *str = '\0' ;
    cmd[0] = &(buf[0]);
    str = cmd[0];
    while (*str != '\0') {
      if (*str == ' ') {
        *str = '\0';
        opt++;
        str++;
        cmd[opt] = str;
      }
      else
        str++;
    }
  
    outbyte('\r') ; outbyte('\n') ;
    
    if( cmd[0][0] == '\0' )
      continue ; 
        
    /* Process the command......*/
        
    /*
     * ld - command
     */
    if( !strcmp(cmd[0], "ld") ) {
      unsigned int start_addr ;
      char prio ;
      int i;
      
      if( opt != 2 ) {
        print("Invalid argument to ld\r\n\tUsage :: ld <program_name> <priority>\r\n" ) ;
        continue ;
      }
      i = 0;
      while(i < MAX_PROGS_LOADED) {
        if (!strcmp(cmd[1], progs_loaded[i][1]))
          break;
        i++;
      }
      if (i == MAX_PROGS_LOADED) {
        print("Unknown program\r\n");
      }
      else {
       
        if( (progs_loaded[i][0][1] == 'x') || (progs_loaded[i][0][1] == 'X') )
          start_addr = strtoul(progs_loaded[i][0], (char **)NULL, 16);
        else
          start_addr = strtoul(progs_loaded[i][0], (char **)NULL, 10);
        prio = strtol(cmd[2], (char **)NULL, 10 ) ;
        pid = process_create( start_addr, prio ) ;
      }
      /*
       * ps - command.
       */
    } else if( !strcmp( cmd[0], "ps") ) {
      //print("ps command !!\r\n" ) ;
      if( opt > 1 ) {
        print("\r\n\tps [pid]\r\n") ;
        continue ;
      }
      print("PID\tStatus\r\n") ;
      if( opt == 1 ) {
        pid = strtol(cmd[1], (char **)NULL, 10 ) ;
        if( !process_status(pid, &ps) )
          print_status( &ps ) ;
        else 
          xil_printf("No Process %d exists\r\n",pid) ;
      } else {
        int i = 0 ;
        while( i < MAX_PROCS ) {
          if( !process_status(i, &ps ) )
            print_status(&ps) ;
          i++ ; 
        }
      }
      /*
       * kill - command.
       */
    } else if( !strcmp( cmd[0], "kill") ) {
      //print("kill command !!\r\n" ) ;
      int status ;
      
      if( opt != 1 ) {
        print("\r\n\tkill <pid>\r\n" ) ;
        continue ;
      }
      pid = strtol(cmd[1], (char **)NULL, 10 ) ;
      status = process_kill(pid) ;
      if( !status )
        xil_printf("Process %d killed\r\n", pid ) ;
      else 
        xil_printf("No Process %d running\r\n", pid ) ;
      
      /*
       * clear - command.
       */
    } else if( !strcmp(cmd[0], "clear") ) {
      clear() ;
    } else if( !strcmp(cmd[0], "list") ) {
      int i;
      print("List of programs loaded in this example system\r\n") ;
      for (i = 0; i < MAX_PROGS_LOADED; i++) {
        print(progs_loaded[i][0]); // start address
        print(" :");
        print(progs_loaded[i][1]); // Name
        print(" \t\t:");
        print(progs_loaded[i][2]); // description
        print("\r\n");
      }
    } else if( !strcmp(cmd[0], "help") ) {
      print("\r\nList of commands\r\n");
      print("ld <program_name> <priority> : Load the named program with priority\r\n") ;
      print("ps	           : Status of all processes\r\n");
      print("ps <pid>	   : Status of the process\r\n");
      print("kill <pid>    : Kill the process.\r\n") ;
      print("clear 	   : Clear the screen\r\n") ;
      print("list	   : List the programs loaded for this example system\r\n") ;
      print("help	   : This help screen\r\n") ;
      print("exit	   : Exit this shell\r\n") ;
    } 
    else if (!strcmp(cmd[0], "exit")) {
      print("Exiting shell\r\nBye\r\n");
      process_exit();
    } else {
      print(cmd[0]) ;
      print(" : Unrecognised command\r\n" ) ;
    }
  }
  return 0 ;
}

void clear()
{
  int i = 0 ;
  for(; i < 80; i++ ) {
    outbyte('\r') ; outbyte('\n') ;
  }
}

void print_status( p_stat *ps )
{
  int pid = (int) ps->pid;
  int state = (int) ps->state;
  putnum(pid); print("\t");
  if(state == PROC_RUNNING)
    print("RUNNING\r\n") ;
  else if(state == PROC_READY)
    print("READY\r\n") ;
  else if(state == PROC_WAITING)
    print("WAITING\r\n") ;
  else if (state == PROC_DEAD)
    print("DEAD\r\n");
  else
    print("NEW PROCESS\r\n") ;
}


