#include "stdafx.h"
#include "utilities.h"
#include <Iprtrmib.h>
#include <Iphlpapi.h>
#include <lmerr.h>


void PrintLastError(const char * identifier)
{
	DWORD dwLastError = GetLastError();
    HMODULE hModule = NULL; // default to system source
    LPSTR MessageBuffer;
    DWORD dwBufferLength;

    DWORD dwFormatFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
        FORMAT_MESSAGE_IGNORE_INSERTS |
        FORMAT_MESSAGE_FROM_SYSTEM ;

    //
    // If dwLastError is in the network range, 
    //  load the message source.
    //

    if(dwLastError >= NERR_BASE && dwLastError <= MAX_NERR) {
        hModule = LoadLibraryEx(
            TEXT("netmsg.dll"),
            NULL,
            LOAD_LIBRARY_AS_DATAFILE
            );

        if(hModule != NULL)
            dwFormatFlags |= FORMAT_MESSAGE_FROM_HMODULE;
    }

    //
    // Call FormatMessage() to allow for message 
    //  text to be acquired from the system 
    //  or from the supplied module handle.
    //

    if(dwBufferLength = FormatMessageA(
        dwFormatFlags,
        hModule, // module to get message from (NULL == system)
        dwLastError,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // default language
        (LPSTR) &MessageBuffer,
        0,
        NULL
        ))
    {
		print(L"%S: %S\n",identifier,MessageBuffer);
        //
        // Free the buffer allocated by the system.
        //
        LocalFree(MessageBuffer);
    }

    //
    // If we loaded a message source, unload it.
    //
    if(hModule != NULL)
        FreeLibrary(hModule);
}

int GetEncoderClsid(TCHAR* format, CLSID* pClsid)
{
   UINT  num = 0;          // number of image encoders
   UINT  size = 0;         // size of the image encoder array in bytes

   ImageCodecInfo* pImageCodecInfo = NULL;

   GetImageEncodersSize(&num, &size);
   if(size == 0)
      return -1;  // Failure

   pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
   if(pImageCodecInfo == NULL)
      return -1;  // Failure

   GetImageEncoders(num, size, pImageCodecInfo);

   for(UINT j = 0; j < num; ++j)
   {
      if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )
      {
         *pClsid = pImageCodecInfo[j].Clsid;
         free(pImageCodecInfo);
         return j;  // Success
      }    
   }

   free(pImageCodecInfo);
   return -1;  // Failure
}

int DrawTransparentImage(Graphics* graphics, Image* image, int x, int y, int width, int height)
{
	try {
		// Create an ImageAttributes object, and set its color key.
		ImageAttributes imAtt;
		imAtt.SetColorKey(
			env.TransparentColorLo, // lo end of transparent color range
			env.TransparentColorHi, // hi end of transparent color range
			ColorAdjustTypeBitmap);

		// Draw the image. Apply the color key.
		return (graphics->DrawImage(
			image, 
			Rect(x, y, image->GetWidth(), image->GetHeight()),  // dest rect
			0, 0, width, height,          // source rect
			UnitPixel,
			&imAtt)==Ok);
	} catch (...)  {
		print(L"DrawTransparentImage: Error drawing image.\n");
		PrintLastError("DrawTransparentImage");
		return 0;
	}
}

int DrawTransparentImage(Graphics* graphics, Image* image, int x, int y)
{
	try {
		// Create an ImageAttributes object, and set its color key.
		ImageAttributes imAtt;
		imAtt.SetColorKey(
			env.TransparentColorLo, // lo end of transparent color range
			env.TransparentColorHi, // hi end of transparent color range
			ColorAdjustTypeBitmap);

		// Draw the image. Apply the color key.
		return (graphics->DrawImage(
			image, 
			Rect(x, y, image->GetWidth(), image->GetHeight()),  // dest rect
			0, 0, image->GetWidth(), image->GetHeight(),          // source rect
			UnitPixel,
			&imAtt)==Ok);
	} catch (...) {
		print(L"Error drawing image.\n");
		return 0;
	}

}

