# Statistics Library

The statistics library can be used to provide statistics services within App. The following functionality is implemented:

- Support of two types of datasets: StatisticsCumulative and StatisticsState. The StatisticsCumulative provides values at timestamps, which can be added up over a period of time to get a total in this timeframe. The StatisticsState provide a state at a given timeframe. It can be used to find maximum values in a timeframe of averages.
- The Data is organized with Datasets, Charts and Categories. A dataset is a table containing pairs of timestamp and value. These datasets can be combined with to Charts. The data from multiple datasets of type StatisticsCumulative can be added into a chart. The charts can be assigned to different categories.
- Implement the App Websocker Api "com.innovaphone.statistics". For this the library can register as JsonApi into the AppWebsocket framework so that it can be accessed via AppWebsocket. If announced as a Service, the Api can be also found with the Services Mechanism. The main Requests on this Api are:
  Categories
    Read all available categories
  Charts
    Read the available Charts
  Datasets
    Read the available Datasets
  Data
    Read the data in a dataset from a start to an end timestamp. This is for testing only
  Current
    Read the current value of a StatisticsState dataset.
  Read
    Read data from a start to an end timestamp as yearly, monthly, weekly or live data. It returns an array of long64 values. For live data the values since the last Read are returned. By reading for example once a second a live chart can be displayed
- Provide internal Apis so that the App can define the available Categories, Charts and Datasets and can provide data for the dataset. The App is responsible to provide Updates whenever needed, the libray does not do any periodic polling.
  The internal Api is split in statistics.h and statistics_dataset.h. statistics_dataset.h is the Api to provide the data. It has no dependency on any other header file.
- Keep a table for one hour of live data for each dataset. To limit the size of the table the information of one second is combined. This means the table has a maximum of 3600 entries.
- Store dataset data into a database table. A single entry in the table consists of a long64 timestamp (ms), a long64 value and a long64 reference to a dataset. So a total of 24 bytes are stored per value (plus any database overhead). Only one value per hour is stored in case of StatisticsCumulative this is the sum of the values and in case of StatisticsState it is the maximum. So during one year this can addup to 24*365.25=8766 values or 210KB

## Interface

### class IStatisticsProvider * CreateStatisticsProvider()

Global function to instaniate the library. Usually called from the App main module. To have the library instantiated with this function, allows it to be replaced by a test library for unit testing.

The function class IStatistics * IStatisticsProvider::CreateStatistics() can be used to create the instance used within the AppInstance.

### class IStatistics

Interface class to be used by the App Code

void Init(class UStatistics * user, class IDatabase * database)
  Has to be called for initialization. As long a no StatisticsInitComplete is called all other calls to the interface are ignored
void StartMonitor(const char * type, class json_io & send, word base, char *& tmp)
  Starts monitoring of a given value with the "Monitor" functionality outside the scope of the library
void Close()
  Close the library. Has to be done for graceful AppInstance shutdown. Is acknowledged with StatisticsCloseComplete()
void CreateCategory(const char * name)
  Used to create a category
void CreateChart(const char * category, const char * name, const char * condition)
  Used to create a Chart. The condition identifies the datasets for the chart. Currently only a single dataset identified with the name is supported.
class IStatisticsDataset * CreateDataset(const char * name, enum StatisticsType type, class UStatisticsDataset * provider = 0)
  Creates a dataset. If a provider pointer is given, no data is stored in the library, but the data is retrieved from the App itself using the void UStatisticsDataset::Get(class IStatisticsGet * user, long64 start, long64 end) function.

### class IStatisticsDataset

Interface class to a dataset

void Data(long64 value)
  Provide a value. The timestamp of the value is the current system timestamp as read from ITime::TimeStampMilliseconds()
void BusyStart()/void BusyEnd()
  With the call to BusyEnd the time since the call to BusyStart is stored as value.

## Steps to include the libray into an App

- Share sdk/common/service/statistics into App code and add

                      "include sdk/common/service/statistics/statistics.mak" to submodules.mak

- Include the "com.innovaphone.statistis" as Client and as Service Api. Something like `

                      word apis = msg.add_object(base, "apis");
                      msg.add_object(apis, "com.innovaphone.statistics");

  ` In AppWebsocketAppInfo and AppWebsocketServiceInfo. At this point the App should show up in Charts.
- Include

                      IStatisticsProvider * statisticsProvider = CreateStatisticsProvider();

  in <app>-main.cpp and include the statisticsProvider as argument in the AppService constructor. The include file "common/interface/statistics.h" ís needed for this. Add cleanup of the statistics provider before exiting main:

                      delete statisticsProvider;

- Add

                      #include "common/interface/statistics.h"
                      #include "common/interface/statistics_dataset.h"

  to the <App>.cpp module.
- Add member

                      class IStatisticsProvider * statisticsProvider;

  to the App Service class and

                      IStatistics * statistics;

  to the App Instance class
- Create the statistics instance with in the App instance constructor:

                      statistics = service->statisticsProvider->CreateStatistics();

- Add a first category for the data. E.g.

                      this->statistics->CreateCategory("*");

- Register the Json Api in the App Instance constructor with

                      RegisterJsonApi(statistics);

  At this point the category should show up in charts when clicking on the App
- Add CreateChart and CreateDataset to announce the data which shall be published. For example

                      statisticsSessions = statistics->CreateDataset("sessions", StatisticsState);
                      statistics->CreateChart("*", "Sessions", "sessions");

- App functions to provide data. For example in the session constructor to update the sessions Count:

                      <AppService>->sessionCount++;
                      <AppService>->statisticsSessions->Data(<AppService>->sessionCount);

- Add instance initialization and closing of the lib. For this use "public UStatistics" as base class to the App Instance class. Add override functions

                      void StatisticsInitComplete() override;
                      void StatisticsCloseComplete() override;

  Call statistics->Init(this, database) in the initialization chain after database inititialization and statistics->Close() in the App Instance Close function. Continue with closing only after the StatisticsCloseComplete() callback.