# Scoring

## Scoring <a href="#scoring" id="scoring"></a>

You can get the average and maximum aggregate scores for previous trips taken by using the `ScoringAggregateService`. Functions have been added to query the scores over various different time periods. The time periods available are:

* today
* the last 7 days / last week
* the last 30 days / last month
* the last 90 days
* the last 365 days
* the last N days
* custom date range

The definition of a day is based on the user's current timezone.

For the following, the example timezone should be considered to be UTC-0400 (i.e Toronto). If a request for today's data is made at on the 2nd day of the month, at 23:00 (11PM) UTC-0400, the result should be based on that specific day, even though the current date according to the UTC would be the 3rd day of the month. (11:00PM UTC-0400 corresponds to 03:00AM the next day on UTC-0000 time).

Some other examples: User's time: 2020-01-01 - 00:01AM UTC-0400 (04:01AM UTC-0000) Results: 2020-01-01

User's time: 2020-01-01 - 12:01PM UTC-0400 (04:01PM UTC-0000) Results: 2020-01-01

User's time: 2020-01-01 - 10:01PM UTC-0400 (2020-01-02 02:01AM UTC-0000) Results: 2020-01-01

## Scoring Aggregate <a href="#scoring-aggregate" id="scoring-aggregate"></a>

An aggregate of scoring averages and sub scoring (braking, cornering, acceleration and speed).

