/*! 
* 
* Copyright(c) 2010 Apogee Instruments, Inc. 
* \class WinEthernetIO 
* \brief windows ethernet io 
* 
*/ 

// removes warnings about vectors
#pragma warning(disable: 4786)

#include "WinEthernetIO.h" 


//////////////////////////// 
//   CTOR
WinEthernetIO::WinEthernetIO() : m_hSession(NULL)
{
    m_hSession = InternetOpen( "ApogeeNet", 
				  			   INTERNET_OPEN_TYPE_DIRECT, 
							   NULL, 
							   NULL, 
							   0 );

    if( NULL == m_hSession )
	{
        throw std::runtime_error("InternetOpen FAILED");
	}
}

//////////////////////////// 
//   DTOR
WinEthernetIO::~WinEthernetIO()
{ 
    InternetCloseHandle( m_hSession ); 
    m_hSession = NULL;
} 

//////////////////////////// 
//      HTTP   GET
void WinEthernetIO::HttpGet( const std::string & Url,  std::string & data)
{
    
    HINTERNET hService = NULL;

    FetchService( Url, &hService);

    try
    {
        DWORD dwBytesAvailable = 0; 

        if( !InternetQueryDataAvailable( hService, &dwBytesAvailable, 0, 0 ) )
        {
            throw std::runtime_error( "InternetQueryDataAvailable FAILED" );
        }

        if(  0 == dwBytesAvailable )
        {
            std::string msg = "Get function, " + Url + ", FAILED.";
		    throw std::runtime_error( msg );
        }

        data.erase(data.begin(), data.end());
        data.resize(dwBytesAvailable);
        ReadData( &hService, &(*data.begin()), dwBytesAvailable );

        InternetCloseHandle( hService );
    }
    catch(std::exception & err)
    {
        InternetCloseHandle( hService );
        throw err;
    }

}


//////////////////////////// 
//      HTTP   GET
void WinEthernetIO::HttpGet( const std::string & Url,  std::vector<unsigned short> & data,
                            const int numBytesExpected)
{
    HINTERNET hService = NULL;

    FetchService( Url, &hService);

    try
    {
        data.clear();
        data.resize(numBytesExpected / sizeof(unsigned short));


        DWORD dwBytesAvailable = 0; 
        DWORD dwTotalBytes = 0;
        int loopCount = 0;
        const int MAX_NUM_LOOPS = 50000;

        while(  numBytesExpected > dwTotalBytes )
        {
 
            if( !InternetQueryDataAvailable( hService, &dwBytesAvailable, 0, 0 ) )
            {
                throw std::runtime_error( "InternetQueryDataAvailable FAILED" );
            }

            if(  0 == dwBytesAvailable )
            {
                std::string msg = "Get function, " + Url + ", FAILED.";
		        throw std::runtime_error( msg );
            }

            std::vector<unsigned short>::iterator iter = data.begin()+( dwTotalBytes / sizeof(unsigned short) );
            ReadData( &hService, &(*iter), dwBytesAvailable );

            dwTotalBytes += dwBytesAvailable;

            //make sure we don't end up in an infinite while loop
            if( loopCount > MAX_NUM_LOOPS )
            {
                throw std::runtime_error( "Get failed to complete." );
            }

            ++loopCount;
        }


        InternetCloseHandle( hService );
    }
    catch(std::exception & err)
    {
        InternetCloseHandle( hService );
        throw err;
    }
}


//////////////////////////// 
//  FETCH    SERVICE
void WinEthernetIO::FetchService( const std::string & Url, HINTERNET * service )
{
    if ( NULL == m_hSession  )
    {
        throw std::runtime_error( "Internet session not open" );
    }

    *service = InternetOpenUrl( m_hSession, Url.c_str(), NULL, 0, 0, 0 );

	if ( NULL == *service)
	{
		std::string msg = "Opening URL failed: " + Url;
		throw std::runtime_error( msg );
	}
}

//////////////////////////// 
//  READ      DATA
void WinEthernetIO::ReadData( HINTERNET * service, void * data, const DWORD BytesAvailable )
{
    DWORD  dwBytesRead = 0;

    if( !InternetReadFile( *service, data, BytesAvailable, &dwBytesRead ) )
    {
        throw std::runtime_error( "InternetReadFile FAILED" );
    }

    if( BytesAvailable != dwBytesRead )
    {
        std::string msg = "Number of bytes read DOES NOT EQUAL number of bytes available";
        throw std::runtime_error( msg );
    }

}

 
