/**
 * @file ctlrlist.cc
 *
 * ControllerList - Class for maintaining a list of CAPI controllers.
 *
 * Copyright: 2005 Thomas Wintergerst. All rights reserved.
 *
 * $Id: ctlrlist.cc,v 1.1.2.1 2006/02/28 21:35:45 thomas Exp $
 * $Project:    CAPI for BSD $
 * $Target:     Common source files for c4b tools $
 * @date        06.05.2005
 * @author      "Thomas Wintergerst" <twinterg@gmx.de>
 * <p>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * </p>
 */

#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");

// Own interface
#include "ctlrlist.h"

// System includes
#include <stdexcept>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <functional>

// Import includes

#define __CTLRLIST__

// Local includes





// === Private definitions ===============================================





// === Definitions for public declarations ===============================





// === Prototypes for private functions ==================================





// === Implementation of class members ===================================





// --- The data maintained for a controller of the list ------------------

/**
 * Constructor.
 */

CController::CController
   (unsigned                    uCtlrNum,
    const CAPICtlrDriverInfo_t &driverInfo):
   m_uCtlrNum (uCtlrNum),
   m_ctlrInfo (driverInfo)
{
   m_strName = m_ctlrInfo.szCtlrName;
   
   size_t n;
   n = m_strName.find ('/');
   if (n == std::string::npos)
   {
      m_strBoardName = m_strName;
   }
   else
   {
      m_strBoardName = m_strName.substr (0, n);
   }
   
} // CController::CController





/**
 * Get the name of the controller.
 */

const std::string &CController::GetControllerName (void) const
{
   return (m_strName);
} // CController::GetControllerName





/**
 * Get the name of the board the controller is on.
 *
 * The board name in this context is defined as the first part of the
 * controller name delimited by a "/" character. If there is none the
 * board name and the controller name are identical.
 *
 * The "/" character is mostly used to add a port number to the name of
 * multi-port boards, so the controller name is unique. This port number
 * suffix is substracted when determining the board name.
 */

const std::string &CController::GetBoardName (void) const
{
   return (m_strBoardName);
} // CController::GetBoardName





/**
 * Get the CAPI controller number.
 */

unsigned CController::GetControllerNumber (void) const
{
   return (m_uCtlrNum);
} // CController::GetControllerNumber





/**
 * Get the port index for this controller.
 */

unsigned CController::GetPortIndex (void) const
{
   return (C_GET_WORD (m_ctlrInfo.wPortIdx));
} // CController::GetPortIndex





/**
 * Ask if the name of the controller is identical to a string.
 */
bool CController::NameIs
   (const char *psz)
{
   if (psz == NULL)
   {
      return (false);
   }
   return (strcasecmp (m_strName.c_str (), psz) == 0);
} // CController::NameIs





/**
 * Ask if the name of the controller's board is identical to a string.
 */
bool CController::BoardNameIs
   (const char *psz)
{
   if (psz == NULL)
   {
      return (false);
   }
   return (strcasecmp (m_strBoardName.c_str (), psz) == 0);
} // CController::BoardNameIs





/**
 * Ask if this controller's number is identical to a specific number.
 */
bool CController::CtlrNumIs
   (unsigned u)
{
   return (m_uCtlrNum == u);
} // CController::CtlrNumIs





// --- Class for maintaining a list of CAPI controllers ------------------

/**
 * Constructor.
 *
 * @param strDriverName         I: The name of the controller driver to look
 *                                 for. Only controllers for this driver name
 *                                 are inserted into the list.
 * @param fQuiet                I: Print out a line of all controllers added to
 *                                 the list or not.
 *
 * @return Nothing.
 */

CControllerList::CControllerList
   (const std::string &strDriverName,
    bool               fQuiet):
   std::list<CController> ()
{
   CAPIProfileBuffer_t  profile;
   CAPICtlrDriverInfo_t drvInfo;
   int                  i;
   unsigned             uNumCtlr;
   unsigned             u;
   unsigned             uRes;
   
   // determine the total number of available CAPI controllers
   uRes = capi20_get_profile (0, &profile);
   if (uRes != CAPI_OK)
   {
      std::ostringstream oss;
      oss << "Error getting number of installed controllers: 0x"
          << std::hex << std::setfill ('0') << std::setw (4) << uRes;
      throw std::runtime_error (oss.str ());
   }
   uNumCtlr = C_GET_WORD (profile.wCtlr);
   if (uNumCtlr == 0)
   {
      // no controllers installed leave this list empty
      return;
   }
   
   // now query all controllers until all found
   for (i = 1, u = 0; i <= 127 && u < uNumCtlr; i++)
   {
      // get information about the current controller number
      uRes = capi20_get_ctlr_driver_info ((unsigned) i, &drvInfo);
      if (uRes == CRE_CAPI_NOT_INSTALLED)
      {
         // seems to be a hole in the array of CAPI controllers...
         continue;
      }
      
      // count the controller found, even if we did not get any information
      u++;
      if (uRes != CAPI_OK)
      {
         std::cerr << "Error getting driver information for controller "
                   << std::dec << i << ": 0x"
                   << std::hex << std::setfill ('0') << std::setw (4) << uRes
                   << std::endl;
         continue;
      }
      
      // if it is an ISDN controller we shall treat specially, create a
      // controller object for it
      if (strcasecmp (drvInfo.szDriverName, strDriverName.c_str ()) == 0)
      {
         push_back (CController ((unsigned) i, drvInfo));
         
         if (! fQuiet)
         {
            CController &ctlr = back ();
            std::cout << "Controller found: " << ctlr.GetControllerName ()
                      << std::endl;
         }
      }
   }
   
} // CControllerList::CControllerList





/**
 * Destructor.
 */

CControllerList::~CControllerList (void)
{
   // nothing to do
   
} // CControllerList::~CControllerList





/**
 * Find a controller through its name.
 */

CControllerList::const_iterator CControllerList::find
   (const std::string &strName)
{
   return (std::find_if (begin (), end (),
                         std::bind2nd
                            (std::mem_fun_ref (&CController::NameIs),
                             strName.c_str ())));
} // CControllerList::find





/**
 * Find a controller through its CAPI controller number.
 */

CControllerList::const_iterator CControllerList::find
   (unsigned uCtlrNum)
{
   return (std::find_if (begin (), end (),
                         std::bind2nd
                            (std::mem_fun_ref (&CController::CtlrNumIs),
                             uCtlrNum)));
} // CControllerList::find





/**
 * Find a controller through its board name.
 */

CControllerList::const_iterator CControllerList::find_by_board_name
   (const std::string &strBoardName)
{
   return (std::find_if (begin (), end (),
                         std::bind2nd
                            (std::mem_fun_ref (&CController::BoardNameIs),
                             strBoardName.c_str ())));
} // CControllerList::find_by_board_name





// === Implementation of public functions ================================





// === Implementation of private functions ===============================
