/**
 * @file square_sawtooth.c
 * @brief Example: generate square and sawtooth waves and compare their spectra.
 *
 * This program demonstrates MD_square_wave() and MD_sawtooth_wave() by:
 *   1. Generating a 440 Hz square wave and sawtooth wave (N=4096, fs=44100).
 *   2. Computing their magnitude spectra via MD_magnitude_spectrum().
 *   3. Writing the results to CSV and to an interactive HTML visualisation
 *      (Plotly.js, no server required).
 *
 * Build and run (from the repository root):
 *   make                          # build libminidsp.a first
 *   make -C examples plot         # build example, run it, generate HTML
 *   open examples/square_sawtooth.html
 */

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "minidsp.h"
#include "plot_html.h"

/* -----------------------------------------------------------------------
 * Write the interactive HTML visualisation with both spectra.
 * -----------------------------------------------------------------------*/
static int write_html(const char *path,
                      const double *freqs,
                      const double *sq_mag, const double *saw_mag,
                      unsigned num_bins,
                      double sample_rate, unsigned N,
                      double freq_hz)
{
    FILE *fp = fopen(path, "w");
    if (!fp) {
        fprintf(stderr, "cannot open %s for writing\n", path);
        return -1;
    }

    char subtitle[256];
    snprintf(subtitle, sizeof(subtitle),
        "%.0f Hz fundamental &nbsp;|&nbsp;\n"
        "    sample rate %.0f Hz &nbsp;|&nbsp;\n"
        "    FFT size %u",
        freq_hz, sample_rate, N);

    plot_html_begin(fp, "Square &amp; Sawtooth Wave Spectra", subtitle, 0);

    fprintf(fp,
        "  <div id=\"plot\" class=\"plot-container\"></div>\n"
        "  <div class=\"info\">\n"
        "    <strong>What you are seeing:</strong><br>\n"
        "    <em>Square wave</em> (blue) &mdash; contains only odd harmonics\n"
        "    (1f, 3f, 5f, &hellip;) decaying as 1/<em>k</em>.<br>\n"
        "    <em>Sawtooth wave</em> (orange) &mdash; contains all integer\n"
        "    harmonics (1f, 2f, 3f, &hellip;) decaying as 1/<em>k</em>.<br>\n"
        "    The difference illustrates how waveform shape determines\n"
        "    harmonic content.  Hover for exact values.\n"
        "  </div>\n\n");

    /* ---- Embed spectrum data as JS arrays ---- */
    fprintf(fp, "  <script>\n");
    fprintf(fp, "    // Spectrum data generated by square_sawtooth.c\n");
    plot_html_js_array(fp, "freqs", freqs, num_bins, "%.4f");
    plot_html_js_array(fp, "sqMag", sq_mag, num_bins, "%.8f");
    plot_html_js_array(fp, "sawMag", saw_mag, num_bins, "%.8f");
    fprintf(fp, "\n");

    /* ---- Plotly visualisation ---- */
    fprintf(fp,
        "    Plotly.newPlot('plot', [{\n"
        "      x: freqs, y: sqMag,\n"
        "      type: 'scatter', mode: 'lines',\n"
        "      line: { color: '#2563eb', width: 1.2 },\n"
        "      name: 'Square',\n"
        "      hovertemplate: '%%{x:.1f} Hz<br>Amplitude: %%{y:.6f}<extra>Square</extra>'\n"
        "    }, {\n"
        "      x: freqs, y: sawMag,\n"
        "      type: 'scatter', mode: 'lines',\n"
        "      line: { color: '#ea580c', width: 1.2 },\n"
        "      name: 'Sawtooth',\n"
        "      hovertemplate: '%%{x:.1f} Hz<br>Amplitude: %%{y:.6f}<extra>Sawtooth</extra>'\n"
        "    }], {\n"
        "      title: { text: 'Magnitude Spectra: Square vs Sawtooth (%.0f Hz)', font: { size: 15 } },\n"
        "      xaxis: { title: 'Frequency (Hz)', range: [0, %.1f] },\n"
        "      yaxis: { title: 'Amplitude' },\n"
        "      margin: { t: 55, r: 30, b: 55, l: 65 },\n"
        "      height: 420\n"
        "    }, { responsive: true });\n"
        "  </script>\n",
        freq_hz, sample_rate / 2.0);

    plot_html_end(fp);
    fclose(fp);
    return 0;
}

