<%
/**
 *  Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 *  WSO2 Inc. licenses this file to you 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.
 *
 */
(function () {
    var TYPE = "type";
    var TABLE_NAME = "tableName";
    var TIME_FROM = "timeFrom";
    var TIME_TO = "timeTo";
    var START = "start";
    var COUNT = "count";
    var RECORDSTORE_NAME = "recordStore";
    var HTTPS_TRANSPORT = "https";
    var CONTENT_TYPE_JSON = "application/json";
    var AUTHORIZATION_HEADER = "Authorization";
    var USER_TOKEN = "user";
    var TENANT_DOMAIN = "domain";
    var CONST_AT = "@";
    var USERNAME = "username";
    var WAIT_TIME = "waitTime";
    var LOCALHOST = "localhost";
    var HTTP_USER_NOT_AUTHENTICATED = 403;
    var HTTP_INTERNAL_ERROR = 500;
    var MILLISECONDS_PER_SECOND = 1000;
    var JS_MAX_VALUE = "9007199254740992";
    var JS_MIN_VALUE = "-9007199254740992";
    var ZERO_INDEX = "0";
    var LAST_INDEX = "5000";    //Set the max value to 5000. This is to prevent accidental loading of millions of records.
    var TYPE_CLEAR_INDEX_DATA = 1;
    var TYPE_GET_RECORD_COUNT = 6;
    var TYPE_GET_BY_ID = 7;
    var TYPE_GET_BY_RANGE = 8;
    var TYPE_LIST_TABLES = 9;
    var TYPE_GET_SCHEMA = 10;
    var TYPE_SEARCH = 13;
    var TYPE_SEARCH_COUNT = 14;
    var TYPE_SET_SCHEMA = 15;
    var TYPE_TABLE_EXISTS = 16;
    var TYPE_WAIT_FOR_INDEXING = 17;
    var TYPE_PAGINATION_SUPPORTED = 18;
    var TYPE_DRILLDOWN_CATEGORIES = 19;
    var TYPE_DRILLDOWN_SEARCH = 20;
    var TYPE_DRILLDOWN_SEARCH_COUNT = 21;
    var TYPE_ADD_STREAM_DEFINITION = 22;
    var TYPE_GET_STREAM_DEFINITION = 23;
    var TYPE_PUBLISH_EVENTS = 24;
    var TYPE_GET_WITH_KEY_VALUES = 25;
    var TYPE_GET_RECORDSTORES = 26;
    var TYPE_GET_RECORDSTORE_BY_TABLE = 27;
    var TYPE_WAIT_FOR_INDEXING_FOR_TABLE = 28;
    var TYPE_SEARCH_WITH_AGGREGATES = 29;
    var TYPE_REINDEX = 30;
    var TYPE_SEARCH_MULTI_TABLES_WITH_AGGREGATES = 31;
    var TYPE_DRILLDOWN_RANGE_COUNT = 32;
    var log = new Log();
    var carbon = require('carbon');
    var configs = require('/configs/designer.json');
    var utils = require('/modules/utils.js');
    var JSUtils = Packages.org.wso2.carbon.analytics.jsservice.Utils;
    var AnalyticsCachedJSServiceConnector = Packages.org.wso2.carbon.analytics.jsservice.AnalyticsCachedJSServiceConnector;
    var AnalyticsCache = Packages.org.wso2.carbon.analytics.jsservice.AnalyticsCachedJSServiceConnector.AnalyticsCache;
    var cacheTimeoutSeconds = 5;
    var loggedInUser = null;

    if (configs.cacheTimeoutSeconds) {
        cacheTimeoutSeconds = parseInt(configs.cacheTimeoutSeconds);
    }
    var cacheSizeBytes = 1024 * 1024 * 1024; // 1GB
    if (configs.cacheSizeBytes) {
        cacheSizeBytes = parseInt(configs.cacheSizeBytes);
    }
    response.contentType = CONTENT_TYPE_JSON;

    var authParam = request.getHeader(AUTHORIZATION_HEADER);
    if (authParam != null) {
        credentials = JSUtils.authenticate(authParam);
        loggedInUser = credentials[0];
    } else {
        var token = session.get(USER_TOKEN);
        if (token != null) {
            loggedInUser = token[USERNAME] + CONST_AT + token[TENANT_DOMAIN];
        } else {
            log.error("user is not authenticated!");
            response.status = HTTP_USER_NOT_AUTHENTICATED;
            print('{ "status": "Failed", "message": "User is not authenticated." }');
            return;
        }
    }

    var cache = application.get("AnalyticsWebServiceCache");
    if (cache == null) {
        cache = new AnalyticsCache(cacheTimeoutSeconds, cacheSizeBytes);
        application.put("AnalyticsWebServiceCache", cache);
    }

    var connector = new AnalyticsCachedJSServiceConnector(cache);

    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;
    }

    var tableName = request.getParameter(TABLE_NAME);
    if (type != TYPE_LIST_TABLES &&
        //        type != TYPE_PUT_RECORDS &&
        type != TYPE_PAGINATION_SUPPORTED &&
        type != TYPE_ADD_STREAM_DEFINITION &&
        type != TYPE_GET_STREAM_DEFINITION &&
        type != TYPE_PUBLISH_EVENTS &&
        type != TYPE_WAIT_FOR_INDEXING &&
        type != TYPE_SEARCH_MULTI_TABLES_WITH_AGGREGATES &&
        type != TYPE_GET_RECORDSTORES) {
        if (tableName == null) {
            log.error("tableName is not provided!");
            response.status = HTTP_INTERNAL_ERROR;
            print('{ "status": "Failed", "message": "Table name param is empty" }');
            return;
        }
    }

    var content = request.getContent();
    var contentAsString = null;
    if (content != '' && content != null) {
        contentAsString = stringify(content);
        if (log.isDebugEnabled()) {
            log.debug("value of content: " + contentAsString);
        }
    }
    if (connector != null && loggedInUser != null) {
        var result = null;
        switch (type) {
            case TYPE_LIST_TABLES:
            {
                result = connector.getTableList(loggedInUser);
                break;
            }
            case TYPE_TABLE_EXISTS:
            {
                result = connector.tableExists(loggedInUser, tableName);
                break;
            }
            case TYPE_GET_BY_RANGE:
            {
                var from = request.getParameter(TIME_FROM);
                if (from == 'undefined') from = JS_MIN_VALUE;
                var to = request.getParameter(TIME_TO);
                if (to == 'undefined') to = JS_MAX_VALUE;
                var start = request.getParameter(START);
                var intStart = ZERO_INDEX;
                if (start != 'undefined' && start != null) {
                    intStart = parseInt(start, 10);
                }
                var count = request.getParameter(COUNT);
                var intCount = LAST_INDEX;
                if (count != 'undefined' && count != null) {
                    intCount = parseInt(count, 10);
                }
                result = connector.getRecordsByRange(loggedInUser, tableName, from, to, intStart, intCount, contentAsString);
                break;
            }
            case TYPE_GET_WITH_KEY_VALUES:
            {
                result = connector.getWithKeyValues(loggedInUser, tableName, contentAsString);
                break;
            }
            case TYPE_GET_BY_ID:
            {
                result = connector.getRecordsByIds(loggedInUser, tableName, contentAsString);
                break;
            }
            case TYPE_GET_RECORD_COUNT:
            {
                result = connector.getRecordCount(loggedInUser, tableName);
                break;
            }
            /*case TYPE_DELETE_BY_RANGE:
             {
             var timeFrom = Long.parseLong(request.getParameter(TIME_FROM));
             var timeTo = Long.parseLong(request.getParameter(TIME_TO));
             print(connector.deleteRecordsByRange(tableName, timeFrom, timeTo));
             break;
             }
             case TYPE_DELETE_BY_ID:
             {
             print(connector.deleteRecordsByIds(tableName, contentAsString));
             break;
             }*/
            case TYPE_CLEAR_INDEX_DATA:
            {
                result = connector.clearIndexData(loggedInUser, tableName);
                break;
            }
            /*case TYPE_PUT_RECORDS:
             {
             print(connector.insertRecords(contentAsString));
             break;
             }*/
            case TYPE_SEARCH_COUNT:
            {
                result = connector.searchCount(loggedInUser, tableName, contentAsString);
                break;
            }
            case TYPE_SEARCH:
            {
                result = connector.search(loggedInUser, tableName, contentAsString);
                break;
            }
            case TYPE_SET_SCHEMA:
            {
                print(connector.setTableSchema(loggedInUser, tableName, contentAsString));
                break;
            }
            case TYPE_GET_SCHEMA:
            {
                result = connector.getTableSchema(loggedInUser, tableName);
                break;
            }
            case TYPE_PAGINATION_SUPPORTED:
            {
                var recordStore = request.getParameter(RECORDSTORE_NAME)
                result = connector.isPaginationSupported(recordStore);
                break;
            }
            case TYPE_WAIT_FOR_INDEXING:
            {
                var waitTimeAsString = request.getParameter(WAIT_TIME);
                var waitTime = -1;
                if (waitTimeAsString != null) {
                    waitTime = parseInt(waitTimeAsString);
                }
                result = connector.waitForIndexing(waitTime * MILLISECONDS_PER_SECOND);
                break;
            }
            case TYPE_WAIT_FOR_INDEXING_FOR_TABLE:
            {
                var waitTimeAsString = request.getParameter(WAIT_TIME);
                var waitTime = -1;
                if (waitTimeAsString != null) {
                    waitTime = parseInt(waitTimeAsString);
                }
                result = connector.waitForIndexing(tableName, waitTime * MILLISECONDS_PER_SECOND);
                break;
            }
            case TYPE_DRILLDOWN_CATEGORIES:
            {
                result = connector.drillDownCategories(loggedInUser, tableName, contentAsString);
                break;
            }
            case TYPE_DRILLDOWN_SEARCH:
            {
                result = connector.drillDownSearch(loggedInUser, tableName, contentAsString);
                break;
            }
            case TYPE_DRILLDOWN_RANGE_COUNT:
            {
                result = connector.drillDownRangeCount(loggedInUser, tableName, contentAsString);
                break;
            }
            case TYPE_DRILLDOWN_SEARCH_COUNT:
            {
                result = connector.drillDownSearchCount(loggedInUser, tableName, contentAsString);
                break;
            }
            case TYPE_ADD_STREAM_DEFINITION:
            {
                result = connector.addStreamDefinition(loggedInUser, contentAsString);
                break;
            }
            case TYPE_GET_STREAM_DEFINITION:
            {
                result = connector.getStreamDefinition(loggedInUser, contentAsString);
                break;
            }
            case TYPE_PUBLISH_EVENTS:
            {
                result = connector.publishEvent(loggedInUser, contentAsString);
                break;
            }
            case TYPE_GET_RECORDSTORES:
            {
                result = connector.getRecordStoreList();
                break;
            }
            case TYPE_GET_RECORDSTORE_BY_TABLE:
            {
                result = connector.getRecordStoreByTable(loggedInUser, tableName);
                break;
            }
            case TYPE_SEARCH_WITH_AGGREGATES:
            {
                result = connector.searchWithAggregates(loggedInUser, tableName, contentAsString);
                break;
            }
            case TYPE_SEARCH_MULTI_TABLES_WITH_AGGREGATES:
            {
                result = connector.searchMultiTablesWithAggregates(loggedInUser, contentAsString);
                break;
            }
            case TYPE_REINDEX:
            {
                var from = request.getParameter(TIME_FROM);
                if (from == 'undefined') from = JS_MIN_VALUE;
                var to = request.getParameter(TIME_TO);
                if (to == 'undefined') to = JS_MAX_VALUE;
                result = connector.reIndex(loggedInUser, tableName, from, to);
                break;
            }
            default:
                response.status = 500;
                result = {
                    status: "Failed",
                    message: "Unidentified operation"
                };
                print(result);
                return;
        }
        if (result != null) {
            if (log.isDebugEnabled()) {
                log.debug("value of result: " + result);
                log.debug("status code: " + result.getstatusCode())
            }
            var statusCode = result.getStatusCode();
            var status = result.getStatus();
            var message = result.getMessage();
            response.status = statusCode;
            var finalResult = {
                status: status,
                message: message
            };
            print(finalResult);
        }
    } else {
        response.status = 500;
        print({status: "Failed", message: "AnalyticsCachedWebServiceConnector is unavailable"});
    }

}());
%>
