//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
=== Web Tracker

This extension is providing the web tracker to start collecting visitors data on your website.
The tracker is implemented as an integration of https://github.com/segmentio/analytics.js[analytics.js] for Unomi.

==== Getting started

Extension can be tested at : `http://localhost:8181/tracker/index.html`

In your page include unomiOptions and include code snippet from `snippet.min.js` :

[source]
----
<script type="text/javascript">
        var unomiOption = {
            scope: 'realEstateManager',
            url: 'http://localhost:8181'
        };
        window.unomiTracker||(window.unomiTracker={}),function(){function e(e){for(unomiTracker.initialize({"Apache Unomi":unomiOption});n.length>0;){var r=n.shift(),t=r.shift();unomiTracker[t]&&unomiTracker[t].apply(unomiTracker,r)}}for(var n=[],r=["trackSubmit","trackClick","trackLink","trackForm","initialize","pageview","identify","reset","group","track","ready","alias","debug","page","once","off","on","personalize"],t=0;t<r.length;t++){var i=r[t];window.unomiTracker[i]=function(e){return function(){var r=Array.prototype.slice.call(arguments);return r.unshift(e),n.push(r),window.unomiTracker}}(i)}unomiTracker.load=function(){var n=document.createElement("script");n.type="text/javascript",n.async=!0,n.src=unomiOption.url+"/tracker/unomi-tracker.min.js",n.addEventListener?n.addEventListener("load",function(n){"function"==typeof e&&e(n)},!1):n.onreadystatechange=function(){"complete"!==this.readyState&&"loaded"!==this.readyState||e(window.event)};var r=document.getElementsByTagName("script")[0];r.parentNode.insertBefore(n,r)},document.addEventListener("DOMContentLoaded",unomiTracker.load),unomiTracker.page()}();
</script>
----

`window.unomiTracker` can be used to send additional events when needed.

Check analytics.js API https://segment.com/docs/sources/website/analytics.js/[here].
All methods can be used on `unomiTracker` object, although not all event types are supported by Unomi intergation.

==== How to contribute

The source code is in the folder javascript with a package.json, the file to update is `analytics.js-integration-apache-unomi.js` apply your modification in this file then use the command `yarn build` to compile a new JS file.
Then you can use the test page to try your changes `http://localhost:8181/tracker/index.html`.

==== Tracking page views

In the initialize call, the tracker will generate an implicit page view event, which by default will be populated with
the following information:

[source,javascript]
----
    window.digitalData.page = window.digitalData.page || {
        path: location.pathname + location.hash,
        pageInfo: {
            pageName: document.title,
            pageID : location.pathname + location.hash,
            pagePath : location.pathname + location.hash,
            destinationURL: location.href
        }
    }
----

Now if you want to provide your own custom page information for the initial page view, you can simply do it like this:

