%s: %s
", Txt_Time_zone_used_in_the_calculation_of_these_statistics, BrowserTimeZone); break; default: break; } } /*****************************************************************************/ /******************* Show a listing of detailed clicks ***********************/ /*****************************************************************************/ static void Sta_ShowDetailedAccessesList (unsigned long NumRows,MYSQL_RES *mysql_res) { extern const char *Txt_Show_previous_X_clicks; extern const char *Txt_PAGES_Previous; extern const char *Txt_Clicks; extern const char *Txt_of_PART_OF_A_TOTAL; extern const char *Txt_page; extern const char *Txt_Show_next_X_clicks; extern const char *Txt_PAGES_Next; extern const char *Txt_No_INDEX; extern const char *Txt_User_ID; extern const char *Txt_Name; extern const char *Txt_Role; extern const char *Txt_Date; extern const char *Txt_Action; extern const char *Txt_LOG_More_info; extern const char *Txt_ROLES_SINGUL_Abc[Rol_NUM_ROLES][Usr_NUM_SEXS]; extern const char *Txt_Today; unsigned long NumRow; unsigned long FirstRow; // First row to show unsigned long LastRow; // Last rows to show unsigned long NumPagesBefore; unsigned long NumPagesAfter; unsigned long NumPagsTotal; struct UsrData UsrDat; MYSQL_ROW row; long LogCod; Rol_Role_t RoleFromLog; unsigned UniqueId; long ActCod; char ActTxt[Act_MAX_BYTES_ACTION_TXT + 1]; /***** Initialize estructura of data of the user *****/ Usr_UsrDataConstructor (&UsrDat); /***** Compute the first and the last row to show *****/ FirstRow = Gbl.Stat.FirstRow; LastRow = Gbl.Stat.LastRow; if (FirstRow == 0 && LastRow == 0) // Call from main form { // Show last clicks FirstRow = (NumRows / Gbl.Stat.RowsPerPage - 1) * Gbl.Stat.RowsPerPage + 1; if ((FirstRow + Gbl.Stat.RowsPerPage - 1) < NumRows) FirstRow += Gbl.Stat.RowsPerPage; LastRow = NumRows; } if (FirstRow < 1) // For security reasons; really it should never be less than 1 FirstRow = 1; if (LastRow > NumRows) LastRow = NumRows; if ((LastRow - FirstRow) >= Gbl.Stat.RowsPerPage) // For if there have been clicks that have increased the number of rows LastRow = FirstRow + Gbl.Stat.RowsPerPage - 1; /***** Compute the number total of pages *****/ /* Number of pages before the current one */ NumPagesBefore = (FirstRow-1) / Gbl.Stat.RowsPerPage; if (NumPagesBefore * Gbl.Stat.RowsPerPage < (FirstRow-1)) NumPagesBefore++; /* Number of pages after the current one */ NumPagesAfter = (NumRows - LastRow) / Gbl.Stat.RowsPerPage; if (NumPagesAfter * Gbl.Stat.RowsPerPage < (NumRows - LastRow)) NumPagesAfter++; /* Count the total number of pages */ NumPagsTotal = NumPagesBefore + 1 + NumPagesAfter; /***** Put heading with backward and forward buttons *****/ Tbl_TR_Begin (NULL); Tbl_TD_Begin ("colspan=\"7\" class=\"LM\""); Tbl_TABLE_BeginWidePadding (2); Tbl_TR_Begin (NULL); /* Put link to jump to previous page (older clicks) */ if (FirstRow > 1) { Frm_StartFormAnchor (ActSeeAccCrs,Sta_STAT_RESULTS_SECTION_ID); Dat_WriteParamsIniEndDates (); Par_PutHiddenParamUnsigned ("GroupedBy",(unsigned) Sta_CLICKS_CRS_DETAILED_LIST); Par_PutHiddenParamUnsigned ("StatAct" ,(unsigned) Gbl.Stat.NumAction); Par_PutHiddenParamLong ("FirstRow",FirstRow - Gbl.Stat.RowsPerPage); Par_PutHiddenParamLong ("LastRow" ,FirstRow - 1); Par_PutHiddenParamLong ("RowsPage",Gbl.Stat.RowsPerPage); Usr_PutHiddenParSelectedUsrsCods (); } Tbl_TD_Begin ("class=\"LM\""); if (FirstRow > 1) { snprintf (Gbl.Title,sizeof (Gbl.Title), Txt_Show_previous_X_clicks, Gbl.Stat.RowsPerPage); Frm_LinkFormSubmit (Gbl.Title,"TIT_TBL",NULL); fprintf (Gbl.F.Out,"<%s", Txt_PAGES_Previous); } Tbl_TD_End (); if (FirstRow > 1) Frm_EndForm (); /* Write number of current page */ Tbl_TD_Begin ("class=\"DAT_N CM\""); fprintf (Gbl.F.Out,"" "%s %lu-%lu %s %lu (%s %ld %s %lu)" "", Txt_Clicks, FirstRow,LastRow,Txt_of_PART_OF_A_TOTAL,NumRows, Txt_page,NumPagesBefore + 1,Txt_of_PART_OF_A_TOTAL,NumPagsTotal); Tbl_TD_End (); /* Put link to jump to next page (more recent clicks) */ if (LastRow < NumRows) { Frm_StartFormAnchor (ActSeeAccCrs,Sta_STAT_RESULTS_SECTION_ID); Dat_WriteParamsIniEndDates (); Par_PutHiddenParamUnsigned ("GroupedBy",(unsigned) Sta_CLICKS_CRS_DETAILED_LIST); Par_PutHiddenParamUnsigned ("StatAct" ,(unsigned) Gbl.Stat.NumAction); Par_PutHiddenParamUnsigned ("FirstRow" ,(unsigned) (LastRow + 1)); Par_PutHiddenParamUnsigned ("LastRow" ,(unsigned) (LastRow + Gbl.Stat.RowsPerPage)); Par_PutHiddenParamUnsigned ("RowsPage" ,(unsigned) Gbl.Stat.RowsPerPage); Usr_PutHiddenParSelectedUsrsCods (); } Tbl_TD_Begin ("class=\"RM\""); if (LastRow < NumRows) { snprintf (Gbl.Title,sizeof (Gbl.Title), Txt_Show_next_X_clicks, Gbl.Stat.RowsPerPage); Frm_LinkFormSubmit (Gbl.Title,"TIT_TBL",NULL); fprintf (Gbl.F.Out,"%s>" "", Txt_PAGES_Next); } Tbl_TD_End (); if (LastRow < NumRows) Frm_EndForm (); Tbl_TR_End (); Tbl_TABLE_End (); Tbl_TD_End (); Tbl_TR_End (); /***** Write heading *****/ Tbl_TR_Begin (NULL); Tbl_TH (1,1,"RT",Txt_No_INDEX); Tbl_TH (1,1,"CT",Txt_User_ID); Tbl_TH (1,1,"LT",Txt_Name); Tbl_TH (1,1,"CT",Txt_Role); Tbl_TH (1,1,"CT",Txt_Date); Tbl_TH (1,1,"LT",Txt_Action); Tbl_TH (1,1,"LT",Txt_LOG_More_info); Tbl_TR_End (); /***** Write rows back *****/ for (NumRow = LastRow, UniqueId = 1, Gbl.RowEvenOdd = 0; NumRow >= FirstRow; NumRow--, UniqueId++, Gbl.RowEvenOdd = 1 - Gbl.RowEvenOdd) { mysql_data_seek (mysql_res,(my_ulonglong) (NumRow - 1)); row = mysql_fetch_row (mysql_res); /* Get log code */ LogCod = Str_ConvertStrCodToLongCod (row[0]); /* Get user's data of the database */ UsrDat.UsrCod = Str_ConvertStrCodToLongCod (row[1]); Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&UsrDat,Usr_DONT_GET_PREFS); /* Get logged role */ if (sscanf (row[2],"%u",&RoleFromLog) != 1) Rol_WrongRoleExit (); Tbl_TR_Begin (NULL); /* Write the number of row */ Tbl_TD_Begin ("class=\"LOG RT COLOR%u\"",Gbl.RowEvenOdd); fprintf (Gbl.F.Out,"%ld ",NumRow); Tbl_TD_End (); /* Write the user's ID if user is a student */ Tbl_TD_Begin ("class=\"LOG CT COLOR%u\"",Gbl.RowEvenOdd); ID_WriteUsrIDs (&UsrDat,NULL); fprintf (Gbl.F.Out," "); Tbl_TD_End (); /* Write the first name and the surnames */ Tbl_TD_Begin ("class=\"LOG LT COLOR%u\"",Gbl.RowEvenOdd); fprintf (Gbl.F.Out,"%s ",UsrDat.FullName); Tbl_TD_End (); /* Write the user's role */ Tbl_TD_Begin ("class=\"LOG CT COLOR%u\"",Gbl.RowEvenOdd); fprintf (Gbl.F.Out,"%s ", RoleFromLog < Rol_NUM_ROLES ? Txt_ROLES_SINGUL_Abc[RoleFromLog][UsrDat.Sex] : "?"); Tbl_TD_End (); /* Write the date-time (row[3]) */ Tbl_TD_Begin ("id=\"log_date_%u\" class=\"LOG RT COLOR%u\"", UniqueId,Gbl.RowEvenOdd); fprintf (Gbl.F.Out,"", UniqueId,(long) Dat_GetUNIXTimeFromStr (row[3]), (unsigned) Gbl.Prefs.DateFormat,Txt_Today); Tbl_TD_End (); /* Write the action */ if (sscanf (row[4],"%ld",&ActCod) != 1) Lay_ShowErrorAndExit ("Wrong action code."); if (ActCod >= 0) { Tbl_TD_Begin ("class=\"LOG LT COLOR%u\"",Gbl.RowEvenOdd); fprintf (Gbl.F.Out,"%s ",Act_GetActionTextFromDB (ActCod,ActTxt)); } else { Tbl_TD_Begin ("class=\"LOG LT COLOR%u\"",Gbl.RowEvenOdd); fprintf (Gbl.F.Out,"? "); } Tbl_TD_End (); /* Write the comments of the access */ Tbl_TD_Begin ("class=\"LOG LT COLOR%u\"",Gbl.RowEvenOdd); Sta_WriteLogComments (LogCod); Tbl_TD_End (); Tbl_TR_End (); } /***** Free memory used by the data of the user *****/ Usr_UsrDataDestructor (&UsrDat); } /*****************************************************************************/ /******** Show a listing of with the number of clicks of each user ***********/ /*****************************************************************************/ static void Sta_WriteLogComments (long LogCod) { MYSQL_RES *mysql_res; MYSQL_ROW row; /***** Get log comments from database *****/ if (DB_QuerySELECT (&mysql_res,"can not get log comments", "SELECT Comments FROM log_comments WHERE LogCod=%ld", LogCod)) { /***** Get and write comments *****/ row = mysql_fetch_row (mysql_res); fprintf (Gbl.F.Out,"%s",row[0]); } /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); } /*****************************************************************************/ /********* Show a listing of with the number of clicks of each user **********/ /*****************************************************************************/ static void Sta_ShowNumHitsPerUsr (unsigned long NumRows,MYSQL_RES *mysql_res) { extern const char *Txt_No_INDEX; extern const char *Txt_Photo; extern const char *Txt_ID; extern const char *Txt_Name; extern const char *Txt_Role; extern const char *Txt_STAT_TYPE_COUNT_CAPS[Sta_NUM_COUNT_TYPES]; extern const char *Txt_ROLES_SINGUL_Abc[Rol_NUM_ROLES][Usr_NUM_SEXS]; MYSQL_ROW row; unsigned long NumRow; struct Sta_Hits Hits; unsigned BarWidth; struct UsrData UsrDat; char PhotoURL[PATH_MAX + 1]; bool ShowPhoto; /***** Initialize user's data *****/ Usr_UsrDataConstructor (&UsrDat); /***** Write heading *****/ Tbl_TR_Begin (NULL); Tbl_TH (1,1,"RT",Txt_No_INDEX); Tbl_TH (1,1,"CT",Txt_Photo); Tbl_TH (1,1,"LT",Txt_ID); Tbl_TH (1,1,"LT",Txt_Name); Tbl_TH (1,1,"CT",Txt_Role); Tbl_TH (1,2,"LT",Txt_STAT_TYPE_COUNT_CAPS[Gbl.Stat.CountType]); Tbl_TR_End (); /***** Write rows *****/ for (NumRow = 1, Hits.Max = 0.0, Gbl.RowEvenOdd = 0; NumRow <= NumRows; NumRow++, Gbl.RowEvenOdd = 1 - Gbl.RowEvenOdd) { row = mysql_fetch_row (mysql_res); /* Get user's data from the database */ UsrDat.UsrCod = Str_ConvertStrCodToLongCod (row[0]); Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&UsrDat,Usr_DONT_GET_PREFS); // Get the data of the user from the database Tbl_TR_Begin (NULL); /* Write the number of row */ Tbl_TD_Begin ("class=\"LOG RT COLOR%u\"",Gbl.RowEvenOdd); fprintf (Gbl.F.Out,"%ld ",NumRow); Tbl_TD_End (); /* Show the photo */ Tbl_TD_Begin ("class=\"CT COLOR%u\"",Gbl.RowEvenOdd); ShowPhoto = Pho_ShowingUsrPhotoIsAllowed (&UsrDat,PhotoURL); Pho_ShowUsrPhoto (&UsrDat,ShowPhoto ? PhotoURL : NULL, "PHOTO15x20",Pho_ZOOM,false); Tbl_TD_End (); /* Write the user's ID if user is a student in current course */ Tbl_TD_Begin ("class=\"LOG LT COLOR%u\"",Gbl.RowEvenOdd); ID_WriteUsrIDs (&UsrDat,NULL); fprintf (Gbl.F.Out," "); Tbl_TD_End (); /* Write the name and the surnames */ Tbl_TD_Begin ("class=\"LOG LT COLOR%u\"",Gbl.RowEvenOdd); fprintf (Gbl.F.Out,"%s ",UsrDat.FullName); Tbl_TD_End (); /* Write user's role */ Tbl_TD_Begin ("class=\"LOG CT COLOR%u\"",Gbl.RowEvenOdd); fprintf (Gbl.F.Out,"%s ", Txt_ROLES_SINGUL_Abc[UsrDat.Roles.InCurrentCrs.Role][UsrDat.Sex]); Tbl_TD_End (); /* Write the number of clicks */ Hits.Num = Str_GetFloatNumFromStr (row[1]); if (NumRow == 1) Hits.Max = Hits.Num; if (Hits.Max > 0.0) { BarWidth = (unsigned) (((Hits.Num * 375.0) / Hits.Max) + 0.5); if (BarWidth == 0) BarWidth = 1; } else BarWidth = 0; Tbl_TD_Begin ("class=\"LOG LT COLOR%u\"",Gbl.RowEvenOdd); if (BarWidth) fprintf (Gbl.F.Out,"" " ", Cfg_URL_ICON_PUBLIC, UsrDat.Roles.InCurrentCrs.Role == Rol_STD ? 'o' : // Student 'r', // Non-editing teacher or teacher BarWidth); Str_WriteFloatNumToFile (Gbl.F.Out,Hits.Num); fprintf (Gbl.F.Out," "); Tbl_TD_End (); Tbl_TR_End (); } /***** Free memory used by the data of the user *****/ Usr_UsrDataDestructor (&UsrDat); } /*****************************************************************************/ /********** Show a listing of with the number of clicks in each date *********/ /*****************************************************************************/ static void Sta_ShowNumHitsPerDay (unsigned long NumRows,MYSQL_RES *mysql_res) { extern const char *Txt_Date; extern const char *Txt_Day; extern const char *Txt_STAT_TYPE_COUNT_CAPS[Sta_NUM_COUNT_TYPES]; extern const char *Txt_DAYS_SMALL[7]; unsigned long NumRow; struct Date ReadDate; struct Date LastDate; struct Date Date; unsigned D; unsigned NumDaysFromLastDateToCurrDate; int NumDayWeek; struct Sta_Hits Hits; MYSQL_ROW row; char StrDate[Cns_MAX_BYTES_DATE + 1]; /***** Initialize LastDate *****/ Dat_AssignDate (&LastDate,&Gbl.DateRange.DateEnd.Date); /***** Write heading *****/ Tbl_TR_Begin (NULL); Tbl_TH (1,1,"CT",Txt_Date); Tbl_TH (1,1,"LT",Txt_Day); Tbl_TH (1,1,"LT",Txt_STAT_TYPE_COUNT_CAPS[Gbl.Stat.CountType]); Tbl_TR_End (); /***** Compute maximum number of pages generated per day *****/ Sta_ComputeMaxAndTotalHits (&Hits,NumRows,mysql_res,1,1); /***** Write rows beginning by the most recent day and ending by the oldest *****/ mysql_data_seek (mysql_res,0); for (NumRow = 1; NumRow <= NumRows; NumRow++) { row = mysql_fetch_row (mysql_res); /* Get year, month and day (row[0] holds the date in YYYYMMDD format) */ if (!(Dat_GetDateFromYYYYMMDD (&ReadDate,row[0]))) Lay_ShowErrorAndExit ("Wrong date."); /* Get number of pages generated (in row[1]) */ Hits.Num = Str_GetFloatNumFromStr (row[1]); Dat_AssignDate (&Date,&LastDate); NumDaysFromLastDateToCurrDate = Dat_GetNumDaysBetweenDates (&ReadDate,&LastDate); /* In the next loop (NumDaysFromLastDateToCurrDate-1) días (the more recent) with 0 clicks are shown and a last day (the oldest) with Hits.Num */ for (D = 1; D <= NumDaysFromLastDateToCurrDate; D++) { NumDayWeek = Dat_GetDayOfWeek (Date.Year,Date.Month,Date.Day); Tbl_TR_Begin (NULL); /* Write the date */ Dat_ConvDateToDateStr (&Date,StrDate); Tbl_TD_Begin ("class=\"%s RT\"",NumDayWeek == 6 ? "LOG_R" : "LOG"); fprintf (Gbl.F.Out,"%s ",StrDate); Tbl_TD_End (); /* Write the day of the week */ Tbl_TD_Begin ("class=\"%s LT\"",NumDayWeek == 6 ? "LOG_R" : "LOG"); fprintf (Gbl.F.Out,"%s ",Txt_DAYS_SMALL[NumDayWeek]); Tbl_TD_End (); /* Draw bar proportional to number of hits */ Sta_DrawBarNumHits (NumDayWeek == 6 ? 'r' : // red background 'o', // orange background D == NumDaysFromLastDateToCurrDate ? Hits.Num : 0.0, Hits.Max,Hits.Total,500); Tbl_TR_End (); /* Decrease day */ Dat_GetDateBefore (&Date,&Date); } Dat_AssignDate (&LastDate,&Date); } NumDaysFromLastDateToCurrDate = Dat_GetNumDaysBetweenDates (&Gbl.DateRange.DateIni.Date,&LastDate); /***** Finally NumDaysFromLastDateToCurrDate days are shown with 0 clicks (the oldest days from the requested initial day until the first with clicks) *****/ for (D = 1; D <= NumDaysFromLastDateToCurrDate; D++) { NumDayWeek = Dat_GetDayOfWeek (Date.Year,Date.Month,Date.Day); Tbl_TR_Begin (NULL); /* Write the date */ Dat_ConvDateToDateStr (&Date,StrDate); Tbl_TD_Begin ("class=\"%s RT\"",NumDayWeek == 6 ? "LOG_R" : "LOG"); fprintf (Gbl.F.Out,"%s ",StrDate); Tbl_TD_End (); /* Write the day of the week */ Tbl_TD_Begin ("class=\"%s LT\"",NumDayWeek == 6 ? "LOG_R" : "LOG"); fprintf (Gbl.F.Out,"%s ",Txt_DAYS_SMALL[NumDayWeek]); Tbl_TD_End (); /* Draw bar proportional to number of hits */ Sta_DrawBarNumHits (NumDayWeek == 6 ? 'r' : // red background 'o', // orange background 0.0,Hits.Max,Hits.Total,500); Tbl_TR_End (); /* Decrease day */ Dat_GetDateBefore (&Date,&Date); } } /*****************************************************************************/ /************ Show graphic of number of pages generated per hour *************/ /*****************************************************************************/ #define GRAPH_DISTRIBUTION_PER_HOUR_HOUR_WIDTH 25 #define GRAPH_DISTRIBUTION_PER_HOUR_TOTAL_WIDTH (GRAPH_DISTRIBUTION_PER_HOUR_HOUR_WIDTH * 24) static void Sta_ShowDistrAccessesPerDayAndHour (unsigned long NumRows,MYSQL_RES *mysql_res) { extern const char *The_ClassFormInBox[The_NUM_THEMES]; extern const char *Txt_Color_of_the_graphic; extern const char *Txt_STAT_COLOR_TYPES[Sta_NUM_COLOR_TYPES]; extern const char *Txt_Date; extern const char *Txt_Day; extern const char *Txt_STAT_TYPE_COUNT_CAPS[Sta_NUM_COUNT_TYPES]; extern const char *Txt_DAYS_SMALL[7]; Sta_ColorType_t ColorType; Sta_ColorType_t SelectedColorType; unsigned long NumRow; struct Date PreviousReadDate; struct Date CurrentReadDate; struct Date LastDate; struct Date Date; unsigned D; unsigned NumDaysFromLastDateToCurrDate = 1; unsigned NumDayWeek; unsigned Hour; unsigned ReadHour = 0; struct Sta_Hits Hits; float NumAccPerHour[24]; float NumAccPerHourZero[24]; MYSQL_ROW row; char StrDate[Cns_MAX_BYTES_DATE + 1]; /***** Get selected color type *****/ SelectedColorType = Sta_GetStatColorType (); /***** Put a selector for the type of color *****/ Tbl_TR_Begin (NULL); Tbl_TD_Begin ("colspan=\"26\" class=\"CM\""); Frm_StartFormAnchor (Gbl.Action.Act,Sta_STAT_RESULTS_SECTION_ID); Dat_WriteParamsIniEndDates (); Par_PutHiddenParamUnsigned ("GroupedBy",(unsigned) Gbl.Stat.ClicksGroupedBy); Par_PutHiddenParamUnsigned ("CountType",(unsigned) Gbl.Stat.CountType); Par_PutHiddenParamUnsigned ("StatAct" ,(unsigned) Gbl.Stat.NumAction); if (Gbl.Action.Act == ActSeeAccCrs) Usr_PutHiddenParSelectedUsrsCods (); else // Gbl.Action.Act == ActSeeAccGbl { Par_PutHiddenParamUnsigned ("Role",(unsigned) Gbl.Stat.Role); Sta_PutHiddenParamScopeSta (); } fprintf (Gbl.F.Out,""); Frm_EndForm (); Tbl_TD_End (); Tbl_TR_End (); /***** Compute maximum number of pages generated per day-hour *****/ Sta_ComputeMaxAndTotalHits (&Hits,NumRows,mysql_res,2,1); /***** Initialize LastDate *****/ Dat_AssignDate (&LastDate,&Gbl.DateRange.DateEnd.Date); /***** Reset number of pages generated per hour *****/ for (Hour = 0; Hour < 24; Hour++) NumAccPerHour[Hour] = NumAccPerHourZero[Hour] = 0.0; /***** Write heading *****/ Tbl_TR_Begin (NULL); Tbl_TH (3,1,"CT",Txt_Date); Tbl_TH (3,1,"LT",Txt_Day); Tbl_TH (1,24,"LT",Txt_STAT_TYPE_COUNT_CAPS[Gbl.Stat.CountType]); Tbl_TR_End (); Tbl_TR_Begin (NULL); Tbl_TD_Begin ("colspan=\"24\" class=\"LT\""); Sta_DrawBarColors (SelectedColorType,Hits.Max); Tbl_TD_End (); Tbl_TR_End (); Tbl_TR_Begin (NULL); for (Hour = 0; Hour < 24; Hour++) { Tbl_TD_Begin ("class=\"LOG CT\" style=\"width:%upx;\"", GRAPH_DISTRIBUTION_PER_HOUR_HOUR_WIDTH); fprintf (Gbl.F.Out,"%02uh",Hour); Tbl_TD_End (); } Tbl_TR_End (); /***** Write rows beginning by the most recent day and ending by the oldest one *****/ mysql_data_seek (mysql_res,0); for (NumRow = 1; NumRow <= NumRows; NumRow++) { row = mysql_fetch_row (mysql_res); /* Get year, month and day (row[0] holds the date in YYYYMMDD format) */ if (!(Dat_GetDateFromYYYYMMDD (&CurrentReadDate,row[0]))) Lay_ShowErrorAndExit ("Wrong date."); /* Get the hour (in row[1] is the hour in formato HH) */ if (sscanf (row[1],"%02u",&ReadHour) != 1) Lay_ShowErrorAndExit ("Wrong hour."); /* Get number of pages generated (in row[2]) */ Hits.Num = Str_GetFloatNumFromStr (row[2]); /* If this is the first read date, initialize PreviousReadDate */ if (NumRow == 1) Dat_AssignDate (&PreviousReadDate,&CurrentReadDate); /* Update number of hits per hour */ if (PreviousReadDate.Year != CurrentReadDate.Year || PreviousReadDate.Month != CurrentReadDate.Month || PreviousReadDate.Day != CurrentReadDate.Day) // Current read date (CurrentReadDate) is older than previous read date (PreviousReadDate) */ { /* In the next loop we show (NumDaysFromLastDateToCurrDate-1) days with 0 clicks and a last day (older) with Hits.Num */ Dat_AssignDate (&Date,&LastDate); NumDaysFromLastDateToCurrDate = Dat_GetNumDaysBetweenDates (&PreviousReadDate,&LastDate); for (D = 1; D <= NumDaysFromLastDateToCurrDate; D++) { NumDayWeek = Dat_GetDayOfWeek (Date.Year,Date.Month,Date.Day); Tbl_TR_Begin (NULL); /* Write the date */ Dat_ConvDateToDateStr (&Date,StrDate); Tbl_TD_Begin ("class=\"%s RT\"",NumDayWeek == 6 ? "LOG_R" : "LOG"); fprintf (Gbl.F.Out,"%s ",StrDate); Tbl_TD_End (); /* Write the day of the week */ Tbl_TD_Begin ("class=\"%s LT\"",NumDayWeek == 6 ? "LOG_R" : "LOG"); fprintf (Gbl.F.Out,"%s ",Txt_DAYS_SMALL[NumDayWeek]); Tbl_TD_End (); /* Draw a cell with the color proportional to the number of clicks */ if (D == NumDaysFromLastDateToCurrDate) Sta_DrawAccessesPerHourForADay (SelectedColorType,NumAccPerHour,Hits.Max); else // D < NumDaysFromLastDateToCurrDate Sta_DrawAccessesPerHourForADay (SelectedColorType,NumAccPerHourZero,Hits.Max); Tbl_TR_End (); /* Decrease day */ Dat_GetDateBefore (&Date,&Date); } Dat_AssignDate (&LastDate,&Date); Dat_AssignDate (&PreviousReadDate,&CurrentReadDate); /* Reset number of pages generated per hour */ for (Hour = 0; Hour < 24; Hour++) NumAccPerHour[Hour] = 0.0; } NumAccPerHour[ReadHour] = Hits.Num; } /***** Show the clicks of the oldest day with clicks *****/ /* In the next loop we show (NumDaysFromLastDateToCurrDate-1) days (more recent) with 0 clicks and a last day (older) with Hits.Num clicks */ Dat_AssignDate (&Date,&LastDate); NumDaysFromLastDateToCurrDate = Dat_GetNumDaysBetweenDates (&PreviousReadDate,&LastDate); for (D = 1; D <= NumDaysFromLastDateToCurrDate; D++) { NumDayWeek = Dat_GetDayOfWeek (Date.Year,Date.Month,Date.Day); Tbl_TR_Begin (NULL); /* Write the date */ Dat_ConvDateToDateStr (&Date,StrDate); Tbl_TD_Begin ("class=\"%s RT\"",NumDayWeek == 6 ? "LOG_R" : "LOG"); fprintf (Gbl.F.Out,"%s ",StrDate); Tbl_TD_End (); /* Write the day of the week */ Tbl_TD_Begin ("class=\"%s LT\"",NumDayWeek == 6 ? "LOG_R" : "LOG"); fprintf (Gbl.F.Out,"%s ",Txt_DAYS_SMALL[NumDayWeek]); Tbl_TD_End (); /* Draw the color proporcional al number of clicks */ if (D == NumDaysFromLastDateToCurrDate) Sta_DrawAccessesPerHourForADay (SelectedColorType,NumAccPerHour,Hits.Max); else // D < NumDaysFromLastDateToCurrDate Sta_DrawAccessesPerHourForADay (SelectedColorType,NumAccPerHourZero,Hits.Max); Tbl_TR_End (); /* Decrease day */ Dat_GetDateBefore (&Date,&Date); } /***** Finally NumDaysFromLastDateToCurrDate days are shown with 0 clicks (the oldest days since the initial day requested by the user until the first with clicks) *****/ Dat_AssignDate (&LastDate,&Date); NumDaysFromLastDateToCurrDate = Dat_GetNumDaysBetweenDates (&Gbl.DateRange.DateIni.Date,&LastDate); for (D = 1; D <= NumDaysFromLastDateToCurrDate; D++) { NumDayWeek = Dat_GetDayOfWeek (Date.Year,Date.Month,Date.Day); Tbl_TR_Begin (NULL); /* Write the date */ Dat_ConvDateToDateStr (&Date,StrDate); Tbl_TD_Begin ("class=\"%s RT\"",NumDayWeek == 6 ? "LOG_R" : "LOG"); fprintf (Gbl.F.Out,"%s ",StrDate); Tbl_TD_End (); /* Write the day of the week */ Tbl_TD_Begin ("class=\"%s LT\"",NumDayWeek == 6 ? "LOG_R" : "LOG"); fprintf (Gbl.F.Out,"%s ",Txt_DAYS_SMALL[NumDayWeek]); Tbl_TD_End (); /* Draw the color proportional to number of clicks */ Sta_DrawAccessesPerHourForADay (SelectedColorType,NumAccPerHourZero,Hits.Max); Tbl_TR_End (); /* Decrease day */ Dat_GetDateBefore (&Date,&Date); } } /*****************************************************************************/ /********* Put hidden parameter for the type of figure (statistic) ***********/ /*****************************************************************************/ static void Sta_PutHiddenParamScopeSta (void) { Sco_PutParamScope ("ScopeSta",Gbl.Scope.Current); } /*****************************************************************************/ /********************** Get type of color for statistics *********************/ /*****************************************************************************/ static Sta_ColorType_t Sta_GetStatColorType (void) { return (Sta_ColorType_t) Par_GetParToUnsignedLong ("ColorType", 0, Sta_NUM_COLOR_TYPES - 1, (unsigned long) Sta_COLOR_TYPE_DEF); } /*****************************************************************************/ /************************* Draw a bar with colors ****************************/ /*****************************************************************************/ static void Sta_DrawBarColors (Sta_ColorType_t ColorType,float HitsMax) { unsigned Interval; unsigned NumColor; unsigned R; unsigned G; unsigned B; /***** Write numbers from 0 to Hits.Max *****/ Tbl_TABLE_BeginWide (); Tbl_TR_Begin (NULL); Tbl_TD_Begin ("colspan=\"%u\" class=\"LOG LB\" style=\"width:%upx;\"", (GRAPH_DISTRIBUTION_PER_HOUR_TOTAL_WIDTH/5)/2, (GRAPH_DISTRIBUTION_PER_HOUR_TOTAL_WIDTH/5)/2); fprintf (Gbl.F.Out,"0"); Tbl_TD_End (); for (Interval = 1; Interval <= 4; Interval++) { Tbl_TD_Begin ("colspan=\"%u\" class=\"LOG CB\" style=\"width:%upx;\"", GRAPH_DISTRIBUTION_PER_HOUR_TOTAL_WIDTH/5, GRAPH_DISTRIBUTION_PER_HOUR_TOTAL_WIDTH/5); Str_WriteFloatNumToFile (Gbl.F.Out,(float) Interval * HitsMax / 5.0); Tbl_TD_End (); } Tbl_TD_Begin ("colspan=\"%u\" class=\"LOG RB\" style=\"width:%upx;\"", (GRAPH_DISTRIBUTION_PER_HOUR_TOTAL_WIDTH/5)/2, (GRAPH_DISTRIBUTION_PER_HOUR_TOTAL_WIDTH/5)/2); Str_WriteFloatNumToFile (Gbl.F.Out,HitsMax); Tbl_TD_End (); Tbl_TR_End (); Tbl_TR_Begin (NULL); /***** Draw colors *****/ for (NumColor = 0; NumColor < GRAPH_DISTRIBUTION_PER_HOUR_TOTAL_WIDTH; NumColor++) { Sta_SetColor (ColorType,(float) NumColor,(float) GRAPH_DISTRIBUTION_PER_HOUR_TOTAL_WIDTH,&R,&G,&B); Tbl_TD_Begin ("class=\"LM\" style=\"width:1px; background-color:#%02X%02X%02X;\"", R,G,B); fprintf (Gbl.F.Out,"", Cfg_URL_ICON_PUBLIC); Tbl_TD_End (); } Tbl_TR_End (); Tbl_TABLE_End (); } /*****************************************************************************/ /********************* Draw accesses per hour for a day **********************/ /*****************************************************************************/ static void Sta_DrawAccessesPerHourForADay (Sta_ColorType_t ColorType,float HitsNum[24],float HitsMax) { unsigned Hour; unsigned R; unsigned G; unsigned B; char *Str; for (Hour = 0; Hour < 24; Hour++) { /***** Set color depending on hits *****/ Sta_SetColor (ColorType,HitsNum[Hour],HitsMax,&R,&G,&B); /***** Write from floating point number to string *****/ Str_FloatNumToStr (&Str,HitsNum[Hour]); /***** Write cell *****/ Tbl_TD_Begin ("class=\"LOG LM\" title=\"%s\"" " style=\"width:%upx; background-color:#%02X%02X%02X;\"", Str,GRAPH_DISTRIBUTION_PER_HOUR_HOUR_WIDTH,R,G,B); Tbl_TD_End (); /***** Free memory allocated for string *****/ free ((void *) Str); } } /*****************************************************************************/ /************************* Set color depending on hits ***********************/ /*****************************************************************************/ // Hits.Max must be > 0 /* Black Blue Cyan Green Yellow Red +------------+------------+------------+------------+------------+ | 0.2 | 0.2 | 0.2 | 0.2 | 0.2 | +------------+------------+------------+------------+------------+ 0.0 0.2 0.4 0.6 0.8 1.0 */ static void Sta_SetColor (Sta_ColorType_t ColorType,float HitsNum,float HitsMax, unsigned *R,unsigned *G,unsigned *B) { float Result = (HitsNum / HitsMax); switch (ColorType) { case Sta_COLOR: if (Result < 0.2) // Black -> Blue { *R = 0; *G = 0; *B = (unsigned) (Result * 256.0 / 0.2 + 0.5); if (*B == 256) *B = 255; } else if (Result < 0.4) // Blue -> Cyan { *R = 0; *G = (unsigned) ((Result-0.2) * 256.0 / 0.2 + 0.5); if (*G == 256) *G = 255; *B = 255; } else if (Result < 0.6) // Cyan -> Green { *R = 0; *G = 255; *B = 256 - (unsigned) ((Result-0.4) * 256.0 / 0.2 + 0.5); if (*B == 256) *B = 255; } else if (Result < 0.8) // Green -> Yellow { *R = (unsigned) ((Result-0.6) * 256.0 / 0.2 + 0.5); if (*R == 256) *R = 255; *G = 255; *B = 0; } else // Yellow -> Red { *R = 255; *G = 256 - (unsigned) ((Result-0.8) * 256.0 / 0.2 + 0.5); if (*G == 256) *G = 255; *B = 0; } break; case Sta_BLACK_TO_WHITE: *B = (unsigned) (Result * 256.0 + 0.5); if (*B == 256) *B = 255; *R = *G = *B; break; case Sta_WHITE_TO_BLACK: *B = 256 - (unsigned) (Result * 256.0 + 0.5); if (*B == 256) *B = 255; *R = *G = *B; break; } } /*****************************************************************************/ /********** Show listing with number of pages generated per week *************/ /*****************************************************************************/ static void Sta_ShowNumHitsPerWeek (unsigned long NumRows, MYSQL_RES *mysql_res) { extern const char *Txt_Week; extern const char *Txt_STAT_TYPE_COUNT_CAPS[Sta_NUM_COUNT_TYPES]; unsigned long NumRow; struct Date ReadDate; struct Date LastDate; struct Date Date; unsigned W; unsigned NumWeeksBetweenLastDateAndCurDate; struct Sta_Hits Hits; MYSQL_ROW row; /***** Initialize LastDate to avoid warning *****/ Dat_CalculateWeekOfYear (&Gbl.DateRange.DateEnd.Date); // Changes Week and Year Dat_AssignDate (&LastDate,&Gbl.DateRange.DateEnd.Date); /***** Write heading *****/ Tbl_TR_Begin (NULL); Tbl_TH (1,1,"LT",Txt_Week); Tbl_TH (1,1,"LT",Txt_STAT_TYPE_COUNT_CAPS[Gbl.Stat.CountType]); Tbl_TR_End (); /***** Compute maximum number of pages generated per week *****/ Sta_ComputeMaxAndTotalHits (&Hits,NumRows,mysql_res,1,1); /***** Write rows *****/ mysql_data_seek (mysql_res,0); for (NumRow = 1; NumRow <= NumRows; NumRow++) { row = mysql_fetch_row (mysql_res); /* Get year and week (row[0] holds date in YYYYWW format) */ if (sscanf (row[0],"%04u%02u",&ReadDate.Year,&ReadDate.Week) != 2) Lay_ShowErrorAndExit ("Wrong date."); /* Get number of pages generated (in row[1]) */ Hits.Num = Str_GetFloatNumFromStr (row[1]); Dat_AssignDate (&Date,&LastDate); NumWeeksBetweenLastDateAndCurDate = Dat_GetNumWeeksBetweenDates (&ReadDate,&LastDate); for (W = 1; W <= NumWeeksBetweenLastDateAndCurDate; W++) { Tbl_TR_Begin (NULL); /* Write week */ Tbl_TD_Begin ("class=\"LOG LT\""); fprintf (Gbl.F.Out,"%04u-%02u ",Date.Year,Date.Week); Tbl_TD_End (); /* Draw bar proportional to number of hits */ Sta_DrawBarNumHits ('o', // orange background W == NumWeeksBetweenLastDateAndCurDate ? Hits.Num : 0.0, Hits.Max,Hits.Total,500); Tbl_TR_End (); /* Decrement week */ Dat_GetWeekBefore (&Date,&Date); } Dat_AssignDate (&LastDate,&Date); } /***** Finally, show the old weeks without pages generated *****/ Dat_CalculateWeekOfYear (&Gbl.DateRange.DateIni.Date); // Changes Week and Year NumWeeksBetweenLastDateAndCurDate = Dat_GetNumWeeksBetweenDates (&Gbl.DateRange.DateIni.Date, &LastDate); for (W = 1; W <= NumWeeksBetweenLastDateAndCurDate; W++) { Tbl_TR_Begin (NULL); /* Write week */ Tbl_TD_Begin ("class=\"LOG LT\""); fprintf (Gbl.F.Out,"%04u-%02u ",Date.Year,Date.Week); Tbl_TD_End (); /* Draw bar proportional to number of hits */ Sta_DrawBarNumHits ('o', // orange background 0.0,Hits.Max,Hits.Total,500); Tbl_TR_End (); /* Decrement week */ Dat_GetWeekBefore (&Date,&Date); } } /*****************************************************************************/ /********** Show a graph with the number of clicks in each month *************/ /*****************************************************************************/ static void Sta_ShowNumHitsPerMonth (unsigned long NumRows, MYSQL_RES *mysql_res) { extern const char *Txt_Month; extern const char *Txt_STAT_TYPE_COUNT_CAPS[Sta_NUM_COUNT_TYPES]; unsigned long NumRow; struct Date ReadDate; struct Date LastDate; struct Date Date; unsigned M; unsigned NumMonthsBetweenLastDateAndCurDate; struct Sta_Hits Hits; MYSQL_ROW row; /***** Initialize LastDate *****/ Dat_AssignDate (&LastDate,&Gbl.DateRange.DateEnd.Date); /***** Write heading *****/ Tbl_TR_Begin (NULL); Tbl_TH (1,1,"LT",Txt_Month); Tbl_TH (1,1,"LT",Txt_STAT_TYPE_COUNT_CAPS[Gbl.Stat.CountType]); Tbl_TR_End (); /***** Compute maximum number of pages generated per month *****/ Sta_ComputeMaxAndTotalHits (&Hits,NumRows,mysql_res,1,1); /***** Write rows *****/ mysql_data_seek (mysql_res,0); for (NumRow = 1; NumRow <= NumRows; NumRow++) { row = mysql_fetch_row (mysql_res); /* Get the year and the month (in row[0] is the date in YYYYMM format) */ if (sscanf (row[0],"%04u%02u",&ReadDate.Year,&ReadDate.Month) != 2) Lay_ShowErrorAndExit ("Wrong date."); /* Get number of pages generated (in row[1]) */ Hits.Num = Str_GetFloatNumFromStr (row[1]); Dat_AssignDate (&Date,&LastDate); NumMonthsBetweenLastDateAndCurDate = Dat_GetNumMonthsBetweenDates (&ReadDate, &LastDate); for (M = 1; M <= NumMonthsBetweenLastDateAndCurDate; M++) { Tbl_TR_Begin (NULL); /* Write the month */ Tbl_TD_Begin ("class=\"LOG LT\""); fprintf (Gbl.F.Out,"%04u-%02u ",Date.Year,Date.Month); Tbl_TD_End (); /* Draw bar proportional to number of hits */ Sta_DrawBarNumHits ('o', // orange background M == NumMonthsBetweenLastDateAndCurDate ? Hits.Num : 0.0, Hits.Max,Hits.Total,500); Tbl_TR_End (); /* Decrease month */ Dat_GetMonthBefore (&Date,&Date); } Dat_AssignDate (&LastDate,&Date); } /***** Finally, show the oldest months without clicks *****/ NumMonthsBetweenLastDateAndCurDate = Dat_GetNumMonthsBetweenDates (&Gbl.DateRange.DateIni.Date, &LastDate); for (M = 1; M <= NumMonthsBetweenLastDateAndCurDate; M++) { Tbl_TR_Begin (NULL); /* Write the month */ Tbl_TD_Begin ("class=\"LOG LT\""); fprintf (Gbl.F.Out,"%04u-%02u ",Date.Year,Date.Month); Tbl_TD_End (); /* Draw bar proportional to number of hits */ Sta_DrawBarNumHits ('o', // orange background 0.0,Hits.Max,Hits.Total,500); Tbl_TR_End (); /* Decrease month */ Dat_GetMonthBefore (&Date,&Date); } } /*****************************************************************************/ /*********** Show a graph with the number of clicks in each year *************/ /*****************************************************************************/ static void Sta_ShowNumHitsPerYear (unsigned long NumRows, MYSQL_RES *mysql_res) { extern const char *Txt_Year; extern const char *Txt_STAT_TYPE_COUNT_CAPS[Sta_NUM_COUNT_TYPES]; unsigned long NumRow; struct Date ReadDate; struct Date LastDate; struct Date Date; unsigned Y; unsigned NumYearsBetweenLastDateAndCurDate; struct Sta_Hits Hits; MYSQL_ROW row; /***** Initialize LastDate *****/ Dat_AssignDate (&LastDate,&Gbl.DateRange.DateEnd.Date); /***** Write heading *****/ Tbl_TR_Begin (NULL); Tbl_TH (1,1,"LT",Txt_Year); Tbl_TH (1,1,"LT",Txt_STAT_TYPE_COUNT_CAPS[Gbl.Stat.CountType]); Tbl_TR_End (); /***** Compute maximum number of pages generated per year *****/ Sta_ComputeMaxAndTotalHits (&Hits,NumRows,mysql_res,1,1); /***** Write rows *****/ mysql_data_seek (mysql_res,0); for (NumRow = 1; NumRow <= NumRows; NumRow++) { row = mysql_fetch_row (mysql_res); /* Get the year (in row[0] is the date in YYYY format) */ if (sscanf (row[0],"%04u",&ReadDate.Year) != 1) Lay_ShowErrorAndExit ("Wrong date."); /* Get number of pages generated (in row[1]) */ Hits.Num = Str_GetFloatNumFromStr (row[1]); Dat_AssignDate (&Date,&LastDate); NumYearsBetweenLastDateAndCurDate = Dat_GetNumYearsBetweenDates (&ReadDate, &LastDate); for (Y = 1; Y <= NumYearsBetweenLastDateAndCurDate; Y++) { Tbl_TR_Begin (NULL); /* Write the year */ Tbl_TD_Begin ("class=\"LOG LT\""); fprintf (Gbl.F.Out,"%04u ",Date.Year); Tbl_TD_End (); /* Draw bar proportional to number of hits */ Sta_DrawBarNumHits ('o', // orange background Y == NumYearsBetweenLastDateAndCurDate ? Hits.Num : 0.0, Hits.Max,Hits.Total,500); Tbl_TR_End (); /* Decrease year */ Dat_GetYearBefore (&Date,&Date); } Dat_AssignDate (&LastDate,&Date); } /***** Finally, show the oldest years without clicks *****/ NumYearsBetweenLastDateAndCurDate = Dat_GetNumYearsBetweenDates (&Gbl.DateRange.DateIni.Date, &LastDate); for (Y = 1; Y <= NumYearsBetweenLastDateAndCurDate; Y++) { Tbl_TR_Begin (NULL); /* Write the year */ Tbl_TD_Begin ("class=\"LOG LT\""); fprintf (Gbl.F.Out,"%04u ",Date.Year); Tbl_TD_End (); /* Draw bar proportional to number of hits */ Sta_DrawBarNumHits ('o', // orange background 0.0,Hits.Max,Hits.Total,500); Tbl_TR_End (); /* Decrease year */ Dat_GetYearBefore (&Date,&Date); } } /*****************************************************************************/ /**************** Show graphic of number of pages generated per hour ***************/ /*****************************************************************************/ #define DIGIT_WIDTH 6 static void Sta_ShowNumHitsPerHour (unsigned long NumRows, MYSQL_RES *mysql_res) { unsigned long NumRow; struct Sta_Hits Hits; unsigned NumDays; unsigned Hour = 0; unsigned ReadHour = 0; unsigned H; unsigned NumDigits; unsigned ColumnWidth; MYSQL_ROW row; if ((NumDays = Dat_GetNumDaysBetweenDates (&Gbl.DateRange.DateIni.Date,&Gbl.DateRange.DateEnd.Date))) { /***** Compute maximum number of pages generated per hour *****/ Sta_ComputeMaxAndTotalHits (&Hits,NumRows,mysql_res,1,NumDays); /***** Compute width of columns (one for each hour) *****/ /* Maximum number of dígits. If less than 4, set it to 4 to ensure a minimum width */ NumDigits = (Hits.Max >= 1000) ? (unsigned) floor (log10 ((double) Hits.Max)) + 1 : 4; ColumnWidth = NumDigits * DIGIT_WIDTH + 2; /***** Draw the graphic *****/ mysql_data_seek (mysql_res,0); NumRow = 1; Tbl_TR_Begin (NULL); while (Hour < 24) { Hits.Num = 0.0; if (NumRow <= NumRows) // If not read yet all the results of the query { row = mysql_fetch_row (mysql_res); // Get next result NumRow++; if (sscanf (row[0],"%02u",&ReadHour) != 1) // In row[0] is the date in HH format Lay_ShowErrorAndExit ("Wrong hour."); for (H = Hour; H < ReadHour; H++, Hour++) Sta_WriteAccessHour (H,&Hits,ColumnWidth); Hits.Num = Str_GetFloatNumFromStr (row[1]) / (float) NumDays; Sta_WriteAccessHour (ReadHour,&Hits,ColumnWidth); Hour++; } else for (H = ReadHour + 1; H < 24; H++, Hour++) Sta_WriteAccessHour (H,&Hits,ColumnWidth); } Tbl_TR_End (); } } /*****************************************************************************/ /**** Write a column of the graphic of the number of clicks in each hour *****/ /*****************************************************************************/ static void Sta_WriteAccessHour (unsigned Hour,struct Sta_Hits *Hits,unsigned ColumnWidth) { unsigned BarHeight; Tbl_TD_Begin ("class=\"DAT_SMALL CB\" style=\"width:%upx;\"",ColumnWidth); /* Draw bar with a height porportional to the number of clicks */ if (Hits->Num > 0.0) { fprintf (Gbl.F.Out,"%u%%