Any valid user on the DriveSync system (identified via the `Identity`set during [SDK initialization](https://sdk.ims.tech/readme/ios/initializing-the-sdk#identity)) should be able to know scoring aggregate.

### ScoringAggregate model <a href="#scoringaggregate-model" id="scoringaggregate-model"></a>

ScoringAggregate model includes scores data along with the events captured in `ScoringAggregate.tripScoringDailyAggregate.componentScores`.

The host app can access the events through `componentScores` which have score types:

* speeding
* milage
* braking
* cornering
* payd
* overSpeeding
* acceleration
* distractedDriving

The `otherSubScores` is type of Dictionary for which the key is a custom event that is not in the above list.

### **Pre-made date ranges** <a href="#pre-made-date-ranges" id="pre-made-date-ranges"></a>

There are some Pre-made requests for easy access to some commonly used date ranges, as they are commonly used for other scoring components.

The current list includes:

* Today
* Last 7 days
* Last 30 days
* Last 90 days
* Last 365 days

**Today**

To fetch the `ScoringAggregate` for the user for the today, the following API can be used.

**Concrete example**

{% tabs %}
{% tab title="Swift" %}

```swift
let service = ScoringService()
service.today(then: { result in
    guard !result.value.isEmpty else {
        // failure
        return
    }
    completionHandler(.success(result.value))
})
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
val service = ScoringService()
service.fetchTodaysDailyScores() { result: Result<Content?>? ->
    if (result?.value == null || result.throwable != null) {
        // failure
    } else {
        // Success
        val content = result.value
    }
})
```

{% endtab %}
{% endtabs %}

**Last 7 days**

Fetch the `ScoringAggregate` for the user for the last 7 days, the following API can be used.

**Concrete example**

{% tabs %}
{% tab title="Swift" %}

```swift
let service = ScoringService()
service.last7Days(then: { result in
    guard !result.value.isEmpty else {
        // failure
        return
    }
    completionHandler(.success(result.value))
})
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
val service = ScoringService()
service.fetchLast7DaysDailyScores() { result: Result<Content?>? ->
        if (result?.value == null || result.throwable != null) {
            // failure
        } else {
            // Success
            val content = result.value
        }
})
```

{% endtab %}
{% endtabs %}

**Other values**

In order to get last 30, 90, and 365 days simply replace number "7" with the desired value respectively.

### **Custom date range** <a href="#custom-date-range" id="custom-date-range"></a>

Fetching data for the scoring aggregate requires a start and end date (range).

The date is assumed to be based on the user's current timezone. As an example, if the current user's timezone is set to UTC-5:00, the long 1603416046000 corresponds to 2020-10-22 (even though it corresponds to 2020-10-23 1:20AM UTC).

To fetch the `ScoringAggregate` for the user over a period of time with a start and end date(range), the following API can be used.

**Concrete example**

{% tabs %}
{% tab title="Swift" %}

```swift
let service = ScoringService()
service.dateRange(from: Date(), to: Date(), then: { result in
    guard !result.value.isEmpty else {
        // failure
        return
    }
    completionHandler(.success(result.value))
})
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
val service = ScoringService()
service.fetchDaily(from, to) { result: Result<Content?>? ->
    if (result?.value == null || result.throwable != null) {
        // failure
    } else {
        // Success
        val content = result.value
    }
})
```

{% endtab %}
{% endtabs %}

### **Vehicle** <a href="#vehicle" id="vehicle"></a>

Fetching data for the scoring aggregate requires a start and end date (range).

**Required information**

\*vehicle ID: In order to fetch scoring data for a vehicle, the application must have a valid vehicle associated with the identity.

To fetch the `ScoringAggregate` for a vehicle of the user over a period of time with a start and end date(range), the following API can be used.

**Concrete example**

{% tabs %}
{% tab title="Swift" %}

```swift
service.fetchAggregateScoresByVehicle(vehicleId: vehicleId, from: Date(), to: Date(), then: { result in
    guard !result.value.isEmpty else {
        // failure
        return
    }
    completionHandler(.success(result.value))
})
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
val service = ScoringService()
service.fetchAggregateScoresByVehicle(vehicleID, from, to) {
     result: Result<Content?>? ->
        if (result?.value == null || result.throwable != null) {
            // failure
        } else {
            // Success
            val content = result.value
        }
})
```

{% endtab %}
{% endtabs %}

To fetch the `ScoringAggregate` for a vehicle of the user for the past N days, the following API can be used.

{% tabs %}
{% tab title="Swift" %}

```swift
service.fetchLastNDaysAggregateScoresByVehicle(vehicleId: vehicleId, days: days, then: { result in
    guard !result.value.isEmpty else {
        // failure
        return
    }
    completionHandler(.success(result.value))
})
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
val service = ScoringService()
service.fetchLastNDaysAggregateScoresByVehicle(vehicleID, days) {
     result: Result<Content?>? ->
        if (result?.value == null || result.throwable != null) {
            // failure
        } else {
            // Success
            val content = result.value
        }
})
```

{% endtab %}
{% endtabs %}

**Failures**

ScoringService provides a \[Throwable] in the results sent to the \[ResultCallback].

The \[Result] provided can be differentiated by checking the type of results, which is always \[Result.Success] or \[Result.Failure].

Alternatively, the \[ResultCallback] can test for the presence of the throwable.

```kotlin
scoringService.fetchTodaysScores(result -> {
   ScoringAggregate aggregate = result.getValue();
   if (aggregate != null) {
       setScoreTextValue("Daily: ", result.getValue());
   } else {
       NetworkException exception = (NetworkException) result.getThrowable();
       if (exception.getReason() == NetworkException.Reason.SERVER_NOT_FOUND) {
           showError("Server not found");
       }
   }
});
```

## Scoring average <a href="#scoring-average" id="scoring-average"></a>

Any valid user on the DriveSync system (identified via the Identity set during [SDK initialization](https://sdk.ims.tech/readme/ios/initializing-the-sdk#identity)) should be able to know scoring aggregate.

### ScoringAverage model <a href="#scoringaverage-model" id="scoringaverage-model"></a>

ScoringAverage model includes scores data along with the events captured in `ScoringAverage.tripScoringAverage.componentScores`.

The host app can access the events through `componentScores` which accepts custom scoring events with the sub component named `otherSubScores`.

The `otherSubScores` is type of Dictionary for which the key is a custom event required for host app.

In all the above API's "Daily" can replaced by "Average" to get the corresponding response.

**Concrete example**

For example to fetch the `ScoringAverage` for the user for the last 7 days, the following API can be used.

{% tabs %}
{% tab title="Swift" %}

```swift
let service = ScoringService()
service.custom(from: fromDate, to: toDate, then: { result in
    guard !result.value.isEmpty else {
        // error
        return
    }
    completionHandler(.success(result.value))
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
val service = ScoringService()
service.fetchLast7DaysAverageScores() { result: Result<Content?>? ->
        if (result?.value == null || result.throwable != null) {
            // failure
        } else {
            // Success
            val content = result.value
        }
})
```

{% endtab %}
{% endtabs %}

### Weekly average <a href="#weekly-average" id="weekly-average"></a>

To receive week by week score data, call fetchWeek api to recieve the desired data. The number passed as argument is a UInt representing the number of weeks you want the data. For example, to retreive current week you'll pass 0 and for last week you need to pass 1.

For example to fetch the `ScoringAverage` for the user for the desired week, the following API can be used.

**Concrete example**

{% tabs %}
{% tab title="Swift" %}

```swift
let service = ScoringService()
service.fetchWeek(weekNumber: weekNumber, then: { result in
    guard !result.value.isEmpty else {
        // error
        return
    }
    completionHandler(.success(result.value))
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
val service = ScoringService()
service.fetchWeek(weekNumber) { result: Result<Content?>? ->
        if (result?.value == null || result.throwable != null) {
            // failure
        } else {
            // Success
            val content = result.value
        }
})
```

{% endtab %}
{% endtabs %}

### **Vehicle** <a href="#vehicle-1" id="vehicle-1"></a>

Fetching data for the scoring average requires a start and end date (range).

**Required information**

\*vehicle ID: In order to fetch scoring data for a vehicle, the application must have a valid vehicle associated with the identity.

To fetch the `ScoringAverage` for a vehicle of the user over a period of time with a start and end date(range), the following API can be used.

**Concrete example**

{% tabs %}
{% tab title="Swift" %}

```swift
let service = ScoringService()
service.fetchAverageScoresByVehicle(vehicleId: vehicleId, from: fromDate, to: toDate, then: { result in
    guard !result.value.isEmpty else {
        // error
        return
    }
    completionHandler(.success(result.value))
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
val service = ScoringService()
service.fetchAverageScoresByVehicle(vehicleID, from, to) {
     result: Result<Content?>? ->
        if (result?.value == null || result.throwable != null) {
            // failure
        } else {
            // Success
            val content = result.value
        }
})
```

{% endtab %}
{% endtabs %}

To fetch the `ScoringAverage` for a vehicle of the user for the past N days, the following can be used.

*Note: In iOS (Swift) the method* **fetchLastNDaysAverageScores**, *has vehicle ID as optional. If it is NOT passed, the api returns user's last N days average scores.*

{% tabs %}
{% tab title="Swift" %}

```swift
let service = ScoringService()
service.fetchLastNDaysAverageScores(vehicleId: vehicleId, days: days, then: { result in
    guard !result.value.isEmpty else {
        // error
        return
    }
    completionHandler(.success(result.value))
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
val service = ScoringService()
service.fetchLastNDaysAverageScoresByVehicle(vehicleID, days) {
     result: Result<Content?>? ->
        if (result?.value == null || result.throwable != null) {
            // failure
        } else {
            // Success
            val content = result.value
        }
})
```

{% endtab %}
{% endtabs %}

### PolicyScoring

**Fetch Average Scores For User By Policy (Using Start & End Date)**

To fetch average scores for a specifc user and policy within the given start and end date, the following API can be used.

#### Parameters:

* **`userId`**: The user ID
* **`policyId`**: The policy ID
* **`startDate`**: Start date (optional)
* **`endDate`**: End date (optional)
* **`verificationCutOffDate`**: Verification cutoff date (optional)

#### **Example**

{% tabs %}
{% tab title="Swift" %}

```swift
let service = ScoringService()

service.fetchAverageScoresByPolicy(userId: userId,
                                   policyId: policyId,
                                   startDate: startDate,
                                   endDate: endDate,
                                   verificationCutOffDate: cutOffDate,
                                   then: { result in
    switch result {
    case .success(let policyScoring):
        // fetch successfull
    case .failure:
        // API call failed
    }
})
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
val service = ScoringService()
service.fetchAverageScoresByPolicy(userId,
                                    policyId,
                                    startDate,
                                    endDate,
                                    verificationCutOffDate) { result: Result<UserPolicyScore>? ->
    if (result?.value == null || result.throwable != null) {
        // failure
    } else {
        // Success
        val userPolicyScore = result.value
    }
}
```

{% endtab %}
{% endtabs %}

**Fetch Average Scores For User By Policy (Using Week)**

To fetch average scores for a specifc user and policy within the given week, the following API can be used.

#### Parameters:

* `userId`: User id required
* `policyId`:  Policy id required
* `userScoreWeek`: Week optional (Week number is relative to the current week (0 for current week, 1 for previous week))
* `verificationCutOffDate`: Verification cutoff date optional

{% tabs %}
{% tab title="Swift" %}

```swift
let service = ScoringService()

service.fetchAverageScoresByPolicy(userId: userId,
                                   policyId: policyId,
                                   userScoreWeek: weekNumber,
                                   verificationCutOffDate: cutOffDate,
                                   then: { result in
    switch result {
    case .success(let policyScoring):
        // fetch successfull
    case .failure:
        // API call failed
    }
})

```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
val service = ScoringService()
service.fetchAverageScoresByPolicy(userId,
                                    policyId,
                                    userScoreWeek,
                                    verificationCutOffDate) { result: Result<PolicyScoring>? ->
    if (result?.value == null || result.throwable != null) {
        // API call failed
    } else {
        // fetch successful
        val policyScoring = result.value
    }
}
```

{% endtab %}
{% endtabs %}