int main(void)
{
    /* ------------------------------------------------------------------
     * Signal parameters
     * ----------------------------------------------------------------*/
    const unsigned N           = 4096;       /* FFT size (samples)    */
    const double   sample_rate = 44100.0;    /* Hz                    */
    const double   freq_hz     = 440.0;      /* A4 concert pitch      */
    const double   amplitude   = 1.0;
    const unsigned num_bins    = N / 2 + 1;

    /* ------------------------------------------------------------------
     * Generate the waveforms
     * ----------------------------------------------------------------*/
    double *sq_sig  = malloc(N * sizeof(double));
    double *saw_sig = malloc(N * sizeof(double));
    double *sq_mag  = malloc(num_bins * sizeof(double));
    double *saw_mag = malloc(num_bins * sizeof(double));
    double *freqs   = malloc(num_bins * sizeof(double));

    if (!sq_sig || !saw_sig || !sq_mag || !saw_mag || !freqs) {
        fprintf(stderr, "allocation failed\n");
        return 1;
    }

    //! [generate-square]
    MD_square_wave(sq_sig, N, amplitude, freq_hz, sample_rate);
    //! [generate-square]

    //! [generate-sawtooth]
    MD_sawtooth_wave(saw_sig, N, amplitude, freq_hz, sample_rate);
    //! [generate-sawtooth]

    /* ------------------------------------------------------------------
     * Compute magnitude spectra
     * ----------------------------------------------------------------*/
    MD_magnitude_spectrum(sq_sig, N, sq_mag);
    MD_magnitude_spectrum(saw_sig, N, saw_mag);

    /* Convert to single-sided amplitude spectra */
    for (unsigned k = 0; k < num_bins; k++) {
        freqs[k] = (double)k * sample_rate / (double)N;
        sq_mag[k]  /= (double)N;
        saw_mag[k] /= (double)N;
        if (k > 0 && k < N / 2) {
            sq_mag[k]  *= 2.0;
            saw_mag[k] *= 2.0;
        }
    }

    /* ------------------------------------------------------------------
     * Write results to CSV
     * ----------------------------------------------------------------*/
    const char *csv_file = "square_sawtooth.csv";
    FILE *fp = fopen(csv_file, "w");
    if (!fp) {
        fprintf(stderr, "cannot open %s for writing\n", csv_file);
        return 1;
    }

    fprintf(fp, "bin,frequency_hz,square_magnitude,sawtooth_magnitude\n");
    for (unsigned k = 0; k < num_bins; k++)
        fprintf(fp, "%u,%.4f,%.8f,%.8f\n", k, freqs[k], sq_mag[k], saw_mag[k]);
    fclose(fp);

    printf("Wrote %u frequency bins to %s\n", num_bins, csv_file);

    /* ------------------------------------------------------------------
     * Write interactive HTML visualisation
     * ----------------------------------------------------------------*/
    const char *html_file = "square_sawtooth.html";
    if (write_html(html_file, freqs, sq_mag, saw_mag, num_bins,
                   sample_rate, N, freq_hz) == 0) {
        printf("Wrote interactive plot to %s\n", html_file);
    }

    printf("Signals: %.0f Hz square & sawtooth, amplitude %.1f\n",
           freq_hz, amplitude);
    printf("Sample rate: %.0f Hz, FFT size: %u\n", sample_rate, N);

    /* ------------------------------------------------------------------
     * Cleanup
     * ----------------------------------------------------------------*/
    free(freqs);
    free(saw_mag);
    free(sq_mag);
    free(saw_sig);
    free(sq_sig);
    MD_shutdown();

    return 0;
}
