diff options
author | Vlad Mironov <mironych@googlemail.com> | 2013-02-21 15:59:28 +0000 |
---|---|---|
committer | Vlad Mironov <mironych@googlemail.com> | 2013-02-21 15:59:28 +0000 |
commit | 3b4342ead0909ee9f5d515db932272f901708a3a (patch) | |
tree | 7d79f463c8b05e5c14fa8fa1fa532e6facc90047 /plugins/TrafficCounter/src/statistics.c | |
parent | df14d39c07a22130218388e7ce421710580408be (diff) |
СЃ-plus-plusification
git-svn-id: http://svn.miranda-ng.org/main/trunk@3671 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/TrafficCounter/src/statistics.c')
-rw-r--r-- | plugins/TrafficCounter/src/statistics.c | 751 |
1 files changed, 0 insertions, 751 deletions
diff --git a/plugins/TrafficCounter/src/statistics.c b/plugins/TrafficCounter/src/statistics.c deleted file mode 100644 index 03e30f2e90..0000000000 --- a/plugins/TrafficCounter/src/statistics.c +++ /dev/null @@ -1,751 +0,0 @@ -/*
-Traffic Counter plugin for Miranda IM
-Copyright 2007-2011 Mironych.
-
-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, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-*/
-/* ======================================================================================
-Здесь содержатся переменные и функции для работы со статистикой
-Автор: Mironych
-=======================================================================================*/
-
-#include "commonheaders.h"
-#include <math.h>
-
-HWND hListAccs;
-
-INT_PTR CALLBACK DlgProcOptStatistics(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- WORD i;
-
- switch (msg)
- {
- case WM_INITDIALOG:
- TranslateDialogDefault(hwndDlg);
- // Создаём ListBox c перечнем аккаунтов.
- hListAccs = CreateWindowEx(WS_EX_CLIENTEDGE,
- _T("ListBox"),
- NULL, WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP | LBS_SORT | LBS_NOINTEGRALHEIGHT | LBS_EXTENDEDSEL | LBS_NOTIFY,
- 2, 20, 246, 112,
- hwndDlg, NULL, NULL, NULL);
- SendMessage(hListAccs, WM_SETFONT, (WPARAM)(HFONT)GetStockObject(DEFAULT_GUI_FONT), 0);
- for (i = NumberOfAccounts; i--; )
- {
- // Готовим список аккаунтов
- if (ProtoList[i].tszAccountName)
- SendMessage(hListAccs, LB_ADDSTRING, 0, (LPARAM)ProtoList[i].tszAccountName);
- }
- for (i = NumberOfAccounts; i--; )
- SendMessage(hListAccs, LB_SETSEL, (WPARAM)0x01&(Stat_SelAcc>>i), (LPARAM)i);
- // Готовим список единиц измерения
- SendDlgItemMessage(hwndDlg, IDC_COMBO_UNITS, CB_INSERTSTRING, -1, (LPARAM)TranslateT("Bytes"));
- SendDlgItemMessage(hwndDlg, IDC_COMBO_UNITS, CB_INSERTSTRING, -1, (LPARAM)TranslateT("KB"));
- SendDlgItemMessage(hwndDlg, IDC_COMBO_UNITS, CB_INSERTSTRING, -1, (LPARAM)TranslateT("MB"));
- SendDlgItemMessage(hwndDlg, IDC_COMBO_UNITS, CB_INSERTSTRING, -1, (LPARAM)TranslateT("Adaptive"));
- SendDlgItemMessage(hwndDlg, IDC_COMBO_UNITS, CB_SETCURSEL, unOptions.Stat_Units, 0);
- // Готовим закладки
- {
- TCITEM tci;
- tci.mask = TCIF_TEXT;
- tci.cchTextMax = 32;
- tci.pszText = TranslateT("Hourly");
- SendDlgItemMessage(hwndDlg, IDC_TAB_STATS, TCM_INSERTITEM, 0, (LPARAM)&tci);
- tci.pszText = TranslateT("Daily");
- SendDlgItemMessage(hwndDlg, IDC_TAB_STATS, TCM_INSERTITEM, 1, (LPARAM)&tci);
- tci.pszText = TranslateT("Weekly");
- SendDlgItemMessage(hwndDlg, IDC_TAB_STATS, TCM_INSERTITEM, 2, (LPARAM)&tci);
- tci.pszText = TranslateT("Monthly");
- SendDlgItemMessage(hwndDlg, IDC_TAB_STATS, TCM_INSERTITEM, 3, (LPARAM)&tci);
- tci.pszText = TranslateT("Yearly");
- SendDlgItemMessage(hwndDlg, IDC_TAB_STATS, TCM_INSERTITEM, 4, (LPARAM)&tci);
- SendDlgItemMessage(hwndDlg, IDC_TAB_STATS, TCM_SETCURSEL, unOptions.Stat_Tab, 0);
- }
- // Готовим ListView - колонки и стили
- {
- LVCOLUMN lvc ={0};
-
- SendDlgItemMessage(hwndDlg, IDC_LIST_DATA, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
-#ifdef UNICODE
- SendDlgItemMessage(hwndDlg, IDC_LIST_DATA, LVM_SETUNICODEFORMAT, 1, 0);
-#else
- SendDlgItemMessage(hwndDlg, IDC_LIST_DATA, LVM_SETUNICODEFORMAT, 0, 0);
-#endif
-
- lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
- lvc.fmt = LVCFMT_LEFT;
- lvc.cchTextMax = 32;
- lvc.pszText = TranslateT("Period");
- lvc.cx = 135;
- lvc.iSubItem = 0;
- SendDlgItemMessage(hwndDlg, IDC_LIST_DATA, LVM_INSERTCOLUMN, 0, (LPARAM)&lvc);
- lvc.fmt = LVCFMT_RIGHT;
- lvc.pszText = TranslateT("Incoming");
- lvc.iSubItem = 1;
- lvc.cx = 72;
- SendDlgItemMessage(hwndDlg, IDC_LIST_DATA, LVM_INSERTCOLUMN, 1, (LPARAM)&lvc);
- lvc.pszText = TranslateT("Outgoing");
- lvc.iSubItem = 2;
- lvc.cx = 72;
- SendDlgItemMessage(hwndDlg, IDC_LIST_DATA, LVM_INSERTCOLUMN, 2, (LPARAM)&lvc);
- lvc.pszText = TranslateT("Sum");
- lvc.iSubItem = 3;
- lvc.cx = 72;
- SendDlgItemMessage(hwndDlg, IDC_LIST_DATA, LVM_INSERTCOLUMN, 3, (LPARAM)&lvc);
- lvc.pszText = TranslateT("Online");
- lvc.iSubItem = 4;
- lvc.cx = 72;
- SendDlgItemMessage(hwndDlg, IDC_LIST_DATA, LVM_INSERTCOLUMN, 4, (LPARAM)&lvc);
- }
- Stat_Show(hwndDlg);
- break; // WM_INITDIALOG
- case WM_COMMAND:
- if ((HWND)lParam == hListAccs)
- {
- DWORD SelItems[16];
- BYTE SelItemsCount;
- if (HIWORD(wParam) == LBN_SELCHANGE)
- {
- SelItemsCount = SendMessage(hListAccs, LB_GETSELCOUNT, 0, 0);
- SendMessage(hListAccs,
- LB_GETSELITEMS,
- SelItemsCount,
- (LPARAM)SelItems);
- for (Stat_SelAcc = i = 0; i < SelItemsCount; i++)
- Stat_SelAcc |= 1 << SelItems[i];
- Stat_Show(hwndDlg);
- }
- }
- switch (LOWORD(wParam))
- {
- case IDC_COMBO_UNITS:
- if (HIWORD(wParam) != CBN_SELCHANGE) break;
- unOptions.Stat_Units = SendDlgItemMessage(hwndDlg, IDC_COMBO_UNITS, CB_GETCURSEL, 0, 0);
- Stat_Show(hwndDlg);
- break;
- case IDC_BUTTON_CLEAR:
- {
- SYSTEMTIME stNow;
-
- if (IDOK != MessageBox(hwndDlg,
- TranslateT("Now traffic statistics for selected accounts will be cleared.\nContinue?"),
- TranslateT("Traffic counter"),
- MB_OKCANCEL | MB_ICONWARNING))
- break;
- GetLocalTime(&stNow);
- for (i = NumberOfAccounts; i--;)
- if (0x01&(Stat_SelAcc>>i))
- {
- SetFilePointer(ProtoList[i].hFile, sizeof(HOURLYSTATS), NULL, FILE_BEGIN);
- SetEndOfFile(ProtoList[i].hFile); // Усекаем файл до одной записи.
- ProtoList[i].NumberOfRecords = 1;
- ProtoList[i].AllStatistics = (HOURLYSTATS*)mir_realloc(ProtoList[i].AllStatistics, sizeof(HOURLYSTATS));
- ProtoList[i].AllStatistics[0].Hour = stNow.wHour;
- ProtoList[i].AllStatistics[0].Day = stNow.wDay;
- ProtoList[i].AllStatistics[0].Month = stNow.wMonth;
- ProtoList[i].AllStatistics[0].Year = stNow.wYear;
- ProtoList[i].AllStatistics[0].Incoming = 0;
- ProtoList[i].AllStatistics[0].Outgoing = 0;
- ProtoList[i].StartIncoming = 0;
- ProtoList[i].StartOutgoing = 0;
- ProtoList[i].AllStatistics[0].Time = 0;
- ProtoList[i].Total.TimeAtStart = GetTickCount();
- Stat_CheckStatistics(i);
- }
- Stat_Show(hwndDlg);
- }
- break;
- }
- break; // WM_COMMAND
- case WM_NOTIFY:
- {
- LPNMHDR lpnmhdr = (LPNMHDR)lParam;
-
- switch(lpnmhdr->idFrom)
- {
- case IDC_TAB_STATS:
- if (lpnmhdr->code != TCN_SELCHANGE) break;
- unOptions.Stat_Tab = SendDlgItemMessage(hwndDlg, IDC_TAB_STATS, TCM_GETCURSEL, 0, 0);
- Stat_Show(hwndDlg);
- break;
- case IDC_LIST_DATA:
- switch (lpnmhdr->code)
- {
- case LVN_GETDISPINFO:
- {
- NMLVDISPINFO* pdi = (NMLVDISPINFO*)lParam;
- SYSTEMTIME st = {0};
- DWORD Index, Value;
- double vartime;
- TCHAR szBufW[64];
- BYTE EldestAcc;
-
- if (!(pdi->item.mask & LVIF_TEXT)) return 0;
-
- // Если нужна надпись.
- if (!pdi->item.iSubItem)
- {
- EldestAcc = Stat_GetEldestAcc(Stat_SelAcc);
- // Индекс применим только для самого старого аккаунта!
- Index = Stat_GetStartIndex(EldestAcc, unOptions.Stat_Tab, pdi->item.iItem, &st);
- switch (unOptions.Stat_Tab)
- {
- case 0: // Hourly
- GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, szBufW, 32);
- mir_sntprintf(pdi->item.pszText, 32, _T("%s %02d:00 - %02d:59"),
- szBufW,
- ProtoList[EldestAcc].AllStatistics[Index].Hour,
- ProtoList[EldestAcc].AllStatistics[Index].Hour);
- break;
- case 1: // Dayly
- GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, pdi->item.pszText, 32);
- break;
- case 2: // Weekly
- // Уходим к первому понедельнику слева.
- SystemTimeToVariantTime(&st, &vartime);
- vartime -= DayOfWeek(st.wDay, st.wMonth, st.wYear) - 1;
- VariantTimeToSystemTime(vartime, &st);
- GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, pdi->item.pszText, 32);
- // Теперь к воскресенью.
- SystemTimeToVariantTime(&st, &vartime);
- vartime += 6;
- VariantTimeToSystemTime(vartime, &st);
- GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, szBufW, 32);
- mir_sntprintf(pdi->item.pszText, 32, _T("%s - %s"), pdi->item.pszText, szBufW);
- break;
- case 3: // Monthly
- GetDateFormat(LOCALE_USER_DEFAULT, DATE_YEARMONTH, &st, NULL, pdi->item.pszText, 32);
- break;
- case 4: // Yearly
- mir_sntprintf(pdi->item.pszText, 32, _T("%d"), st.wYear);
- break;
- }
- return 0;
- }
-
- Value = Stat_GetItemValue(Stat_SelAcc, unOptions.Stat_Tab, pdi->item.iItem, pdi->item.iSubItem);
-
- // Теперь можно записать в ListView циферки.
- switch (pdi->item.iSubItem)
- {
- case 1: // Входящий
- case 2: // Исходящий
- case 3: // Сумма
- GetFormattedTraffic(Value, unOptions.Stat_Units, pdi->item.pszText, 32);
- break;
- case 4: // Время
- {
- TCHAR *Fmt[5] = {_T("m:ss"), _T("h:mm:ss"), _T("h:mm:ss"), _T("d hh:mm:ss"), _T("d hh:mm:ss")};
- GetDurationFormatM(Value, Fmt[unOptions.Stat_Tab], pdi->item.pszText, 32);
- }
- break;
- }
- }
- break;
-
- case NM_CLICK:
- case LVN_ITEMCHANGED:
- {
- DWORD i, j = -1, dwTotalIncoming = 0, dwTotalOutgoing = 0;
-
- i = SendDlgItemMessage(hwndDlg, IDC_LIST_DATA, LVM_GETSELECTEDCOUNT, 0, 0);
- for ( ; i--;)
- {
- j = SendDlgItemMessage(hwndDlg, IDC_LIST_DATA, LVM_GETNEXTITEM, j, LVNI_SELECTED);
- dwTotalIncoming += Stat_GetItemValue(Stat_SelAcc, unOptions.Stat_Tab, j, 1);
- dwTotalOutgoing += Stat_GetItemValue(Stat_SelAcc, unOptions.Stat_Tab, j, 2);
- }
- Stat_UpdateTotalTraffic(hwndDlg, dwTotalIncoming, dwTotalOutgoing);
- }
- break;
-
- case NM_CUSTOMDRAW:
- {
- LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)lParam;
-
- switch (lplvcd->nmcd.dwDrawStage)
- {
- case CDDS_PREPAINT: // Перед началом рисования всего ListView.
- SetWindowLong(hwndDlg, DWLP_MSGRESULT, CDRF_NOTIFYITEMDRAW);
- return TRUE;
- case CDDS_ITEMPREPAINT: // Перед началом рисования строки.
- {
- COLORREF Color;
- BYTE r, g, b;
-
- if (lplvcd->nmcd.dwItemSpec & 0x01)
- {
- Color = SendDlgItemMessage(hwndDlg, IDC_LIST_DATA, LVM_GETBKCOLOR, 0, 0);
- r = GetRValue(Color);
- g = GetGValue(Color);
- b = GetBValue(Color);
- r += r > 0x80 ? -40 : 40;
- g += g > 0x80 ? -40 : 40;
- b += b > 0x80 ? -40 : 40;
- lplvcd->clrTextBk = RGB(r, g, b);;
- }
- SetWindowLong(hwndDlg, DWLP_MSGRESULT, CDRF_NEWFONT);
- return TRUE;
- }
- }
- }
- break;
- }
- break;
- }
- }
- break; // WM_NOTIFY
- }
- return 0;
-}
-
-/*
-Функция читает статистику из файла для аккаунта с номером n.
-*/
-void Stat_ReadFile(BYTE n)
-{
- LARGE_INTEGER Size;
- DWORD BytesRead;
- TCHAR FileName[MAX_PATH], *pszPath;
- SYSTEMTIME stNow, stLast = {0};
-
- pszPath = Utils_ReplaceVarsT(_T("%miranda_userdata%\\statistics"));
- CallService(MS_UTILS_CREATEDIRTREET, 0, (LPARAM)pszPath);
- mir_sntprintf(FileName, MAX_PATH, _T("%s\\%S.stat"), pszPath, ProtoList[n].name);
- mir_free(pszPath);
- GetLocalTime(&stNow);
- ProtoList[n].hFile = CreateFile(FileName, GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
- GetFileSizeEx(ProtoList[n].hFile, &Size);
- if (Size.QuadPart != 0) // Если файл со статистикой существует и имеет ненулевой размер...
- {
- // ...то читаем статистику из файла
- ProtoList[n].NumberOfRecords = Size.QuadPart/sizeof(HOURLYSTATS);
- ProtoList[n].AllStatistics = (HOURLYSTATS*)mir_alloc(sizeof(HOURLYSTATS)*ProtoList[n].NumberOfRecords);
- ReadFile(ProtoList[n].hFile, &ProtoList[n].AllStatistics[0], sizeof(HOURLYSTATS)*ProtoList[n].NumberOfRecords, &BytesRead, NULL);
- if (!BytesRead)
- {
- MessageBox(TrafficHwnd, TranslateT("Couldn't read statistics file"), TranslateT("Traffic Counter"), MB_OK);
- return;
- }
- }
- else
- {
- // Необходимо создать новый файл.
- ProtoList[n].NumberOfRecords = 1;
- ProtoList[n].AllStatistics = (HOURLYSTATS*)mir_alloc(sizeof(HOURLYSTATS));
- ProtoList[n].AllStatistics[0].Hour = stNow.wHour;
- ProtoList[n].AllStatistics[0].Day = stNow.wDay;
- ProtoList[n].AllStatistics[0].Month = stNow.wMonth;
- ProtoList[n].AllStatistics[0].Year = stNow.wYear;
- ProtoList[n].AllStatistics[0].Incoming =
- ProtoList[n].AllStatistics[0].Outgoing =
- ProtoList[n].AllStatistics[0].Time = 0;
- }
- Stat_CheckStatistics(n);
-}
-
-/* Функция готовит вывод в ListView статистики.
-Аргументы: hwndDialog - хэндл окна диалога. */
-void Stat_Show(HWND hwndDialog)
-{
- DWORD MaxRecords;
-
- // Нужно узнать количество записей.
- MaxRecords = Stat_GetRecordsNumber(Stat_GetEldestAcc(Stat_SelAcc), unOptions.Stat_Tab);
- // Установим такое же количество строк в ListView.
- SendDlgItemMessage(hwndDialog, IDC_LIST_DATA, LVM_SETITEMCOUNT, MaxRecords, 0);
- // Надо показать самые свежие записи.
- SendDlgItemMessage(hwndDialog, IDC_LIST_DATA, LVM_ENSUREVISIBLE, (WPARAM)(MaxRecords - 1), 0);
-}
-
-void Stat_UpdateTotalTraffic(HWND hwndDialog, DWORD Incoming, DWORD Outgoing)
-{
- TCHAR tmp[32];
-
- GetFormattedTraffic(Incoming, unOptions.Stat_Units, tmp, 32);
- SetDlgItemText(hwndDialog, IDC_STATIC_DNL, tmp);
- GetFormattedTraffic(Outgoing, unOptions.Stat_Units, tmp, 32);
- SetDlgItemText(hwndDialog, IDC_STATIC_UPL, tmp);
- GetFormattedTraffic(Incoming + Outgoing, unOptions.Stat_Units, tmp, 32);
- SetDlgItemText(hwndDialog, IDC_STATIC_SUMM, tmp);
-}
-
-/*
-Функция сравнивает с текущим время последней записи в статистике для аккаунта с номером n.
-Если они совпадают, ничего не происходит.
-Если текущее время меньше времени последней записи (часы перевели назад),
- количество записей уменьшается на соответствующее количество часов.
-Если текущее время больше, в статистику включается необходимое количество пустых записей.
-*/
-void Stat_CheckStatistics(BYTE n)
-{
- SYSTEMTIME stNow, stLast = {0};
- HOURLYSTATS htTmp = {0};
- signed short int d;//, i;
- DWORD q;
-
- stLast.wHour = ProtoList[n].AllStatistics[ProtoList[n].NumberOfRecords-1].Hour;
- stLast.wDay = ProtoList[n].AllStatistics[ProtoList[n].NumberOfRecords-1].Day;
- stLast.wMonth = ProtoList[n].AllStatistics[ProtoList[n].NumberOfRecords-1].Month;
- stLast.wYear = ProtoList[n].AllStatistics[ProtoList[n].NumberOfRecords-1].Year;
-
- GetLocalTime(&stNow);
- d = TimeCompare(stNow, stLast);
- // Если текущее время совпадает со временем последней записи...
- if (!d)
- {
- // ...сохраняем запись в файл и уходим.
- SetFilePointer(ProtoList[n].hFile, 0-sizeof(HOURLYSTATS), NULL, FILE_END);
- WriteFile(ProtoList[n].hFile, &ProtoList[n].AllStatistics[ProtoList[n].NumberOfRecords-1], sizeof(HOURLYSTATS), &q, NULL);
- return;
- }
-
- // Если часы перевели назад.
- if (d < 0)
- {
- do
- {
- stLast.wHour--;
- if (stLast.wHour == 0xFFFF)
- {
- stLast.wDay--;
- if (!stLast.wDay)
- {
- stLast.wMonth--;
- if (!stLast.wMonth)
- {
- stLast.wMonth = 12;
- stLast.wYear--;
- }
- stLast.wDay = DaysInMonth(htTmp.Month, htTmp.Year);
- }
- }
-
- ProtoList[n].NumberOfRecords--;
- } while (TimeCompare(stNow, stLast));
- return;
- }
-
- if (d > 0)
- {
- // Сохраняем.
- SetFilePointer(ProtoList[n].hFile, 0-sizeof(HOURLYSTATS), NULL, FILE_END);
- WriteFile(ProtoList[n].hFile, &ProtoList[n].AllStatistics[ProtoList[n].NumberOfRecords-1], sizeof(HOURLYSTATS), &q, NULL);
-
- // Последняя запись из статистики понадобится для вычисления новых записей, поэтому копируем её (кроме трафика и времени).
- memcpy(&htTmp, &ProtoList[n].AllStatistics[ProtoList[n].NumberOfRecords - 1],
- sizeof(HOURLYSTATS) - 2 * sizeof(DWORD) - sizeof(WORD));
- // Счётчик времени каждый час должен начинать считать с нуля.
- ProtoList[n].Total.TimeAtStart = GetTickCount() - stNow.wMilliseconds;
-
- do
- {
- ProtoList[n].AllStatistics =
- (HOURLYSTATS*)mir_realloc(ProtoList[n].AllStatistics, sizeof(HOURLYSTATS) * ++ProtoList[n].NumberOfRecords);
-
- htTmp.Hour++;
- if (htTmp.Hour > 23)
- {
- htTmp.Hour = 0; htTmp.Day++;
- if (htTmp.Day > DaysInMonth(htTmp.Month, htTmp.Year))
- {
- htTmp.Day = 1; htTmp.Month++;
- if (htTmp.Month > 12)
- {
- htTmp.Month = 1; htTmp.Year++;
- }
- }
- }
-
- stLast.wHour = htTmp.Hour;
- stLast.wDay = htTmp.Day;
- stLast.wMonth = htTmp.Month;
- stLast.wYear = htTmp.Year;
-
- // Добавляем записи одновременно в ОЗУ и в файл.
- WriteFile(ProtoList[n].hFile, &htTmp, sizeof(HOURLYSTATS), &q, NULL);
- memcpy(&ProtoList[n].AllStatistics[ProtoList[n].NumberOfRecords - 1], &htTmp, sizeof(HOURLYSTATS));
-
- } while (TimeCompare(stNow, stLast));
- }
-}
-
-/* Функция возращает индекс первой записи в статистике, относящейся к выбранному интервалу.
-При вычислении учитывается выбранный интервал и аккаунты.
-Аргументы:
-ItemNumber - номер строки в ListView (номер периода).
-stReq - дата, соответствующая вычисленному индексу.
-*/
-DWORD Stat_GetStartIndex(BYTE AccNum, BYTE Interval, DWORD ItemNumber, SYSTEMTIME *stReq)
-{
- DWORD Left, Right, Probe; // Границы интервала для поиска (индексы статистики).
- SYSTEMTIME stProbe = {0}; // Время тыка.
- signed short int d = 1;
-
- if (!ItemNumber)
- {
- stReq->wHour = ProtoList[AccNum].AllStatistics[0].Hour;
- stReq->wDay = ProtoList[AccNum].AllStatistics[0].Day;
- stReq->wMonth = ProtoList[AccNum].AllStatistics[0].Month;
- stReq->wYear = ProtoList[AccNum].AllStatistics[0].Year;
- return 0;
- }
-
- // Вычисляем время, соответствующее началу интервала.
- for (Probe = 0, Left = 1; Left < ProtoList[AccNum].NumberOfRecords; Left++)
- {
- switch(Interval)
- {
- case STAT_INTERVAL_HOUR:
- stReq->wHour = ProtoList[AccNum].AllStatistics[ItemNumber].Hour;
- stReq->wDay = ProtoList[AccNum].AllStatistics[ItemNumber].Day;
- stReq->wMonth = ProtoList[AccNum].AllStatistics[ItemNumber].Month;
- stReq->wYear = ProtoList[AccNum].AllStatistics[ItemNumber].Year;
- return ItemNumber;
- break;
- case STAT_INTERVAL_DAY:
- if (ProtoList[AccNum].AllStatistics[Left].Day != ProtoList[AccNum].AllStatistics[Left - 1].Day)
- Probe++;
- break;
- case STAT_INTERVAL_WEEK:
- if ( !ProtoList[AccNum].AllStatistics[Left].Hour
- && DayOfWeek(ProtoList[AccNum].AllStatistics[Left].Day,
- ProtoList[AccNum].AllStatistics[Left].Month,
- ProtoList[AccNum].AllStatistics[Left].Year) == 1)
- Probe++;
- break;
- case STAT_INTERVAL_MONTH:
- if (ProtoList[AccNum].AllStatistics[Left].Month != ProtoList[AccNum].AllStatistics[Left - 1].Month)
- Probe++;
- break;
- case STAT_INTERVAL_YEAR:
- if (ProtoList[AccNum].AllStatistics[Left].Year != ProtoList[AccNum].AllStatistics[Left - 1].Year)
- Probe++;
- break;
- }
- if (Probe == ItemNumber) break;
- }
-
- stReq->wHour = ProtoList[AccNum].AllStatistics[Left].Hour;
- stReq->wDay = ProtoList[AccNum].AllStatistics[Left].Day;
- stReq->wMonth = ProtoList[AccNum].AllStatistics[Left].Month;
- stReq->wYear = ProtoList[AccNum].AllStatistics[Left].Year;
-
- Left = 0; Right = ProtoList[AccNum].NumberOfRecords - 1;
-
- // Вычисляем индекс начала интервала.
- while (TRUE)
- {
- if (Right - Left == 1) return Right;
- Probe = (Left + Right) >> 1;
- stProbe.wYear = ProtoList[AccNum].AllStatistics[Probe].Year;
- stProbe.wMonth = ProtoList[AccNum].AllStatistics[Probe].Month;
- stProbe.wDay = ProtoList[AccNum].AllStatistics[Probe].Day;
- stProbe.wHour = ProtoList[AccNum].AllStatistics[Probe].Hour;
- d = TimeCompare(*stReq, stProbe);
- if (!d) break;
- if (d < 0) Right = Probe;
- if (d > 0) Left = Probe;
- }
- return Probe;
-}
-
-/* Функция устанавливает величину сдвига для заданного аккаунта,
-то есть номер записи в статистике старейшего из выбранных аккаунтов,
-дата которой соответствует началу статистики указанного аккаунта. */
-void Stat_SetAccShift(BYTE AccNum, BYTE EldestAccount)
-{
- DWORD Left, Right, Probe; // Границы интервала для поиска (индексы статистики).
- SYSTEMTIME stReq = {0}, stProbe;
- signed short int d = 1;
-
- if (AccNum == EldestAccount)
- {
- ProtoList[AccNum].Shift = 0;
- return;
- }
-
- stReq.wHour = ProtoList[AccNum].AllStatistics[0].Hour;
- stReq.wDay = ProtoList[AccNum].AllStatistics[0].Day;
- stReq.wMonth = ProtoList[AccNum].AllStatistics[0].Month;
- stReq.wYear = ProtoList[AccNum].AllStatistics[0].Year;
-
- // Вычисляем индекс начала интервала.
- Left = 0; Right = ProtoList[EldestAccount].NumberOfRecords - 1;
- while (TRUE)
- {
- if (Right - Left == 1)
- {
- ProtoList[AccNum].Shift = Probe + d;
- return;
- }
- Probe = (Left + Right) >> 1;
- stProbe.wYear = ProtoList[EldestAccount].AllStatistics[Probe].Year;
- stProbe.wMonth = ProtoList[EldestAccount].AllStatistics[Probe].Month;
- stProbe.wDay = ProtoList[EldestAccount].AllStatistics[Probe].Day;
- stProbe.wHour = ProtoList[EldestAccount].AllStatistics[Probe].Hour;
- d = TimeCompare(stReq, stProbe);
- if (!d) break;
- if (d < 0) Right = Probe;
- if (d > 0) Left = Probe;
- }
- ProtoList[AccNum].Shift = Probe;
-}
-
-/* Функция вычисляет значение, соответствующее указанному подэлементу
-указанной строки ListView.
-Аргументы:
-SelectedAccs - слово, в котором единичные биты соответствуют выбранным аккаунтам;
-Interval - выбранный интервал;
-ItemNum - номер строки в ListVew;
-SubitemNum - номер колонки, определяет вид информации. */
-DWORD Stat_GetItemValue(WORD SelectedAccs, BYTE Interval, DWORD ItemNum, BYTE SubItemNum)
-{
- DWORD Result = 0;
- SYSTEMTIME st = {0};
- DWORD Index, IndexP, i;
- signed long int IndexM;
- BYTE a, EldestAcc;
-
- EldestAcc = Stat_GetEldestAcc(SelectedAccs);
- Index = Stat_GetStartIndex(EldestAcc, Interval, ItemNum, &st);
-
- for (a = NumberOfAccounts; a--; )
- {
- if (!((1 << a) & SelectedAccs)) continue;
- Stat_SetAccShift(a, EldestAcc);
- IndexM = Index - ProtoList[a].Shift;
- IndexP = Index;
-
- for (i = 0; ; )
- {
- if (IndexM >= 0)
- switch (SubItemNum)
- {
- case 1: // Входящий
- Result += ProtoList[a].AllStatistics[IndexM].Incoming;
- break;
- case 2: // Исходящий
- Result += ProtoList[a].AllStatistics[IndexM].Outgoing;
- break;
- case 3: // Сумма
- Result += ProtoList[a].AllStatistics[IndexM].Incoming
- + ProtoList[a].AllStatistics[IndexM].Outgoing;
- break;
- case 4: // Время
- Result += ProtoList[a].AllStatistics[IndexM].Time;
- break;
- }
-
- IndexM++; IndexP++; // Переходим к следующей записи.
- if (IndexM == ProtoList[a].NumberOfRecords) break;
-
- // Когда остановиться?
- switch (Interval)
- {
- case STAT_INTERVAL_HOUR:
- i = 1; // Новый час начинается каждый час.
- break;
- case STAT_INTERVAL_DAY:
- i = (0 == ProtoList[EldestAcc].AllStatistics[IndexP].Hour);
- break;
- case STAT_INTERVAL_WEEK:
- i = (1 == DayOfWeek(ProtoList[EldestAcc].AllStatistics[IndexP].Day,
- ProtoList[EldestAcc].AllStatistics[IndexP].Month,
- ProtoList[EldestAcc].AllStatistics[IndexP].Year))
- && (0 == ProtoList[EldestAcc].AllStatistics[IndexP].Hour);
- break;
- case STAT_INTERVAL_MONTH:
- i = (1 == ProtoList[EldestAcc].AllStatistics[IndexP].Day)
- && (0 == ProtoList[EldestAcc].AllStatistics[IndexP].Hour);
- break;
- case STAT_INTERVAL_YEAR:
- i = (1 == ProtoList[EldestAcc].AllStatistics[IndexP].Month)
- && (1 == ProtoList[EldestAcc].AllStatistics[IndexP].Day)
- && (0 == ProtoList[EldestAcc].AllStatistics[IndexP].Hour);
- break;
- }
-
- if (i) break;
- }
- }
-
- return Result;
-}
-
-/* Функция возвращает количество записей в статистике для
-заданного аккаунта и заданного интервала. */
-DWORD Stat_GetRecordsNumber(BYTE AccNum, BYTE Interval)
-{
- DWORD Result, i;
-
- // Нужно узнать количество записей.
- switch (Interval)
- {
- case STAT_INTERVAL_HOUR:
- Result = ProtoList[AccNum].NumberOfRecords; // Для почасовой статистики совпадает.
- break;
- case STAT_INTERVAL_DAY:
- for (Result = 1, i = ProtoList[AccNum].NumberOfRecords - 1; i--; )
- if (ProtoList[AccNum].AllStatistics[i].Day != ProtoList[AccNum].AllStatistics[i+1].Day)
- Result++;
- break;
- case STAT_INTERVAL_WEEK:
- for (Result = 1, i = ProtoList[AccNum].NumberOfRecords; i--; )
- if ( ProtoList[AccNum].AllStatistics[i].Hour == 23
- && DayOfWeek(ProtoList[AccNum].AllStatistics[i].Day,
- ProtoList[AccNum].AllStatistics[i].Month,
- ProtoList[AccNum].AllStatistics[i].Year) == 7)
- Result++;
- break;
- case STAT_INTERVAL_MONTH:
- for (Result = 1, i = ProtoList[AccNum].NumberOfRecords - 1; i--; )
- if (ProtoList[AccNum].AllStatistics[i].Month != ProtoList[AccNum].AllStatistics[i+1].Month)
- Result++;
- break;
- case STAT_INTERVAL_YEAR:
- for (Result = 1, i = ProtoList[AccNum].NumberOfRecords - 1; i--; )
- if (ProtoList[AccNum].AllStatistics[i].Year != ProtoList[AccNum].AllStatistics[i+1].Year)
- Result++;
- break;
- }
-
- return Result;
-}
-
-BYTE Stat_GetEldestAcc(WORD SelectedAccs)
-{
- BYTE Result, i;
-
- // Узнаём номер аккаунта из числа выбранных, имеющего самую старую первую запись.
- // (Это аккаунт с максимальным количеством записей.)
- for (Result = i = 0; i < NumberOfAccounts; i++)
- {
- // Надо с чего-то начать поиск.
- if ( 0x01 & (SelectedAccs >> i))
- {
- Result = i;
- break;
- }
- }
- // Продолжаем поиск.
- for (; ++i < NumberOfAccounts; )
- {
- if ( 0x01 & (SelectedAccs >> i) && (ProtoList[i].NumberOfRecords > ProtoList[Result].NumberOfRecords) )
- Result = i;
- }
-
- return Result;
-}
\ No newline at end of file |