TCHAR * GetLocalHostName()
{
	char tmp[1024];
	static TCHAR machine[1024];
	gethostname(tmp,1023);
	MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,tmp,-1,machine,1024);
	return machine;
}

TCHAR *GetLocalIPAddress()
{
  unsigned long bestInterfaceIndex;
  MIB_IPADDRTABLE *iptable=0;
  unsigned long buffersize = 0;

  unsigned long destAddr = inet_addr("18.7.21.70");
  int result = GetBestInterface(destAddr, &bestInterfaceIndex);
  GetIpAddrTable(iptable, &buffersize, 0); // first time, get the size in buffersize
  // now allocate the buffer
  iptable = (MIB_IPADDRTABLE *)(malloc(buffersize));
  // now call it again to get the table
  GetIpAddrTable(iptable, &buffersize, 0);

  // get what thloe IP address of the appropriate interface
  UINT i;
  unsigned long myaddr;
  for (i = 0; i < iptable->dwNumEntries; i++) {
    if (iptable->table[i].dwIndex == bestInterfaceIndex)
      myaddr = (iptable->table[i].dwAddr);
  }
  free(iptable);

  // convert it to a string an return it
  struct in_addr *ia;
  ia = (struct in_addr *)(&myaddr);
  return ConvertToWideString(inet_ntoa(*ia));
}

TCHAR * ConvertToWideString(const char * str)
{
	static TCHAR buffer[2048];
	MultiByteToWideChar(CP_ACP,0,str,-1,buffer,2048);
	return buffer;
}

void SafeWait(HANDLE event, const TCHAR * identifier)
{
	while(WaitForSingleObject(event,1000)==WAIT_TIMEOUT)
		print(L"%s: timing out\n",identifier);
}

DWORD SafeSendMessage(HWND h, UINT msg, WPARAM wparam, LPARAM lparam )
{
	DWORD ret;
	if(SendMessageTimeout( h,msg,wparam,lparam,SMTO_NORMAL|SMTO_NOTIMEOUTIFNOTHUNG, 1000, &ret)==0){
		PrintLastError("SendMessageTimeOut");
	}
	return ret;
}

int MeasureTextHeight(const TCHAR * fontname, int fontsize, const TCHAR * string, int width)
{
	try{
		HDC hdc = GetDC(GetDesktopWindow());		
		Graphics graphics(hdc);

		Font font(fontname, fontsize);
		RectF layoutRect(0, 0, width, 10000);
		RectF boundRect;

		// Measure the string.
		graphics.MeasureString(string, (int)wcslen(string), &font, layoutRect, &boundRect);

		ReleaseDC(GetDesktopWindow(),hdc);

		return boundRect.Height;
	} catch (...) {
		return 0;
	}
}

void DoEvents(){
	int count = 500;
    MSG msg ; 
    // Read all of the system messages in this next loop,
    // removing each message as we read it.
    while (PeekMessage(&msg, NULL, 0, WM_USER-1, PM_REMOVE)) 
	{
		if(msg.message==WM_QUIT){
			// post the message again and leave
			PostQuitMessage(0);
			break;
		}
		//dispatch the message.
        DispatchMessage(&msg); 
		if(count--==0) break;
    } 
}

