/*
 * Credits Block *** PLEASE DO NOT REMOVE ***
 * 
 * UDS (UpDownSpeed) SAORI is modified from KSM's SAORI Sample.
 * 
 * IP helper code snippets are taken from:
 * Retrieve the number of bytes sent/received (and other useful infos) for any network adapter
 * http://www.codeproject.com/internet/BytesSentReceived.asp
 * 
 * Copyright(C) Roy 2007. Some Rights Reserved.
 * Licence: CC-SA 3.0 ( http://creativecommons.org/licenses/by-sa/3.0/deed.zh_TW )
 */

#include <windows.h>
#include <malloc.h>

#include <stdlib.h>

#ifdef _DEBUG
#include <stdio.h>
#endif

#include "Iprtrmib.h"

//#include <iostream.h>
#include <string>
#include <iterator>

#include "util.h"

typedef DWORD (_stdcall *TGetIfTable) (
  MIB_IFTABLE *pIfTable,  // buffer for interface table 
  ULONG *pdwSize,         // size of buffer
  BOOL bOrder             // sort the table by index?
);

typedef DWORD (_stdcall *TGetNumberOfInterfaces) (
  PDWORD pdwNumIf  // pointer to number of interfaces
);

TGetIfTable pGetIfTable;
TGetNumberOfInterfaces pGetNumberOfInterfaces;
DWORD odwInOctets,odwOutOctets;
DWORD m_dwAdapters;
MIB_IFTABLE *m_pTable;

using namespace std;

FILE *log;

extern "C" __declspec(dllexport) BOOL __cdecl load(HGLOBAL h, long len)
{
	pGetIfTable=(TGetIfTable)GetProcAddress(LoadLibrary("Iphlpapi.dll"),"GetIfTable");
	pGetNumberOfInterfaces=(TGetNumberOfInterfaces)GetProcAddress(LoadLibrary("Iphlpapi.dll"),"GetNumberOfInterfaces");

	m_pTable=NULL;
	odwInOctets = 0;
	odwOutOctets = 0;

	return TRUE;
}

extern "C" __declspec(dllexport) BOOL __cdecl unload(void)
{
	if (m_pTable)
		delete [] m_pTable;

	m_pTable=NULL;

	return (true);
}

