/** @file  pmAstrometryWCS.c
 *
 *  @brief functions to convert FITS WCS keywords to / from pmFPA structures
 *
 *  @ingroup Astrometry
 *
 *  @author EAM, IfA
 *
 *  @version $Revision: 1.7.2.1 $ $Name: not supported by cvs2svn $
 *  @date $Date: 2007-03-02 14:18:40 $
 *
 *  Copyright 2006 Institute for Astronomy, University of Hawaii
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <pslib.h>
#include "pmKapaPlots.h"

// the top portion of this file defines plotting functions which use kapa for plotting.
// if kapa is not available, these functions are defined in the bottom portion as stubs
// which perform NOP and return false (XXX should this be 'true' ??)

# if (HAVE_KAPA)

    // XXX not thread safe (perhaps not needed)
    // to make this thread safe, we could check the thread ID and tie to it
    static int kapa_fd = -1;

int pmKapaOpen (bool showWindow)
{
    char kapa[64];

    if (showWindow) {
        strcpy (kapa, "kapa");
    } else {
        strcpy (kapa, "kapa -noX");
    }

    if (kapa_fd == -1) {
        kapa_fd = KapaOpen (kapa, "psphot");
    }
    return kapa_fd;
}

bool pmKapaClose ()
{

    if (kapa_fd == -1)
        return true;
    KapaClose (kapa_fd);
    kapa_fd = -1;
    return true;
}

bool pmKapaPlotVectorPair_AutoLimits_OpenGraph (int kapa, Graphdata *graphdata, psVector *xVec, psVector *yVec)
{

    // set limits based on data values
    graphdata->xmin = FLT_MAX;
    graphdata->xmax = FLT_MIN;
    graphdata->ymin = FLT_MAX;
    graphdata->ymax = FLT_MIN;
    for (int i = 0; i < xVec->n; i++) {
        graphdata->xmin = PS_MIN (graphdata->xmin, xVec->data.F32[i]);
        graphdata->xmax = PS_MAX (graphdata->xmax, xVec->data.F32[i]);
        graphdata->ymin = PS_MIN (graphdata->ymin, yVec->data.F32[i]);
        graphdata->ymax = PS_MAX (graphdata->ymax, yVec->data.F32[i]);
    }
    // add 5% to range
    float range;

    range = graphdata->xmax - graphdata->xmin;
    graphdata->xmax += 0.05*range;
    graphdata->xmin -= 0.05*range;

    range = graphdata->ymax - graphdata->ymin;
    graphdata->ymax += 0.05*range;
    graphdata->ymin -= 0.05*range;

    KapaSetLimits (kapa, graphdata);
    KapaSetFont (kapa, "helvetica", 14);
    KapaBox (kapa, graphdata);

    KapaPrepPlot (kapa, xVec->n, graphdata);
    KapaPlotVector (kapa, xVec->n, xVec->data.F32);
    KapaPlotVector (kapa, yVec->n, yVec->data.F32);
    return true;
}

bool pmKapaPlotVectorPair (psVector *xVec, psVector *yVec)
{

    Graphdata graphdata;

    int kapa = pmKapaOpen (true);
    if (kapa == -1) {
        psError(PS_ERR_UNKNOWN, true, "failure to open kapa");
        return false;
    }

    if (xVec->n != yVec->n)
        return false;

    KapaInitGraph (&graphdata);
    KapaClear (kapa, TRUE);

    // set limits based on data values
    graphdata.xmin = FLT_MAX;
    graphdata.xmax = FLT_MIN;
    graphdata.ymin = FLT_MAX;
    graphdata.ymax = FLT_MIN;
    for (int i = 0; i < xVec->n; i++) {
        graphdata.xmin = PS_MIN (graphdata.xmin, xVec->data.F32[i]);
        graphdata.xmax = PS_MAX (graphdata.xmax, xVec->data.F32[i]);
        graphdata.ymin = PS_MIN (graphdata.ymin, yVec->data.F32[i]);
        graphdata.ymax = PS_MAX (graphdata.ymax, yVec->data.F32[i]);
    }
    // add 5% to range
    float range;

    range = graphdata.xmax - graphdata.xmin;
    graphdata.xmax += 0.05*range;
    graphdata.xmin -= 0.05*range;

    range = graphdata.ymax - graphdata.ymin;
    graphdata.ymax += 0.05*range;
    graphdata.ymin -= 0.05*range;

    KapaSetLimits (kapa, &graphdata);
    KapaSetFont (kapa, "helvetica", 14);
    KapaBox (kapa, &graphdata);

    graphdata.color = KapaColorByName ("black");
    graphdata.ptype = 0;
    graphdata.size = 0.5;
    graphdata.style = 2;
    KapaPrepPlot (kapa, xVec->n, &graphdata);
    KapaPlotVector (kapa, xVec->n, xVec->data.F32);
    KapaPlotVector (kapa, yVec->n, yVec->data.F32);

    return true;
}

bool pmKapaPlotVectorTriple_AutoLimits_OpenGraph (int kapa, Graphdata *graphdata, psVector *xVec, psVector *yVec, psVector *zVec, bool increasing)
{

    // set limits based on data values
    graphdata->xmin = FLT_MAX;
    graphdata->xmax = FLT_MIN;
    graphdata->ymin = FLT_MAX;
    graphdata->ymax = FLT_MIN;
    float zmin = FLT_MAX;
    float zmax = FLT_MIN;
    for (int i = 0; i < xVec->n; i++) {
        graphdata->xmin = PS_MIN (graphdata->xmin, xVec->data.F32[i]);
        graphdata->xmax = PS_MAX (graphdata->xmax, xVec->data.F32[i]);
        graphdata->ymin = PS_MIN (graphdata->ymin, yVec->data.F32[i]);
        graphdata->ymax = PS_MAX (graphdata->ymax, yVec->data.F32[i]);
        zmin = PS_MIN (zmin, zVec->data.F32[i]);
        zmax = PS_MAX (zmax, zVec->data.F32[i]);
    }
    // add 5% to range
    float range;

    psVector *zScale = psVectorAlloc (zVec->n, PS_DATA_F32);

    range = zmax - zmin;
    if (range == 0.0) {
        psVectorInit (zScale, 1.0);
    } else {
        for (int i = 0; i < zVec->n; i++) {
            if (increasing) {
                zScale->data.F32[i] = PS_MIN (1.5, PS_MAX(0.05, 1.5*(zVec->data.F32[i] - zmin)/range));
            } else {
                zScale->data.F32[i] = PS_MIN (1.5, PS_MAX(0.05, 1.5*(zmax - zVec->data.F32[i])/range));
            }
        }
    }

    range = graphdata->xmax - graphdata->xmin;
    graphdata->xmax += 0.05*range;
    graphdata->xmin -= 0.05*range;

    range = graphdata->ymax - graphdata->ymin;
    graphdata->ymax += 0.05*range;
    graphdata->ymin -= 0.05*range;

    KapaSetLimits (kapa, graphdata);
    KapaSetFont (kapa, "helvetica", 14);
    KapaBox (kapa, graphdata);

    // the point size will be scaled from the z vector
    graphdata->size = -1;
    KapaPrepPlot (kapa, xVec->n, graphdata);
    KapaPlotVector (kapa, xVec->n, xVec->data.F32);
    KapaPlotVector (kapa, yVec->n, yVec->data.F32);
    KapaPlotVector (kapa, zVec->n, zScale->data.F32);
    psFree (zScale);
    return true;
}

# else
    # include "pmKapaPlots.h"

    int pmKapaOpen (bool showWindow)
{
    return -1;
}

bool pmKapaClose ()
{
    return true;
}

bool pmKapaPlotVectorPair (psVector *xVec, psVector *yVec)
{
    return false;
}

bool pmKapaPlotVectorPair_AutoLimits_OpenGraph (int kapa, void *graphdata, psVector *xVec, psVector *yVec)
{
    return false;
}

bool pmKapaPlotVectorTriple_AutoLimits_OpenGraph (int kapa, void *graphdata, psVector *xVec, psVector *yVec, psVector *zVec, bool increasing)
{
    return false;
}
# endif
