/* Copyright (C) 2022-2023 Salvatore Sanfilippo -- All Rights Reserved
 * See the LICENSE file for information about the license. */

#include "app.h"

/* Render the received signal.
 *
 * The screen of the flipper is 128 x 64. Even using 4 pixels per line
 * (where low level signal is one pixel high, high level is 4 pixels
 * high) and 4 pixels of spacing between the different lines, we can
 * plot comfortably 8 lines.
 *
 * The 'idx' argument is the first sample to render in the circular
 * buffer. */
void render_signal(ProtoViewApp* app, Canvas* const canvas, RawSamplesBuffer* buf, uint32_t idx) {
    canvas_set_color(canvas, ColorBlack);

    int rows = 8;
    uint32_t time_per_pixel = app->us_scale;
    uint32_t start_idx = idx;
    bool level = 0;
    uint32_t dur = 0, sample_num = 0;
    for(int row = 0; row < rows; row++) {
        for(int x = 0; x < 128; x++) {
            int y = 3 + row * 8;
            if(dur < time_per_pixel / 2) {
                /* Get more data. */
                raw_samples_get(buf, idx++, &level, &dur);
                sample_num++;
            }

            canvas_draw_line(canvas, x, y, x, y - (level * 3));

            /* Write a small triangle under the last sample detected. */
            if(app->signal_bestlen != 0 && sample_num + start_idx == app->signal_bestlen + 1) {
                canvas_draw_dot(canvas, x, y + 2);
                canvas_draw_dot(canvas, x - 1, y + 3);
                canvas_draw_dot(canvas, x, y + 3);
                canvas_draw_dot(canvas, x + 1, y + 3);
                sample_num++; /* Make sure we don't mark the next, too. */
            }

            /* Remove from the current level duration the time we
             * just plot. */
            if(dur > time_per_pixel)
                dur -= time_per_pixel;
            else
                dur = 0;
        }
    }
}

/* Raw pulses rendering. This is our default view. */
void render_view_raw_pulses(Canvas* const canvas, ProtoViewApp* app) {
    /* Show signal. */
    render_signal(app, canvas, DetectedSamples, app->signal_offset);

    /* Show signal information. */
    char buf[64];
    snprintf(buf, sizeof(buf), "%luus", (unsigned long)DetectedSamples->short_pulse_dur);
    canvas_set_font(canvas, FontSecondary);
    canvas_draw_str_with_border(canvas, 97, 63, buf, ColorWhite, ColorBlack);
    if(app->signal_decoded) {
        canvas_set_font(canvas, FontPrimary);
        canvas_draw_str_with_border(
            canvas, 1, 61, app->msg_info->decoder->name, ColorWhite, ColorBlack);
    }
}

/* Handle input for the raw pulses view. */
void process_input_raw_pulses(ProtoViewApp* app, InputEvent input) {
    if(input.type == InputTypeRepeat) {
        /* Handle panning of the signal window. Long pressing
         * right will show successive samples, long pressing left
         * previous samples. */
        if(input.key == InputKeyRight)
            app->signal_offset++;
        else if(input.key == InputKeyLeft)
            app->signal_offset--;
    } else if(input.type == InputTypeLong) {
        if(input.key == InputKeyOk) {
            /* Reset the current sample to capture the next. */
            reset_current_signal(app);
        }
    } else if(input.type == InputTypeShort) {
        if(input.key == InputKeyOk) {
            app->signal_offset = 0;
            adjust_raw_view_scale(app, DetectedSamples->short_pulse_dur);
        } else if(input.key == InputKeyDown) {
            /* Rescaling. The set becomes finer under 50us per pixel. */
            uint32_t scale_step = app->us_scale >= 50 ? 50 : 10;
            if(app->us_scale < 500) app->us_scale += scale_step;
        } else if(input.key == InputKeyUp) {
            uint32_t scale_step = app->us_scale > 50 ? 50 : 10;
            if(app->us_scale > 10) app->us_scale -= scale_step;
        }
    }
}

/* Adjust raw view scale depending on short pulse duration. */
void adjust_raw_view_scale(ProtoViewApp* app, uint32_t short_pulse_dur) {
    if(short_pulse_dur == 0)
        app->us_scale = PROTOVIEW_RAW_VIEW_DEFAULT_SCALE;
    else if(short_pulse_dur < 75)
        app->us_scale = 10;
    else if(short_pulse_dur < 145)
        app->us_scale = 30;
    else if(short_pulse_dur < 400)
        app->us_scale = 100;
    else if(short_pulse_dur < 1000)
        app->us_scale = 200;
    else
        app->us_scale = PROTOVIEW_RAW_VIEW_DEFAULT_SCALE;
}