#include <fosh/fosh.hpp>
#include <fosh/commander.h>
#include <stdio.h>         // printf

#define LINUX

#if defined ( LINUX )  && ! defined( STM32 )
   #include <termios.h>       // tcgetattr
   #include <unistd.h>        // tcgetattr
   #include <errno.h>         // errno
   #include <stdlib.h>        // exit
   #include <unistd.h>        // usleep
   #include <sys/utsname.h>   // uname
#else
   #include <unistd.h>        // usleep
   #include <biwak/uart.hpp>        // putc
   #include <lepto/log.h>        // blink
#endif

//#define printstr       puts
//#define printstr(a)       lHint << (a)
#define printstr(a)     fputs(a, stdout)
//#define printstr     printf

#include <lepto/lepto.h>
#include <lepto/log.h>

class CCommand;


CFosh::CFosh()
   :m_logedin(false)
{
   // Disable ECHO on Linux systems
   #if defined( LINUX ) && ! defined( STM32 )
   struct termios term, term_orig;

   if(tcgetattr(0, &term_orig))
   {
      printf("tcgetattr failed (%d)\n", errno);
      m_inputTerminal=false;
      return;
    }

    term = term_orig;

    term.c_lflag &= ~ICANON;
    term.c_lflag &= ~ECHO;
    term.c_cc[VMIN] = 0;
    term.c_cc[VTIME] = 0;

    if (tcsetattr(0, TCSANOW, &term)) {
      printf("tcsetattr failed\n");
      exit(-1);
    }
   #endif

   return;
}

void CFosh::addCommand(const CCommand *pCommand)
{
 m_commander.addCommand(pCommand);
}

void CFosh::printPrompt()
{
   if(m_logedin)
      printstr( "$ ");
   else
      printstr( "\nlogin: ");

   return;
}

int CFosh::eventLoop()
{
   int in;
   static bool firstLoop=true;

   if(firstLoop)
   {
      printPrompt();
      firstLoop=false;
   }
   
   #if ! defined( STM32 )
   if( !m_inputTerminal )
   {
      return(0);
   }
   #endif

   do
   {
      // Returns EOF if no data is available (Linux, Biwak)
      in=getchar();

      switch(in)
      {
         case '\r':     // STM32
         case '\n':     // Linux
         {
            printstr("\r\n");
            if( command.length() )
            {
               int sta=execCommand();
               if(sta)
               {
                  lCritical("Error executing command: sta=%d", sta);
               }
            }
            command.clear();
            printPrompt();
            break;
         }
         case EOF:
            break;
         case 0:
            // Decode not finished
            break;
         default:
            command+=(char)in;
            putchar(in);
      };
   }
   while(false);

   return(0);
};


int CFosh::execCommand()
{
   #if defined STM32
      char *line=command.data();
   #else
      char *line=command.toLatin1().data();
   #endif

   if(!m_logedin)
   {
      #if defined STM32
         login( command.data(), strlen(command.data()) );
      #else
         login( command.toLatin1().data(), strlen(command.toLatin1().data()) );
      #endif
      return(0);
   }

   int argc=0;
   const char *argv[10];

   if(line[0])
   {
      argv[argc++]=&line[0];
      for(int i1=0; line[i1] && argc<10; i1++)
         if(line[i1]==' ')
         {
            line[i1]=0;
            argv[argc++]=&line[i1+1];
         }
   }
   return ( m_commander.execCommand( argc, argv) );
}

void CFosh::login(const void *buf, int size)
{
   if(!memcmp(buf, "admin", strlen("admin")))
   {
      m_logedin=true;
      printstr("Successfully logged in\n");
   }
   else
   {
      printstr("Login not successfull. Type 'admin' to log in.\n");
      printstr("\n");
   }

   return;
}

