// This file is part of fityk program. Copyright (C) Marcin Wojdyr
// Licence: GNU General Public License version 2
// $Id: gnuplot.cpp 322 2007-07-24 00:17:11Z wojdyr $

// CLI-only file

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fstream>
#include <string>
#include <sys/types.h>
#include <signal.h>
#include <errno.h>

#include "gnuplot.h"
#include "../common.h"
#include "../data.h"
#include "../sum.h"
#include "../logic.h"
#include "../ui.h"

using namespace std;

extern Ftk* ftk;

char GnuPlot::path_to_gnuplot[]="gnuplot";

GnuPlot::GnuPlot()
{
    fork_and_make_pipe ();
}

GnuPlot::~GnuPlot() 
{
    fclose(gnuplot_pipe);  //it closes gnuplot
}

void GnuPlot::fork_and_make_pipe ()
{
    int     fd[2];
    pid_t   childpid;
    pipe(fd);
    if ((childpid = fork()) == -1) {
        perror("fork");
        exit(1);
    }

    if (childpid == 0) {
        // Child process closes up output side of pipe 
        close (fd[1]);
        // and input side is stdin
        dup2 (fd[0], 0);
        if (fd[0] > 2)
            close (fd[0]);
        //putenv("PAGER="); //putenv() - POSIX, not ANSI
        execlp (path_to_gnuplot, path_to_gnuplot, /*"-",*/NULL);
        // if we are here, sth went wrong
        ftk->warn("Problem encountered when trying to run `" 
                 + S(path_to_gnuplot) + "'.");
        exit(0);
    }
    else {
        // Parent process closes up input side of pipe 
        close (fd[0]);
        gnuplot_pipe  = fdopen (fd[1], "w"); //fdopen() - POSIX, not ANSI
    }
}

bool GnuPlot::gnuplot_pipe_ok()
{
    static bool give_up = false;
    if (give_up) 
        return false;
    //sighandler_t and sig_t are not portable
    typedef void (*my_sighandler_type) (int);
    my_sighandler_type shp = signal (SIGPIPE, SIG_IGN);
    errno = 0;
    fprintf (gnuplot_pipe, " "); //pipe test
    fflush(gnuplot_pipe);
    if (errno == EPIPE) {
        errno = 0;
        fork_and_make_pipe();
        signal (SIGPIPE, SIG_IGN);
        fprintf (gnuplot_pipe, " "); //test again
        fflush(gnuplot_pipe);
        if (errno == EPIPE) {
            give_up = true;
            signal (SIGPIPE, shp);
            return false;
        }
    }                    
    signal (SIGPIPE, shp);
    return true;
}

int GnuPlot::plot() 
{
    // plot only active data with sum
    DataWithSum const* ds = ftk->get_ds(ftk->get_active_ds_position());
    Data const* data = ds->get_data();
    Sum const* sum = ds->get_sum();
    if (!gnuplot_pipe_ok())
        return -1;
    // Send commands through the pipe to gnuplot
    int i_f = data->get_lower_bound_ac (ftk->view.left);
    int i_l = data->get_upper_bound_ac (ftk->view.right);
    if (i_l - i_f <= 0) 
        return 0;
    string plot_string = "plot "+ ftk->view.str() 
        + " \'-\' title \"data\", ";
    plot_string += " '-' title \"sum\" with line\n ";
    fprintf (gnuplot_pipe, plot_string.c_str());
    if (fflush (gnuplot_pipe) != 0)
        ftk->warn("Flushing pipe program-to-gnuplot failed.");
    bool at_least_one_point = false;
    for (int i = i_f; i < i_l; i++) {
        fp x = data->get_x(i);
        fp y = data->get_y(i);
        if (is_finite(x) && is_finite(y)) {
            fprintf(gnuplot_pipe, "%f  %f\n", x, y);
            at_least_one_point = true;
        }
    }
    if (!at_least_one_point)
        fprintf(gnuplot_pipe, "0.0  0.0\n");
    fprintf (gnuplot_pipe, "e\n");//gnuplot needs 'e' at the end of data
    for (int i = i_f; i < i_l; i++) {
        fp x = data->get_x(i);
        fp y = sum->value(x);
        if (is_finite(x) && is_finite(y))
            fprintf(gnuplot_pipe, "%f  %f\n", x, y);
    }
    fprintf(gnuplot_pipe, "e\n");
    fflush(gnuplot_pipe);
    return 0;
}



syntax highlighted by Code2HTML, v. 0.9.1