<%
(function () {

    var log = new Log();
    var carbon = require('carbon');    
    var timeRangeUtil = Packages.org.wso2.analytics.shared.util.time.TimeRangeUtils;
    var MultitenantConstants = Packages.org.wso2.carbon.base.MultitenantConstants;
    var common = require('isanalytics-common.jag');
    
    var CONTENT_TYPE_JSON = "application/json";
    var TYPE = "type";
    var HTTP_INTERNAL_ERROR = 500;
    var HTTP_USER_NOT_AUTHENTICATED = 403;

    //operation types
    var TYPE_TOP_LONGEST_SESSIONS = 21;
    var TYPE_AVERAGE_SESSION_DURATION = 22;
    var TYPE_SESSION_COUNT_OVER_TIME = 23;
    var TYPE_SESSION_USERNAME_LIST = 24;
    var TYPE_SESSION_CHANGE_OVER_TIME = 26;
    var TYPE_SESSION_DATA_TABLE = 27;

    response.contentType = CONTENT_TYPE_JSON;

    loggedInUser = common.getLoggedInUser();

    if (loggedInUser == null) {
        log.error("user is not authenticated!");
        response.status = HTTP_USER_NOT_AUTHENTICATED;
        print('{ "status": "Failed", "message": "User is not authenticated." }');
        response.sendRedirect("/login-controller");
        return;
    }

    var connector = common.getConnector();

    var type = 0;
    var typeParam = request.getParameter(TYPE);
    if (typeParam != null) {
        type = parseInt(typeParam);
    }

    if (type == 0) {
        log.error("operation type is not specified!");
        response.status = HTTP_INTERNAL_ERROR;
        print('{ "status": "Failed", "message": "Operation type is not specified" }');
        return;
    }

    if (connector != null && loggedInUser != null) {

        var result = null;
        var query = null;
        var resp = null;

        var user = carbon.server.tenantUser(loggedInUser);
        var tenantId = user.tenantId;
        var tenantFilter = " AND meta_tenantId : [ "+ tenantId +" TO " +tenantId + " ] ";
        var superTenantId = MultitenantConstants.SUPER_TENANT_ID;

        var timeFrom = request.getParameter("timeFrom");
        var timeTo = request.getParameter("timeTo");
        var timeUnit = timeRangeUtil.getSuitableTimeRangeUnit(timeFrom, timeTo);

        switch (type) {          
            case TYPE_TOP_LONGEST_SESSIONS:
            {
                result = [];
                var data = [];
                var start = parseInt(request.getParameter("start"));
                var length = parseInt(request.getParameter("count"));

                var tableName = "ORG_WSO2_IS_ANALYTICS_STREAM_SESSIONINFO";
                timeFrom = timeRangeUtil.getFloorValueForTimeStamp(timeFrom, timeUnit);
                var timeNow = new Date().getTime();

                query = stringify({
                    fieldName: "sessionId", //field which is indexed as a FACET
                    categoryPath: [], //Path being drilled down, optional
                    query: "startTimestamp : [" + 0 + " TO " + timeTo + "] AND (endTimestamp : [" + timeFrom + " TO " + timeNow + "] OR isActive:true)" + tenantFilter ,
                    scoreFunction: "duration", //score function
                    start: start,
                    count: length
                });

                resp = connector.drillDownCategories(superTenantId, tableName, query);
                var dataPoints = JSON.parse(resp.getMessage());
                var obj = dataPoints.categories;
                var count = Object.keys(obj).length;

                if(count != 0) {
                    var escape = function (text) {
                        return text.replace(/[-[/\]{}()*+?.,\\^$|#\s]/g, "\\$&");
                    };
                    var sessionIds = [];
                    var queryString = "";
                    for (var key in obj) {
                        sessionIds.push(key);
                        if(queryString.length != 0) {
                            queryString += " OR ";
                        }
                        queryString += "sessionId:" + escape(key); //adding "" because sessionId could contain special characters
                    }

                    query = stringify({
                        query: queryString,
                        start: start,
                        count: length,
                        "sortBy": [
                            {
                                "field": "duration",
                                "sortType": "DESC"
                            }
                        ]
                    });

                    resp = connector.search(superTenantId, tableName, query);
                    var dataPoints = JSON.parse(resp.getMessage());

                    for (var i = 0; i < dataPoints.length; i++) {
                        var temp = [];
                        if (dataPoints[i] != null) {
                            var username = dataPoints[i]["values"]["usernameWithTenantDomainAndUserstoreDomain"];
                            var duration = dataPoints[i]["values"]["duration"];
                            data.push({
                                "username": username,
                                "duration": duration / 1000,
                                "sessionId": i
                            });
                        }
                    }
                }
                result.push(data);
                result.push(count);
                break;
            }
            case TYPE_AVERAGE_SESSION_DURATION:
            {
                result = [];
                var data = [];
                dataPointsArray = [];
                var start = parseInt(request.getParameter("start"));
                var length = parseInt(request.getParameter("count"));

                var tableName = "ORG_WSO2_IS_ANALYTICS_STREAM_SESSIONINFO";
                timeFrom = timeRangeUtil.getFloorValueForTimeStamp(timeFrom, timeUnit);
                var timeNow = new Date().getTime();

                query = stringify({
                    fieldName : "usernameWithTenantDomainAndUserstoreDomain",
                    categoryPath : [],
                    query: "startTimestamp : [" + 0 + " TO " + timeTo + "] AND (endTimestamp : [" + timeFrom + " TO " + timeNow + "] OR isActive:true)" + tenantFilter ,
                    scoreFunction : "duration",
                    start: 0,
                    count: 1000000
                });

                resp = connector.drillDownCategories(superTenantId, tableName, query);
                var dataPoints = JSON.parse(resp.getMessage());
                var obj = dataPoints.categories;
                var count = Object.keys(obj).length;

                var durations = [];

                if(count != 0) {
                    for (var key in obj) {
                        durations[key] =  obj[key];
                    }
                }

                query = stringify({
                    fieldName : "usernameWithTenantDomainAndUserstoreDomain",
                    categoryPath : [],
                    query: "startTimestamp : [" + 0 + " TO " + timeTo + "] AND (endTimestamp : [" + timeFrom + " TO " + timeNow + "] OR isActive:true)" + tenantFilter ,
                    scoreFunction : 1,
                    start: 0,
                    count: 1000000
                });

                resp = connector.drillDownCategories(superTenantId, tableName, query);
                var dataPoints = JSON.parse(resp.getMessage());
                var obj = dataPoints.categories;
                var count = Object.keys(obj).length;

                if(count != 0) {
                    for (var key in obj) {
                        if(durations[key]) {
                            var totalDuration = durations[key];
                            var username = key;
                            var duration = totalDuration / obj[key];
                            data.push({
                                "username": username + "",
                                "duration": duration / 1000
                            });
                        }
                    }
                }

                var count = Object.keys(data).length;

                var insert = function (array, rightIndex, value) {
                    for (var j = rightIndex; j > 0 && array[j - 1]["duration"] < value["duration"]; j--) {
                        array[j] = array[j - 1];
                    }
                    array[j] = value;
                };

                for (var i = 0; i < data.length; i++) {
                    insert(data, i, data[i]);
                }

                result.push(data.slice(start, start + length));
                result.push(count);
                break;
            }
            case TYPE_SESSION_COUNT_OVER_TIME:
            {
                result = [];
                dataPointsArray = [];
                var start = parseInt(request.getParameter("start"));
                var length = parseInt(request.getParameter("count"));

                var tableName = "ORG_WSO2_IS_ANALYTICS_STREAM_SESSIONINFO";
                timeFrom = timeRangeUtil.getFloorValueForTimeStamp(timeFrom, timeUnit);

                var labels = ["< 15 mins", "< 1 hr", "< 12 hrs", "< 24 hrs", "> 24 hrs"];
                var timeNow = new Date().getTime();

                query = stringify({
                    tableName: tableName,
                    rangeField: "duration",
                    "ranges":[
                        {
                            "label":"< 15 mins",
                            "from":0,
                            "to":900001
                        },
                        {
                            "label":"< 1 hr",
                            "from":900001,
                            "to":3600001
                        },
                        {
                            "label":"< 12 hrs",
                            "from":3600001,
                            "to":43200001
                        },
                        {
                            "label":"< 24 hrs",
                            "from":43200001,
                            "to":86400001
                        },
                        {
                            "label":"> 24 hrs",
                            "from":86400001,
                            "to":9223372036854775808
                        }
                    ],
                    query: "startTimestamp : [" + 0 + " TO " + timeTo + "] AND (endTimestamp : [" + timeFrom + " TO " + timeNow + "] OR isActive:true)" + tenantFilter
                });

                resp = connector.drillDownRangeCount(superTenantId, tableName, query);
                var dataPoints = JSON.parse(resp.getMessage());

                for (var i=0; i<dataPoints.length; i++) {
                    dataPointsArray.push({
                        "duration": dataPoints[i].label,
                        "sessionCount": dataPoints[i].count
                    });
                }

                result.push(dataPointsArray);
                result.push(dataPoints.length);
                break;
            }
            case TYPE_SESSION_USERNAME_LIST:
            {
                result = [];
                dataPointsArray = [];

                if (timeUnit == "SECOND" || timeUnit == "MINUTE") {
                    timeUnit = "HOUR";
                } else if (timeUnit == "MONTH" || timeUnit == "YEAR") {
                    timeUnit = "DAY";
                }

                var tableName = "ORG_WSO2_IS_ANALYTICS_STREAM_SESSIONINFO";
                timeFrom = timeRangeUtil.getFloorValueForTimeStamp(timeFrom, timeUnit);
                var timeNow = new Date().getTime();

                query = stringify({
                    fieldName: "username", //field which is indexed as a FACET
                    categoryPath: [], //Path being drilled down, optional
                    query: "startTimestamp : [" + 0 + " TO " + timeTo + "] AND (endTimestamp : [" + timeFrom + " TO " + timeNow + "] OR isActive:true)" + tenantFilter,
                });

                resp = connector.drillDownCategories(superTenantId, tableName, query);

                var dataPoints = JSON.parse(resp.getMessage());

                var obj = dataPoints.categories;

                for (var key in obj) {
                    if (obj.hasOwnProperty(key)) {
                        result.push({
                            "username": key
                        });
                    }
                }
                break;
            }
            case TYPE_SESSION_CHANGE_OVER_TIME:
            {
                result = [];
                var data = [];
                dataPointsArray = [];
                var start = parseInt(request.getParameter("start"));
                var length = parseInt(request.getParameter("count"));

                if (timeUnit == "SECOND") {
                    timeUnit = "MINUTE";
                } else if (timeUnit == "YEAR") {
                    timeUnit == "MONTH";
                }

                // querying for session change
                var tableName = "ORG_WSO2_IS_ANALYTICS_STREAM_SESSIONSTATPER" + timeUnit;
                timeFrom = timeRangeUtil.getFloorValueForTimeStamp(timeFrom, timeUnit);

                query = stringify({
                    query: "bucketStart : [" + timeFrom + " TO " + timeTo + "]" + tenantFilter,
                    start: start,
                    count: length,
                    "sortBy": [
                        {
                            "field": "bucketStart",
                            "sortType": "ASC"
                        }
                    ]
                });

                var resp = connector.search(superTenantId, tableName, query);
                var dataPoints = JSON.parse(resp.getMessage());
                var count = connector.searchCount(superTenantId, tableName, query);

                for (i = 0; i < dataPoints.length; i++) {
                    var temp = [];
                    if (dataPoints[i] != null) {
                        var timestamp = dataPoints[i]["values"]["bucketId"];
                        var activeSessionCount = dataPoints[i]["values"]["activeSessionCount"];
                        var newSessionCount = dataPoints[i]["values"]["newSessionCount"];
                        var terminatedSessionCount = dataPoints[i]["values"]["terminatedSessionCount"];

                        data.push({
                            "timestamp": Number(timestamp),
                            "sessionCount": activeSessionCount,
                            "sessionType": "Active"
                        });
                        data.push({
                            "timestamp": Number(timestamp),
                            "sessionCount": newSessionCount,
                            "sessionType": "New"
                        });
                        data.push({
                            "timestamp": Number(timestamp),
                            "sessionCount": terminatedSessionCount,
                            "sessionType": "Terminated"
                        });
                    }
                }

                if(dataPoints.length > 0 && !common.isStartTimestampDataAvailable(timeFrom, dataPoints[0]["values"]["bucketId"], timeUnit)) {
                    data.unshift({
                        "timestamp": timeFrom,
                        "sessionCount": 0,
                        "sessionType": "Active"
                    });
                    data.unshift({
                        "timestamp": timeFrom,
                        "sessionCount": 0,
                        "sessionType": "New"
                    });
                    data.unshift({
                        "timestamp": timeFrom,
                        "sessionCount": 0,
                        "sessionType": "Terminated"
                    });
                }
                if(dataPoints.length > 0 && !common.isEndTimestampDataAvailable(timeTo, dataPoints[dataPoints.length-1]["values"]["bucketId"], timeUnit)) {
                    data.push({
                        "timestamp": timeTo,
                        "sessionCount": dataPoints[dataPoints.length-1]["values"]["activeSessionCount"],
                        "sessionType": "Active"
                    });
                    data.push({
                        "timestamp": timeTo,
                        "sessionCount": 0,
                        "sessionType": "New"
                    });
                    data.push({
                        "timestamp": timeTo,
                        "sessionCount": 0,
                        "sessionType": "Terminated"
                    });
                }

                result.push(data);

                 // querying for active session count
                var tableNameActiveSessions = "ORG_WSO2_IS_ANALYTICS_STREAM_ACTIVESESSIONS";

                queryActiveSessions = stringify({
                    query: "meta_tenantId : [ "+ tenantId +" TO " +tenantId + " ]",
                    start: start,
                    count: length
                });

                var respActiveCount = connector.searchCount(superTenantId, tableNameActiveSessions, queryActiveSessions);
		        if(respActiveCount.status == "success"){
                    var activeCount = JSON.parse(respActiveCount.getMessage());
		            result.push({
                        "activeCount": activeCount,
                        "timeUnit":timeUnit
            	    });

		        }else{
                    result.push([]);
		        }
                break;
            }
            case TYPE_SESSION_DATA_TABLE:
            {

                var columns = ["sessionId", "username", "startTimestamp", "terminationTimestamp", "endTimestamp", "duration",
                    "isActive", "userstoreDomain", "tenantDomain", "remoteIp", "rememberMeFlag", "_timestamp"];
                var result = {};
                var data = [];
                var start = parseInt(request.getParameter("start"));
                var length = parseInt(request.getParameter("length"));
                var draw = request.getParameter("draw");
                var searchValue = request.getParameter("search[value]");
                var usernameFilter = "";
                if(searchValue != "") {
                    usernameFilter = "AND username:" + searchValue + "*";
                }



                var tableName = "ORG_WSO2_IS_ANALYTICS_STREAM_SESSIONINFO";
                timeFrom = timeRangeUtil.getFloorValueForTimeStamp(timeFrom, timeUnit);

                var query;
                if(request.getParameter("order[0][column]") != null) {
                    var sortByColumnNo = parseInt(request.getParameter("order[0][column]"));
                    var sortType = request.getParameter("order[0][dir]").toUpperCase();
                    query = stringify({
                        "query": "_timestamp : [" + timeFrom + " TO " + timeTo + "]" + tenantFilter + usernameFilter,
                        "start": start,
                        "count": length,
                        "sortBy": [
                            {
                                "field": columns[sortByColumnNo],
                                "sortType": sortType
                            }
                        ]
                    });
                } else {
                    query = stringify({
                        "query": "_timestamp : [" + timeFrom + " TO " + timeTo + "]" + tenantFilter + usernameFilter,
                        "start": start,
                        "count": length
                    });
                }


                var resp = connector.search(superTenantId, tableName, query);
                var dataPoints = JSON.parse(resp.getMessage());

                var count = connector.searchCount(superTenantId, tableName, query);
                var limit = count.getMessage();

                for (i = 0; i < dataPoints.length; i++) {
                    var temp = [];

                    for (j = 0; j < columns.length; j++) {
                        var column = columns[j];
                        if (dataPoints[i] != null) {
                            if (column == "startTimestamp") {
                                var value = dataPoints[i]["values"]["startTimestamp"];
                                var date = new Date(value);
                                temp.push(date.toLocaleString());
                            } else if (column == "terminationTimestamp") {
                                var value = dataPoints[i]["values"]["terminationTimestamp"];
                                var date = new Date(value);
                                temp.push(date.toLocaleString());
                            } else if (column == "endTimestamp") {
                                var value = dataPoints[i]["values"]["endTimestamp"];
                                if (value == -1) {
                                    temp.push("Live");
                                } else {
                                    var date = new Date(value);
                                    temp.push(date.toLocaleString());
                                }
                            } else if (column == "_timestamp") {
                                var value = dataPoints[i]["timestamp"];
                                var date = new Date(value);
                                temp.push(date.toLocaleString());
                            } else {
                                var value = dataPoints[i]["values"][column];
                                temp.push(value);
                            }
                        }
                    }
                    data.push(temp);
                }

                result["draw"] = draw;
                result["data"] = data;

                if (dataPoints.length < length) {
                    limit = start + dataPoints.length;
                }
                result["recordsFiltered"] = limit;
                result["recordsTotal"] = limit;
                break;
            }
            default:
            {
                result = '{ "status": "Failed", "message": "Unidentified operation" }';
            }
        }

        if (result != null) {
            if (log.isDebugEnabled()) {
                log.debug("value of result: " + result);
            }
            var finalResult;
            if (type == TYPE_SESSION_DATA_TABLE) {
                finalResult = result;
            } else {
                finalResult = {
                    status: "success",
                    message: result
                }
            }
            print(finalResult);
        }
    }
    else {
        print('{ "status": "Failed", "statusCode": "500", "message": "AnalyticsCachedWebServiceConnector is unavailable" }');
    }
}());

%>