/*
 * Copyright (C) 2013-2014 The Android Open Source Project
 *
 * 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.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <benchmark/benchmark.h>

static const char begin[] = "--------- beginning of ";

static void BM_logcat_sorted_order(benchmark::State& state) {
    FILE* fp;

    if (!state.KeepRunning()) return;

    fp = popen(
        "logcat -v time -b radio -b events -b system -b main -d 2>/dev/null",
        "r");
    if (!fp) return;

    class timestamp {
       private:
        int month;
        int day;
        int hour;
        int minute;
        int second;
        int millisecond;
        bool ok;

       public:
        void init(const char* buffer) {
            ok = false;
            if (buffer != NULL) {
                ok = sscanf(buffer, "%d-%d %d:%d:%d.%d ", &month, &day, &hour,
                            &minute, &second, &millisecond) == 6;
            }
        }

        explicit timestamp(const char* buffer) {
            init(buffer);
        }

        bool operator<(timestamp& T) {
            return !ok || !T.ok || (month < T.month) ||
                   ((month == T.month) &&
                    ((day < T.day) ||
                     ((day == T.day) &&
                      ((hour < T.hour) ||
                       ((hour == T.hour) &&
                        ((minute < T.minute) ||
                         ((minute == T.minute) &&
                          ((second < T.second) ||
                           ((second == T.second) &&
                            (millisecond < T.millisecond))))))))));
        }

        bool valid(void) {
            return ok;
        }
    } last(NULL);

    char* last_buffer = NULL;
    char buffer[5120];

    int count = 0;
    int next_lt_last = 0;

    while (fgets(buffer, sizeof(buffer), fp)) {
        if (!strncmp(begin, buffer, sizeof(begin) - 1)) {
            continue;
        }
        if (!last.valid()) {
            free(last_buffer);
            last_buffer = strdup(buffer);
            last.init(buffer);
        }
        timestamp next(buffer);
        if (next < last) {
            if (last_buffer) {
                fprintf(stderr, "<%s", last_buffer);
            }
            fprintf(stderr, ">%s", buffer);
            ++next_lt_last;
        }
        if (next.valid()) {
            free(last_buffer);
            last_buffer = strdup(buffer);
            last.init(buffer);
        }
        ++count;
    }
    free(last_buffer);

    pclose(fp);

    static const int max_ok = 2;

    // Allow few fails, happens with readers active
    fprintf(stderr, "%s: %d/%d out of order entries\n",
            (next_lt_last) ? ((next_lt_last <= max_ok) ? "WARNING" : "ERROR")
                           : "INFO",
            next_lt_last, count);

    if (next_lt_last > max_ok) {
        fprintf(stderr, "EXPECT_GE(max_ok=%d, next_lt_last=%d)\n", max_ok,
                next_lt_last);
    }

    // sample statistically too small
    if (count < 100) {
        fprintf(stderr, "EXPECT_LT(100, count=%d)\n", count);
    }

    state.KeepRunning();
}
BENCHMARK(BM_logcat_sorted_order);

BENCHMARK_MAIN();