// This will do events until one of the objects in the array has been signaled
// returns the index of the signaled object
int DoEventsUntil ( 
    HANDLE* lphObjects,  // handles that need to be waited on 
    int     cObjects     // number of handles to wait on 
  )
{ 
    // The message loop lasts until we get a WM_QUIT message,
    // upon which we shall return from the function.
    while (TRUE)
    {
        // block-local variable 
        DWORD result ; 
        MSG msg ; 

        // Read all of the messages in this next loop, 
        // removing each message as we read it.
		while (PeekMessage(&msg, NULL, 0, WM_USER-1, PM_REMOVE)) 
        { 
            // If it's a quit message, we're out of here.
			if(msg.message==WM_QUIT){
				// post the message again and leave
				PostQuitMessage(0);
				return 1;
			}
            // Otherwise, dispatch the message.
            DispatchMessage(&msg); 
        } // End of PeekMessage while loop.

        // Wait for any message sent or posted to this queue 
        // or for one of the passed handles be set to signaled.
        result = MsgWaitForMultipleObjects(cObjects, lphObjects, 
                 FALSE, INFINITE, QS_KEY|QS_MOUSE|QS_PAINT|QS_TIMER); 

        // The result tells us the type of event we have.
        if (result == (WAIT_OBJECT_0 + cObjects))
        {
            // New messages have arrived. 
            // Continue to the top of the always while loop to 
            // dispatch them and resume waiting.
            continue;
        } 
        else 
        { 
            // One of the handles became signaled. 
            return (result - WAIT_OBJECT_0) ; 
        } // End of else clause.
    } // End of the always while loop. 
} // End of function.


#define MAX_NICS 10
static IP_ADAPTER_INFO AdapterInfo[MAX_NICS];

void GetMacAddress(Vector<unsigned char>& addr)
{
	ULONG BufLen = sizeof(AdapterInfo);
	::ZeroMemory(&AdapterInfo,sizeof(AdapterInfo));
	DWORD dwRes = GetAdaptersInfo(AdapterInfo, (PULONG) &BufLen);
	if ( ERROR_SUCCESS == dwRes )
	{
		if(IsNetworkWireless()){
			// then find the wireless card
			int i;
			for(i=0; i<MAX_NICS && !strstr(AdapterInfo[i].Description,"Wireless"); i++);
			if ( i >= MAX_NICS )
				i = 0;

			// now i points at the wireless card
			unsigned int j;
			addr.allocate(AdapterInfo[i].AddressLength);
			for(j=0;j<AdapterInfo[i].AddressLength;j++)
				addr[j] = AdapterInfo[i].Address[j];
		} else {
			// just use the first non-wireless
			int i;
			for(i=0; i<MAX_NICS && strstr(AdapterInfo[i].Description,"Wireless"); i++);
			if ( i >= MAX_NICS )
				i = 0;

			// now i points at the first wired card
			unsigned int j;
			addr.allocate(AdapterInfo[i].AddressLength);
			for(j=0;j<AdapterInfo[i].AddressLength;j++)
				addr[j] = AdapterInfo[i].Address[j];
		}
	}
	
}

int IsNetworkWireless()
{
	unsigned long bestInterfaceIndex;
	unsigned long destAddr = inet_addr("18.7.21.70");
	int result = GetBestInterface(destAddr, &bestInterfaceIndex);

	// now determine the adapter the goes with this interface
	ULONG BufLen = sizeof(AdapterInfo);
	::ZeroMemory(&AdapterInfo,sizeof(AdapterInfo));
	DWORD dwRes = GetAdaptersInfo(AdapterInfo, (PULONG) &BufLen);
	if ( ERROR_SUCCESS == dwRes )
	{
		int i;
		for(i=0; i<MAX_NICS;i++){
			if(AdapterInfo[i].Index==bestInterfaceIndex){
				return strstr(AdapterInfo[i].Description,"Wireless")!=NULL;
			}
		}
		return 0;
	} else
		return 0;			
}

const char * GetNetworkAdapterName()
{
	unsigned long bestInterfaceIndex;
	unsigned long destAddr = inet_addr("18.7.21.70");
	int result = GetBestInterface(destAddr, &bestInterfaceIndex);

	// now determine the adapter the goes with this interface
	ULONG BufLen = sizeof(AdapterInfo);
	::ZeroMemory(&AdapterInfo,sizeof(AdapterInfo));
	DWORD dwRes = GetAdaptersInfo(AdapterInfo, (PULONG) &BufLen);
	if ( ERROR_SUCCESS == dwRes )
	{
		int i;
		for(i=0; i<MAX_NICS;i++){
			if(AdapterInfo[i].Index==bestInterfaceIndex){
				return AdapterInfo[i].Description;
			}
		}
		return "none";
	} else
		return "none";			
}