extern "C" __declspec(dllexport) HGLOBAL __cdecl request(HGLOBAL h, long *len)
{
	HGLOBAL Answer;
	string ret;

	string Request((char*)h,*len);


/*	log=fopen("c:\\saori.log","w");
	fputs(Request.c_str(),log);
	fclose(log);
*/
	GlobalFree(h);
	
	util MyUnit(Request);
	if (MyUnit.showSAORIREQ() == GET_VERSION) {
		ret = MyUnit.showSAORIVER() + " 204 No Content\r\n\r\n";
	} else if (MyUnit.showSAORIARG(0) == "ListInt") {
		if (pGetIfTable && pGetNumberOfInterfaces) {
			m_pTable=NULL;

			m_dwAdapters=0;

			ULONG uRetCode=pGetIfTable(m_pTable,&m_dwAdapters,TRUE);

			if (uRetCode == 0 || uRetCode == 122 /* The data area passed to a system call is too small.*/) {
				if (uRetCode == 122) {
					// now we know how much memory allocate
					m_pTable=new MIB_IFTABLE[m_dwAdapters];
					pGetIfTable(m_pTable,&m_dwAdapters,TRUE);
				}

				ret = MyUnit.showSAORIVER();
				ret = ret + " 200 OK\r\n";

				if(!atoi(MyUnit.showSAORIARG(1).c_str())) {

					ret = ret + "Result: OK\r\n";

					for (UINT i=0;i<m_pTable->dwNumEntries;i++) {
						MIB_IFROW Row=m_pTable->table[i];

						char szDescr[MAXLEN_IFDESCR];

						memcpy(szDescr,Row.bDescr,Row.dwDescrLen);

						szDescr[Row.dwDescrLen]=0;

						ret = ret + "Value" + util::IntToString(i) + ": " + szDescr + "\r\n";
					}
				} else {
					ret = ret + "Result: ";

					for (UINT i=0;i<m_pTable->dwNumEntries;i++) {
						MIB_IFROW Row=m_pTable->table[i];

						char szDescr[MAXLEN_IFDESCR];

						memcpy(szDescr,Row.bDescr,Row.dwDescrLen);

						szDescr[Row.dwDescrLen]=0;

						ret = ret + util::IntToString(i) + ": " + szDescr + "\\n";
					}
					ret = ret + "\r\n";
				}
				ret = ret + "Charset: " + MyUnit.showSAORICHAR() + "\r\n";
				ret = ret + "\r\n";
			} else {
				ret = MyUnit.showSAORIVER()+ " 500 Internal Server Error\r\n";
				ret = ret + "Result: NG\r\n";
				ret = ret + "Value0: Error. RetCode=" + util::IntToString(uRetCode) + "\r\n";
				ret = ret + "Charset: " + MyUnit.showSAORICHAR() + "\r\n";
				ret = ret + "\r\n";
			}
		} else {
			ret = MyUnit.showSAORIVER()+ " 500 Internal Server Error\r\n";
			ret = ret + "Result: NG\r\n";
			ret = ret + "Value0: Error loading Iphlpapi.dll\r\n";
			ret = ret + "Charset: " + MyUnit.showSAORICHAR() + "\r\n";
			ret = ret + "\r\n";
		}
	} else if (MyUnit.showSAORIARG(0) == "UpDownSpeed") {
		if (MyUnit.showSAORIARG(1) != "No Argument Found") {
			int nIndex = atoi(MyUnit.showSAORIARG(1).c_str());
			int nFactor = atoi(MyUnit.showSAORIARG(2).c_str());

			if (1 > nFactor)
				nFactor = 1;
			else if (20 < nFactor)
				nFactor = 20;

			ULONG uRetCode=pGetIfTable(m_pTable,&m_dwAdapters,TRUE);

			if (uRetCode == 0 || uRetCode == 122 /* The data area passed to a system call is too small.*/) {
				if (uRetCode == 122) {
					// now we know how much memory allocate
					m_pTable=new MIB_IFTABLE[m_dwAdapters];
					pGetIfTable(m_pTable,&m_dwAdapters,TRUE);
				}

				if (nIndex < 0) {
					odwInOctets = odwOutOctets = 0;
					for (UINT i=0;i<m_pTable->dwNumEntries;i++) {
						MIB_IFROW Row=m_pTable->table[i];
						odwInOctets += Row.dwInOctets;
						odwOutOctets += Row.dwOutOctets;
					}
				} else {
					MIB_IFROW Row=m_pTable->table[nIndex];
					odwInOctets = Row.dwInOctets;
					odwOutOctets = Row.dwOutOctets;
				}

				Sleep((1000 / nFactor));
				pGetIfTable(m_pTable,&m_dwAdapters,TRUE);

				if (nIndex < 0) {
					DWORD ndwInOctets = 0, ndwOutOctets = 0;
					for (UINT i=0;i<m_pTable->dwNumEntries;i++) {
						MIB_IFROW Row=m_pTable->table[i];
						ndwInOctets += Row.dwInOctets;
						ndwOutOctets += Row.dwOutOctets;
					}
					odwInOctets = (ndwInOctets - odwInOctets) * nFactor;
					odwOutOctets = (ndwOutOctets - odwOutOctets) * nFactor;
				} else {
					MIB_IFROW Row=m_pTable->table[nIndex];
					odwInOctets = (Row.dwInOctets - odwInOctets) * nFactor;
					odwOutOctets = (Row.dwOutOctets - odwOutOctets) * nFactor;
				}

				ret = MyUnit.showSAORIVER() + " 200 OK\r\n";
				if(!atoi(MyUnit.showSAORIARG(3).c_str())) {
					ret = ret + "Result: OK\r\n";
					ret = ret + "Value0: " + util::IntToString(odwInOctets) + "\r\n";
					ret = ret + "Value1: " + util::IntToString(odwOutOctets) + "\r\n";
				} else {
					ret = ret + "Result: Down: " + util::IntToString(odwInOctets) + " Bps, Up: " + util::IntToString(odwOutOctets) + " Bps\r\n";
				}
				ret = ret + "Charset: " + MyUnit.showSAORICHAR() + "\r\n";
				ret = ret + "\r\n";
			} else {
				ret = MyUnit.showSAORIVER()+ " 500 Internal Server Error\r\n";
				ret = ret + "Result: NG\r\n";
				ret = ret + "Value0: Error. RetCode=" + util::IntToString(uRetCode) + "\r\n";
				ret = ret + "Charset: " + MyUnit.showSAORICHAR() + "\r\n";
				ret = ret + "\r\n";
			}
		} else {
			ret = MyUnit.showSAORIVER()+ " 400 Bad Request\r\n";
			ret = ret + "Result: NG\r\n";
			ret = ret + "Value0: Too few arguments\r\n";
			ret = ret + "Charset: " + MyUnit.showSAORICHAR() + "\r\n";
			ret = ret + "\r\n";
		}
	} else {
		ret = MyUnit.showSAORIVER()+ " 400 Bad Request\r\n";
		ret = ret + "Result: NG\r\n";
		int cnt = 0;
		while (MyUnit.showSAORIARG(cnt) != "No Argument Found") {
			ret = ret + "Value" + MyUnit.IntToString(cnt) + ": " + MyUnit.showSAORIARG(cnt) + "\r\n";
			cnt++;
		}
		ret = ret + "Charset: " + MyUnit.showSAORICHAR() + "\r\n";
		ret = ret + "\r\n";
	}

	*len = ret.size();
	Answer = GlobalAlloc(GMEM_FIXED,*len);
	memcpy(Answer,ret.c_str(),*len);

	return (Answer);
}