/****************************************************************************
 * [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame      |   \\._.//   *
 * -----------------------------------------------------------|   (0...0)   *
 * SMAUG 1.4 (C) 1994, 1995, 1996, 1998  by Derek Snider      |    ).:.(    *
 * -----------------------------------------------------------|    {o o}    *
 * SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus,      |   / ' ' \   *
 * Scryn, Rennard, Swordbearer, Gorog, Grishnakh, Nivek,      |~'~.VxvxV.~'~*
 * Tricops and Fireblade                                      |             *
 * ------------------------------------------------------------------------ *
 * Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael        *
 * Chastain, Michael Quan, and Mitchell Tse.                                *
 * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,          *
 * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.     *
 * ------------------------------------------------------------------------ *
 *                            Spell handling module                         *
 ****************************************************************************/

#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include "mud.h"

/*
 * Perform a binary search on a section of the skill table	-Thoric
 * Each different section of the skill table is sorted alphabetically
 *
 * Check for prefix matches.
 *
 * Made static by dchaley 2007-06-22. Nobody has any business calling the
 * binary search directly; they should only use the skill_lookup or
 * find_* functions. (A practical reason is that a bsearch call will
 * prevent you from finding skills in the interval used for skills created
 * after MUD boot.)
 */
static int bsearch_skill_prefix( const char *name, int first, int top )
{
   int sn;

   for( ;; )
   {
      sn = ( first + top ) >> 1;
      if( !IS_VALID_SN( sn ) )
         return -1;
      if( LOWER( name[0] ) == LOWER( skill_table[sn]->name[0] ) && !str_prefix( name, skill_table[sn]->name ) )
         return sn;
      if( first >= top )
         return -1;
      if( strcasecmp( name, skill_table[sn]->name ) < 1 )
         top = sn - 1;
      else
         first = sn + 1;
   }
}

/*
 * Perform a binary search on a section of the skill table	-Thoric
 * Each different section of the skill table is sorted alphabetically
 *
 * Check for exact matches only.
 *
 * Made static by dchaley 2007-06-22. Nobody has any business calling the
 * binary search directly; they should only use the skill_lookup or
 * find_* functions. (A practical reason is that a bsearch call will
 * prevent you from finding skills in the interval used for skills created
 * after MUD boot.)
 */
static int bsearch_skill_exact( const char *name, int first, int top )
{
   int sn;

   for( ;; )
   {
      sn = ( first + top ) >> 1;

      if( !IS_VALID_SN( sn ) )
         return -1;
      if( !strcasecmp( name, skill_table[sn]->name ) )
         return sn;
      if( first >= top )
         return -1;
      if( strcasecmp( name, skill_table[sn]->name ) < 1 )
         top = sn - 1;
      else
         first = sn + 1;
   }
}

/*
 * Lookup a skill by slot number.
 * Used for object loading.
 */
int slot_lookup( int slot )
{
   int sn;

   if( slot <= 0 )
      return -1;

   for( sn = 0; sn < num_skills; ++sn )
      if( slot == skill_table[sn]->slot )
         return sn;

   bug( "%s: bad slot %d.", __FUNCTION__, slot );
   abort(  );
}

/*
 * Lookup a skill by name.
 *
 * First tries to find an exact match. Then looks for a prefix match.
 * Rehauled by dchaley 2007-06-22.
 */
int skill_lookup( const char *name )
{
   int sn;

   // Try to find an exact match for this skill.
   if( ( sn = bsearch_skill_exact( name, 0, num_sorted_skills - 1 ) ) == -1 )
   {
      // We failed to find an exact match;
      // so try to find a prefix match.
      if( ( sn = bsearch_skill_prefix( name, 0, num_sorted_skills - 1 ) ) == -1 )
      {
         // We failed to find the skill in the sorted skills. It is
         // possible that the skill was added after the game booted;
         // so try looking through the unsorted skills.
         for( sn = num_sorted_skills; sn < num_skills; ++sn )
         {
            // have we reached the end of the skills?
            if( !skill_table[sn] || !skill_table[sn]->name )
            {
               bug( "%s: WARNING: skill table entry %d had bad skill", __FUNCTION__, sn );
               return -1;
            }

            // is this the one we want?
            if( !str_prefix( name, skill_table[sn]->name ) )
               return sn;
         }
         return -1;
      }
   }
   return sn;
}