static BOOL bProxyConnection = true;

void SetProxy(BOOL b){
	bProxyConnection = b;
}

BOOL IsInternetConnection()
{
 char szHostName[128];

 BOOL bPrivateAdr = false; // Private Address area
 BOOL bClassA = false;     // Class A definition
 BOOL bClassB = false;     // Class B definition
 BOOL bClassC = false;     // Class C definition
 BOOL bAutoNet = false;    // AutoNet definition
 std::string str;

 if (gethostname(szHostName, 128) == 0 )
 {
  // Get host adresses
  struct hostent * pHost;
  int i;
  UINT ipb;
  pHost = gethostbyname(szHostName); 

  for (i = 0; 
       pHost!= NULL && pHost->h_addr_list[i]!= NULL; 
       i++ )
  {
   int j;
   str="";
   bClassA = bClassB = bClassC = false;
   for( j = 0; j < pHost->h_length; j++ )
   {
	   std::string addr;

    if( j > 0 )	str += ".";
    ipb = (unsigned int)((unsigned char*)pHost->h_addr_list[i])[j];

    // Define the IP range for exclusion
    if(j==0)
    {
     if(bClassA = (ipb == 10)) break; // Class A defined
     bClassB = (ipb == 172); 
     bClassC = (ipb == 192);
     bAutoNet = (ipb == 169);
    }
    else if (j==1)
    {
     // Class B defined
     if(bClassB = (bClassB && ipb >= 16 && ipb <= 31)) break;

     // Class C defined
     if(bClassC = (bClassC && ipb == 168)) break;

     //AutoNet pasibility defined
     if(bAutoNet = (bAutoNet && ipb == 254)) break;
    }

	char buffer[128];
	sprintf(buffer,"%u",ipb);
    addr = buffer;
    str += addr;
   }
   // If any address of Private Address 
   // area has been found bPrivateAdr = true
   bPrivateAdr = bPrivateAdr || bClassA || bClassB || bClassC;

   // If any address of Internet Address area 
   // has been found returns TRUE
   if (!bClassA 
   && !bClassB 
   && !bClassC 
   && !bAutoNet 
   && str != "127.0.0.1" 
   && str.length()>0) 
    return TRUE;
  }
 }

 if (bPrivateAdr)
 {
  // The system has IP address from Private Address 
  // area,only. Internet from the computer can be accessable 
  // via Proxy. If user turn on proxy connection flag, the 
  // function believe Internet accessable.
  return bProxyConnection;
 }
 
 return false;
}


// image resources
typedef struct _ImageResource {
	std::wstring filename;
	Image * image;
} ImageResource;

static std::list<ImageResource *> images;

Image * LoadImageResource(const TCHAR * filename)
{

	// first see if we have already loaded this image
	std::list<ImageResource*>::iterator i;
	for(i=images.begin();i!=images.end();i++){
		ImageResource * ir = *i;
		if(ir->filename==filename){
			return ir->image;
		}
	}

	// the image isn't loaded yet
	ImageResource * ir = new ImageResource;
	ir->filename = filename;
	print(L"	Image Resource (%d): %s\n",images.size(),filename);
	ir->image = Image::FromFile(filename);

	images.push_back(ir);

	return ir->image;
}

TCHAR * ConvertTimeSpanToCompactString(COleDateTimeSpan & span)
{
	static TCHAR buffer[1000];
	int total = span.GetTotalSeconds();

	if(total<60){ // seconds
		_stprintf(buffer,L"%d secs",span.GetSeconds());		
	} else if(total<3600){ // minutes
		_stprintf(buffer,L"%d mins",span.GetMinutes());		
	} else if(total<24*3600){ // hours
		_stprintf(buffer,L"%d hrs %d mins",span.GetHours(),span.GetMinutes());		
	} else { // days
		_stprintf(buffer,L"%d days %d hrs",span.GetDays(),span.GetHours());		
	}

	return buffer;
}