[source,`javascript]
----
    unomiTracker.initialize({
            scope: 'myScope',
            url: 'http://unomi:8181', // we use an empty URL to make it relative to this page.
            initialPageProperties: {
                path: path,
                pageInfo: {
                    destinationURL: location.href,
                    tags: ["tag1", "tag2", "tag3"],
                    categories: ["category1", "category2", "category3"]
                },
                interests: {
                    "interest1": 1,
                    "interest2": 2,
                    "interest3": 3
                }
            }
        });
----

`

Also note that the FIRST call to unomiTracker.page() will be IGNORED because of this initial page view.This is the
way that the Analytics.js library handles it.So make sure you are aware of this when calling it.This is to avoid having
two page views on a single call and to be compatible with old versions that did use the explicit call.

By default the script will track page views, but maybe you want to take control over this mechanism of add page views
to a single page application.In order to generate a page view programmatically from Javascript you can use code similar
to this :

[source]
----
    <script type="text/javascript">
        // This is an example of how to provide more details page properties to the view event. This can be useful
        // in the case of an SPA that wants to provide information about a view that has metadata such as categories,
        // tags or interests.
        path = location.pathname + location.hash;
        properties = {
            path: path,
            pageInfo: {
                destinationURL: location.href,
                tags : [ "tag1", "tag2", "tag3"],
                categories : ["category1", "category2", "category3"],
            },
            interests : {
                "interest1" : 1,
                "interest2" : 2,
                "interest3" : 3
            }
        };
        console.log(properties);
        // this will trigger a second page view for the same page (the first page view is in the tracker snippet).
        window.unomiTracker.page(properties);
    </script>
----

Here is a more detail view of what you may include in the pageInfo object :

.PageInfo Properties
|===
|Name|Description

|pageID
|A unique identifier in string format for the page. Default value : page path

|pageName
|A user-displayed name for the page. Default value : page title

|pagePath
|The path of the page, stored by Unomi. This value should be the same as the one passed in the `page` property of the
object passed to the unomiTracker call. Default value : page path

|destinationURL
|The full URL for the page view. This doesn't have to be a real existing URL it could be an internal SPA route. Default value : page URL

|referringURL
|The referringURL also known as the previous URL of the page/screen viewed. Default value : page referrer URL

|tags
|A String array of tag identifiers. For example `['tag1', 'tag2', 'tag3']`

|categories
|A String array of category identifiers. For example `['category1', 'category2', 'category3']`

|===

The `interests` object is basically list of interests with "weights" attached to them.These interests will be accumulated
in Apache Unomi on profiles to indicate growing interest over time for specific topics.These are freely defined and
will be accepted by Apache Unomi without needing to declare them previously anywhere (the same is true for tags and
categories).

==== Tracking form submissions

Using the web tracker you can also track form submissions. In order to do this a few steps are required to get a form's
submission to be tracked and then its form values to be sent as events to Apache Unomi. Finally setting up a rule to
react to the incoming event will help use the form values to perform any action that is desired.

Let's look at a concrete example. Before we get started you should know that this example is already available to
directly test in Apache Unomi at the following URL :

    http://localhost:8181/tracker

Simply modify the form values and click submit and it will perform all the steps we are describing below.

So here is the form we want to track :

[source]
----
<form id="testFormTracking" action="#" name="testFormTracking">
    <label for="firstName">First name</label>
    <input type="text" id="firstName" name="firstName" value="John"/>

    <label for="lastName">Last name</label>
    <input type="text" id="lastName" name="lastName" value="Doe"/>

    <label for="email">Email</label>
    <input type="email" id="email" name="email" value="johndoe@acme.com"/>

    <input type="submit" name="submitButton" value="Submit"/>
</form>
----

As you can see it's composed of three fields - firstName, lastName and email - as well as a submit button. In order to
track it we can add directly under the following snippet :

[source]
----
<script type="text/javascript">
    window.addEventListener("load", function () {
        var form = document.getElementById('testFormTracking');
        unomiTracker.trackForm(form, 'formSubmitted', {formName: form.name});
    });
</script>
----

What this snippet does is retrieve the form using its element ID and then uses the unomiTracker to track form submissions.
Be careful to always use in the form event name a string that starts with `form` in order for the event to be sent back
to Unomi. Also the form name is also a mandatory parameter that will be passed to Unomi inside a event of type `form` under
the `target.itemId` property name.

Here is an example of the event that gets sent back to Apache Unomi:

[source]
----
{
  "itemId" : "cd627012-963e-4bb5-97f0-480990b41254",
  "itemType" : "event",
  "scope" : "realEstateManager",
  "version" : 1,
  "eventType" : "form",
  "sessionId" : "aaad09aa-88c2-67bd-b106-5a47ded43ead",
  "profileId" : "48563fd0-6319-4260-8dba-ae421beba26f",
  "timeStamp" : "2018-11-23T16:32:26Z",
  "properties" : {
    "firstName" : "John",
    "lastName" : "Doe",
    "email" : "johndoe@acme.com",
    "submitButton" : "Submit"
  },
  "source" : {
    "itemId" : "/tracker/",
    "itemType" : "page",
    "scope" : "realEstateManager",
    "version" : null,
    "properties" : {
      "pageInfo" : {
        "destinationURL" : "http://localhost:8181/tracker/?firstName=Bill&lastName=Gates&email=bgates%40microsoft.com",
        "pageID" : "/tracker/",
        "pagePath" : "/tracker/",
        "pageName" : "Apache Unomi Web Tracker Test Page",
        "referringURL" : "http://localhost:8181/tracker/?firstName=John&lastName=Doe&email=johndoe%40acme.com"
      },
      "attributes" : [ ],
      "consentTypes" : [ ],
      "interests" : { }
    }
  },
  "target" : {
    "itemId" : "testFormTracking",
    "itemType" : "form",
    "scope" : "realEstateManager",
    "version" : null,
    "properties" : { }
  },
  "persistent" : true
}
----

You can see in this event that the form values are sent as properties of the event itself, while the form name is sent
as the `target.itemId`

While setting up form tracking, it can be very useful to use the Apache Unomi Karaf SSH shell commands : `event-tail`
and `event-view` to check if you are properly receiving the form submission events and that they contain the expected
data. If not, check your tracking code for any errors.

Now that the data is properly sent using an event to Apache Unomi, we must still use it to perform some kind of actions.
Using rules, we could do anything from updating the profile to sending the data to a third-party server (using a custom-
developped action of course). In this example we will illustrate how to update the profile.

In order to do so we will deploy a rule that will copy data coming from the event into a profile. But we will need to
map the form field names to profile names, and this can be done using the `setPropertyAction` that's available out of the
box in the Apache Unomi server.

There are two ways to register rules : either by building a custom OSGi bundle plugin or using the REST API to directly
send a JSON representation of the rule to be saved. We will in this example use the CURL shell command to make a call to
the REST API.

[source]
----
curl -X POST -k -u karaf:karaf https://localhost:9443/cxs/rules \
  --header "Content-Type: application/json" \
-d @- << EOF
{
  "itemId": "form-mapping-example",
  "itemType": "rule",
  "linkedItems": null,
  "raiseEventOnlyOnceForProfile": false,
  "raiseEventOnlyOnceForSession": false,
  "priority": -1,
  "metadata": {
    "id": "form-mapping-example",
    "name": "Example Form Mapping",
    "description": "An example of how to map event properties to profile properties",
    "scope": "realEstateManager",
    "tags": [],
    "enabled": true,
    "missingPlugins": false,
    "hidden": false,
    "readOnly": false
  },
  "condition": {
    "type": "formEventCondition",
    "parameterValues": {
      "formId": "testFormTracking",
      "pagePath" : "/tracker/"
    }
  },
  "actions": [
    {
      "type": "setPropertyAction",
      "parameterValues": {
        "setPropertyName": "properties(firstName)",
        "setPropertyValue": "eventProperty::properties(firstName)",
        "setPropertyStrategy": "alwaysSet"
      }
    },
    {
      "type": "setPropertyAction",
      "parameterValues": {
        "setPropertyName": "properties(lastName)",
        "setPropertyValue": "eventProperty::properties(lastName)",
        "setPropertyStrategy": "alwaysSet"
      }
    },
    {
      "type": "setPropertyAction",
      "parameterValues": {
        "setPropertyName": "properties(email)",
        "setPropertyValue": "eventProperty::properties(email)",
        "setPropertyStrategy": "alwaysSet"
      }
    }
  ]
}
EOF
----

As you can see in this request, we have a few parameters that need explaining:

- `-k` is used to accept any certificate as we are in this example using a default Apache Unomi server configuration that
comes with its predefined HTTPS certificates
- `-u karaf:karaf` is the default username/password for authenticating to the REST API. To change this value you should
edit the `etc/users.properties`file and it is required to modify this login before going to production.

Finally the rule itself should be pretty self-explanatory but there are a few important things to note :

- the `itemId` and `metadata.id` values should be the same
- the `scope` should be the same as the scope that was setup in the tracker initialization
- the `formId` parameter must have the form name value
- the `pagePath` should be the pagePath passed through the event (if you're not sure of its value, you could either using
network debugging in the browser or use the `event-tail` and `event-view` commands in the Apache Unomi Karaf SSH shell).
- the setPropertyAction may be repeated as many times as desired to copy the values from the event to the profile. Note that
the `setPropertyName` will define the property to set on the profile and the `setPropertyValue` will define where the
value is coming from. In this example the name and the value are the same but that is no way a requirement. It could
even be possible to using multiple `setPropertyAction` instances to copy the same event property into different profile
properties.

To check if your rule is properly deployed you can use the following SSH shell command :

`unomi:rule-view form-mapping-example`

The parameter is the `itemId` of the rule. If you want to see all the rules deployed in the system you can use the
command :

`unomi:rule-list 1000`

The `1000` parameter is the limit of number of objects to retrieve. As the number of rules can grow quickly in an Apache
Unomi instance, it is recommended to put this value a bit high to make sure you get the full list of rules.

Once the rule is in place, try submitting the form with some values and check that the profile is properly updated. One
recommend way of doing this is to use the `event-tail` command that will output something like this :

[source]
----
ID                                  |Type          |Session                             |Profile                             |Timestamp                    |Scope          |Persi|
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
cef09b89-6b99-4e4f-a99c-a4159a66b42b|form          |aaad09aa-88c2-67bd-b106-5a47ded43ead|48563fd0-6319-4260-8dba-ae421beba26f|Fri Nov 23 17:52:33 CET 2018 |realEstateManag|true |
----

You can directly see the profile that is being used, so you can then simply use the

`unomi:profile-view 48563fd0-6319-4260-8dba-ae421beba26f`

command to see a JSON dump of the profile and check that the form values have been properly positioned.