/* ---------------------------------------------------------------------
   (c) ED 2005
   Project      : CLIB
   Function     : Command interpretor
   Module       : CI
   File         : ci.c
   Created      : 11-03-2005
   Modified     : 08-05-2005
   --------------------------------------------------------------------- */

/* ---------------------------------------------------------------------
   Log

   0.0 11-03-2005 Created
   1.0 11-03-2005 Initial version
   1.1 11-03-2005 debug 'interpretor()'
   1.2 08-05-2005 ci_serr() added

   --------------------------------------------------------------------- */
#ifdef __cplusplus
#error This is not C++. Please use a C compiler.
#endif

#include "ed/inc/ci.h"
#include "ed/inc/sysalloc.h"
#include "ed/inc/sys.h"
#include "ed/inc/tok.h"

/* private macro definitions =========================================== */

#define ID "CI"
#define VER "1.2"

/* private constants =================================================== */

/* private types ======================================================= */

/* private structures ================================================== */

#if CI_ADT
struct ci
{
   ci_out_f *pf;
   void *p_usr;
};
#endif /* ADT */

/* private data ======================================================== */
/* private functions =================================================== */

/* ---------------------------------------------------------------------
   help_cde ()
   ---------------------------------------------------------------------

   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
static void usage (ci_s * this, char const *param)
{
   if (param == NULL)
   {
      size_t n = 2;
      size_t i;

      printf ("command list\n");
      printf ("%-10s", "help");
      printf ("%-10s", "quit");

      for (i = 0; i < this->nb_cde; i++)
      {
         ci_cfg_s const *p = this->p_cfg + i;

         printf ("%-10s", p->s_cde);

         n++;
         if (n % 8 == 0)
         {
            printf ("\n");
         }

      }
      if (n % 8 != 0)
      {
         printf ("\n");
      }
   }
   else
   {
      size_t i;

      for (i = 0; i < this->nb_cde; i++)
      {
         ci_cfg_s const *p = this->p_cfg + i;

         if (strcmp (param, p->s_cde) == 0)
         {
            printf ("\nUSAGE %s %s"
                    ,param
                    ,p->s_man
               );
            fflush (stdout);
         }
      }
   }
}

/* ---------------------------------------------------------------------
   interpretor ()
   ---------------------------------------------------------------------
   interpreteur de commande
   ---------------------------------------------------------------------
   I: tableau des commandes
   I: nombre de commandes
   I: nombre de parametre (y compris la commande)
   I: liste des parametres (y compris la commande)
   O: 0=OK ou ignoree 1=erreur -1=inconnue
   --------------------------------------------------------------------- */
static int interpretor (ci_cfg_s const *p_cfg
                        ,size_t nb
                        ,int argc
                        ,char const **argv)
{
   int ret = 0;

   if (p_cfg != NULL && nb != 0 && argc > 0 && argv != NULL)
   {
      char const *s_cde = argv[0];
      size_t i;

      /* par defaut : commande inconnue */
      ret = -1;

      for (i = 0; i < nb; i++)
      {
         ci_cfg_s const *p = p_cfg + i;

         if (strcmp (s_cde, p->s_cde) == 0)
         {
            if (p->pf_cde != NULL)
            {
               ret = p->pf_cde (argc, argv);
            }
            break;
         }
      }
   }
   else
   {
      /* commande non traitable, ignoree  */
      ret = 0;
   }
   return ret;
}

/* public internal functions =========================================== */

/* entry points ======================================================== */

/* ---------------------------------------------------------------------
   ci_sid ()
   ---------------------------------------------------------------------

   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
char const *ci_sid (void)
{
   return ID;
}

/* ---------------------------------------------------------------------
   ci_sver ()
   ---------------------------------------------------------------------

   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
char const *ci_sver (void)
{
   return VER;
}

/* ---------------------------------------------------------------------
   ci_serr ()
   ---------------------------------------------------------------------

   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
char const * ci_serr (ci_err_e err)
{
   char const *s = "CI_ERR_???";

   if (err < CI_ERR_NB)
   {
      static char const *as[] =
      {
         "CI_OK",
#define ITEM(n_, s_)\
         s_,

#include "ed/inc/ci_err.itm"

#undef ITEM

      };
      s = as[err];
   }
   return s;
}
/* ---------------------------------------------------------------------
   ci_create ()
   ---------------------------------------------------------------------

   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
ci_s *ci_create (void)
{
   ci_s *this = malloc (sizeof *this);
   if (this != NULL)
   {
      CLR (this, ci_s);

/*    -> Insert your code here */

   }
   return this;
}

/* ---------------------------------------------------------------------
   ci_delete ()
   ---------------------------------------------------------------------

   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
void ci_delete (ci_s * this)
{
   if (this != NULL)
   {

/*   -> Insert your code here */

      free (this);
   }
}

/* ---------------------------------------------------------------------
   ci_init ()
   ---------------------------------------------------------------------

   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
ci_err_e ci_init (ci_s * this, ci_cfg_s const *p_cfg, size_t nb)
{
   ci_err_e err = CI_OK;

   if (this != NULL)
   {
      this->p_cfg = p_cfg;
      this->nb_cde = nb;
   }
   else
   {
      err = CI_ERR_CONTEXT;
   }
   return err;
}

/* ---------------------------------------------------------------------
   ci_install_out ()
   ---------------------------------------------------------------------

   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
ci_err_e ci_install_out (ci_s * this, ci_out_f * pf, void *p_usr)
{
   ci_err_e err = CI_OK;

   if (this != NULL)
   {
      this->pf = pf;
      this->p_usr = p_usr;
   }
   else
   {
      err = CI_ERR_CONTEXT;
   }
   return err;
}

/* ---------------------------------------------------------------------
   ci_in ()
   ---------------------------------------------------------------------

   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
ci_err_e ci_in (ci_s * this, char const *sline)
{
   ci_err_e err = CI_OK;

   if (this != NULL)
   {
      tok_s *p_tok = tok_create (sline, " ", NULL);

      if (p_tok != NULL)
      {
         tok_info_s info;

         tok_get (p_tok, &info);

         if (info.argc > 0)
         {
            if (strcmp ("quit", info.argv[0]) == 0)
            {
               err = CI_ERR_QUIT;
            }
            else if (strcmp ("help", info.argv[0]) == 0)
            {
               if (info.argc > 1)
               {
                  usage (this, info.argv[1]);
               }
               else
               {
                  usage (this, NULL);
               }
            }
            else
            {
               int ret = interpretor (this->p_cfg, this->nb_cde, info.argc, info.argv);

               switch (ret)
               {
               case 1:
                  err = CI_ERR_CDE_PARAMETER;
                  break;

               case -1:
                  err = CI_ERR_CDE_UNKNOWN;
                  break;

               default:
                  ;
               }
            }
         }
         else
         {
            err = CI_ERR_NO_COMMAND;
         }

         tok_delete (p_tok), p_tok = NULL;
      }
      else
      {
         err = CI_ERR_NO_COMMAND;
      }
   }
   else
   {
      err = CI_ERR_CONTEXT;
   }
   return err;
}

/* public data ========================================================= */

/* ---------------------------------------------------------------------
   Generated by NEW (c) ED 2.4
   Powered by C-code generator (c) ED 2003 1.0
   --------------------------------------------------------------------- */
