/*
 * Video On Demand Samples
 *
 * Copyright (C) 2015 Microchip Technology Germany II GmbH & Co. KG
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * You may also obtain this software under a propriety license from Microchip.
 * Please contact Microchip for further information.
 *
 */

#include "Types.h"
#include "Xml.h"

#define CHILD(x)    ( (x) ? (x)->xmlChildrenNode : NULL )




CXml::CXml( const char *szFile )
{
    m_Doc = xmlReadFile( szFile, NULL, 0 );

    if( NULL == m_Doc )
        LOG("unable to open XML file\n");
    else
        m_bDocOpened = true;
}



CXml::CXml( const char *szBuffer, uint32_t nBufferLen )
{
    if( NULL == szBuffer || strlen( szBuffer ) >= nBufferLen )
    {
        LOG("Parameter error in constructor of memory driven CXml\n");
    }
    m_Doc = xmlReadMemory( szBuffer, strlen( szBuffer ), "config.xml", NULL, 0 );

    if( NULL == m_Doc )
        LOG("unable to open XML buffer\n");
    else
        m_bDocOpened = true;
}




CXml::CXml( CXml &Node ) : m_Doc( Node.m_Doc ), m_Node( Node.m_Node ), m_bDocOpened( false )
{
}





CXml::~CXml()
{
    if( m_bDocOpened )
        xmlFreeDoc( m_Doc );
}





bool CXml::SetToTopNode()
{
    m_Node = xmlDocGetRootElement( m_Doc );
    m_Node = CHILD(m_Node);

    return ( NULL != m_Node );
}





bool CXml::FindFirstChildNode()
{
    m_Node = CHILD(m_Node);
    return ( NULL != m_Node );
}





bool CXml::FindNextNode()
{
    if( NULL == m_Node )
        return false;

    m_Node = m_Node->next;

    return NULL != m_Node;
}





bool CXml::FindNode( const xmlChar *szTag )
{
    if( NULL == m_Node || NULL == szTag )
    {
        m_Node = NULL;
        return false;
    }

    while( m_Node && xmlStrcmp( m_Node->name, szTag ) )        // search in all nodes
        m_Node = m_Node->next;

    return ( NULL != m_Node );
}





bool CXml::GetChildValue( const xmlChar *szTag, xmlChar *szValue, int nMaxLen )
{
    xmlNode *nodeMem = m_Node;
    FindFirstChildNode();
    FindNode( szTag );

    if( NULL == m_Node )
    {
        m_Node = nodeMem;
        return false;
    }

    xmlChar *szTmp = xmlNodeListGetString( m_Doc, m_Node->xmlChildrenNode, 1 );
    m_Node = nodeMem;

    if( NULL == szTmp )
        return false;

    if( xmlStrlen( szTmp ) >= nMaxLen )
    {
        xmlFree( szTmp );
        return false;
    }

    memcpy( szValue, szTmp, sizeof( xmlChar ) * ( xmlStrlen( szTmp ) + 1 ) );
    xmlFree( szTmp );

    return true;
}





bool CXml::GetChildValueInt( const xmlChar *szTag, int &nValue )
{
    xmlNode *nodeMem = m_Node;
    FindFirstChildNode();
    FindNode( szTag );
    xmlNode *node = m_Node;
    m_Node = nodeMem;

    if( NULL == node )
    {
        return false;
    }

    xmlChar *szVal = xmlNodeListGetString( m_Doc, node->xmlChildrenNode, 1 );

    if( NULL == szVal )
        return false;

    nValue = (szVal[0] == '0' && (szVal[1] =='x' || szVal[1] =='X')) ?
        strtol(  ( char * )szVal + 2, NULL, 16 ) :
        atoi( ( char * )szVal );

    xmlFree( szVal );

    return true;
}





bool CXml::FindNodeWithValue( const xmlChar *szNodeTag, const xmlChar *szValueTag, const xmlChar *szValue )
{
    while( FindNode( szNodeTag ) )
    {                           // search node fitting to NodeTag
        xmlChar *szCmp = NULL;

        if( GetChildValue( szValueTag, szCmp ) )
        {             // get nodes value fitting to ValueTag
            int nCmp = xmlStrcmp( szValue, szCmp );           // value fitting to compare value
            xmlFree( szCmp );

            if( 0 == nCmp )                                  // search completed?
                break;
        }

        m_Node = m_Node->next;                              // continue with next node
    }

    return ( NULL != m_Node );
}





bool CXml::FindNodeWithValueInt( const xmlChar *szNodeTag, const xmlChar *szValueTag, int nValue )
{
    int nCmp;

    while( FindNode( szNodeTag ) &&
        GetChildValueInt( szValueTag, nCmp ) &&
        nValue != nCmp )
    {
        FindNextNode();
    }

    return NULL !=
        m_Node;                                  // return found node or NULL;
}


int CXml::ConvertToInt( xmlChar *xString )
{
    char *cString = ( char * )xString; //Convertion may be needed..
    for( uint32_t i = 0; i < strlen( cString ); i++ )
    {
        if( cString[i] >= 65 && cString[i] <= 90 )
        {
            //convert upper case to lower case
            cString[i] += 32;
        }
    }
    return strtol( cString, NULL, 16 );
}