/*!
THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES INC. ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE
DISCLAIMED. IN NO EVENT SHALL ANALOG DEVICES INC. BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

YOU ASSUME ANY AND ALL RISK FROM THE USE OF THIS CODE OR SUPPORT FILE.

IT IS THE RESPONSIBILITY OF THE PERSON INTEGRATING THIS CODE INTO AN APPLICATION
TO ENSURE THAT THE RESULTING APPLICATION PERFORMS AS REQUIRED AND IS SAFE.

    @file        : menu.c
    @brief       : Menu Handling functions
    @date        : 19th June 2010
    @version     : v1.00
    Changelog    : v1.00 Initial
*/
/** \addtogroup Menu_Driver Menu Functions
 *  @{
 */

#include <include.h>

/*! 
The menu system will show at most MAX_USER_ENTRIES out of the total number of
available options. This should be 1 <= MAX_USER_ENTRIES <= 10.
 */ 
#define MAX_USER_ENTRIES 10  

// Local Functions
static void DoPrompt(boolean bTopLevel,boolean bNext,boolean bPrevious,int iNumOptions);


/*! 
    \fn      void DoPrompt(boolean bTopLevel,boolean bNext,boolean bPrevious,int iNumOptions)
    \brief   Display a menu prompt, asking the user to select from a number of options.

             The function also inserts Exit, Next and previous options if requested.

    \param[in]   bTopLevel      #TRUE if a Top level menu, or #FALSE if not. An Exit option is presented for non-toplevel menus.
    \param[in]   bNext          #TRUE if more options follow these in the menu, or #FALSE if not. A Next option is presented if TRUE.
    \param[in]   bPrevious      #TRUE if more options preceed these in the menu, or #FALSE if not. A Previous option is presented if TRUE.
    \param[in]   iNumOptions    Number of options in the menu

    @sa          void DoMenu(const char * pMenuText, TyMenuItem *pMenu,boolean bTopLevel,pfMenuBackgroundFunc BkgrndFunc)
    @note        This function is only called by DoMenu
*/
static void DoPrompt(boolean  bTopLevel,
                     boolean  bNext,
                     boolean  bPrevious,
                     int      iNumOptions)
{
   int       iEntry     = 0;

   printf("\n\n Please choose ");
   if (!bTopLevel)
      printf("E, ");
   if (bNext)
      printf("N, ");
   if (bPrevious)
      printf("P, ");
   for (iEntry = 0; iEntry < iNumOptions;iEntry++)
      printf("%d, ",iEntry);
   printf("or %d > ",iEntry);
}

/*! 
    \fn      void DoMenu(const char * pMenuText, TyMenuItem *pMenu,boolean bTopLevel,pfMenuBackgroundFunc BkgrndFunc)
    \brief   Display and handle a menu.

             Handles displaying of a menu and the calling of the menu item handlers.

    \param[in]       pMenuText            Menu Title
    \param[in]       pMenu                Menu to display
    \param[in]       bTopLevel            Root menu or not
    \param[in]       BkgrndFunc           Function to call in the background

*/
void DoMenu(const char *         pMenuText, 
            TyMenuItem *         pMenu,
            boolean              bTopLevel,
            pfMenuBackgroundFunc BkgrndFunc)
{
   int       iChar;
   int       iMnuIndex     = 0;
   int       iMaxIndex     = 0;
   boolean   bNext;
   boolean   bPrevious;

   int       iTotalEntries       = 0x0; // Total Number of menu items
   int       iSubSetIndxStart    = 0x0; // Start number of subset to display

   // Determine the total number of entries (last entry marked with NULL)
   iTotalEntries = 0x0;
   while(pMenu[iTotalEntries++].pszMenuText);
   iTotalEntries--;

   do
      {
      printf("\n****************************  %s  ***************************\n",pMenuText);
      // Print the subset of entries that we are interested in
      iMnuIndex = 0;
      while(pMenu[iMnuIndex + iSubSetIndxStart].pszMenuText && (iMnuIndex < MAX_USER_ENTRIES))
         {
         printf("    %d. %s\n",iMnuIndex,pMenu[iMnuIndex + iSubSetIndxStart].pszMenuText);
         iMnuIndex++;
         }
      iMaxIndex = iMnuIndex - 1;

      // Display fixed menu items?
      bPrevious   = (iSubSetIndxStart != 0x0);
      bNext       = ((iSubSetIndxStart + iMaxIndex) != (iTotalEntries-1));
      if (!bTopLevel)
         printf("    E. Exit Menu\n");
      if (bPrevious)
         printf("    P. Previous Items\n");
      if (bNext)
         printf("    N. Next Items\n");

      DoPrompt(bTopLevel,bNext,bPrevious,iMaxIndex);

      // While we are waiting for input, do the caller supplied background func
      while(Urt_DataAvail() == 0x0)
         {
         if((BkgrndFunc != NULL) && BkgrndFunc())
            DoPrompt(bTopLevel,bNext,bPrevious,iMaxIndex);
         }

      // Handle user selection
      iChar = getchar();
      if((iChar < '0') || (iChar > ('0' + iMaxIndex)))
         {
         // Not 0 - 9, might be P,p,E,e,N, or n
         if (!bTopLevel && ((iChar == 'E') || (iChar == 'e')))
            break; // Exit the menu
         else
            if ((iSubSetIndxStart != 0x0) && ((iChar == 'P') || (iChar == 'p')))
               iSubSetIndxStart -= MAX_USER_ENTRIES; // Previous subset
            else
               if (((iSubSetIndxStart + iMaxIndex) != iTotalEntries) && ((iChar == 'N') || (iChar == 'n') ))
                  iSubSetIndxStart += MAX_USER_ENTRIES; // Next subset
         }
      else
         {
         // Handle 0 - 9 selection
         iMnuIndex = iChar - '0';
         if (pMenu[iMnuIndex+iSubSetIndxStart].MenuActionFunc)
            {
            printf("\n");
            pMenu[iMnuIndex+iSubSetIndxStart].MenuActionFunc();

            // Flush out any remaining uart bytes before the menu gets handled again
            while(Urt_DataAvail() == 0x1)
               (void)Urt_DataBytRd() ; 
            }
         }
      }
   while(1);
   printf("\n");
}

/*@}*/









