/*
 GigE interface wrapper on araviss
 Copyright (C) 2016 Hendrik Beijeman (hbeyeman@gmail.com)

 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 2.1 of the License, or (at your option) any later version.

 This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 Lesser General Public License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
#ifndef CPP_ARV_GENERIC_H
#define CPP_ARV_GENERIC_H

//#extern "C" {
#include <stddef.h>
#include <stdio.h>
#include <arv.h>
//}

#include "ArvInterface.h"

using namespace arv;

class ArvGeneric : public arv::ArvCamera
{
  public:
    ArvGeneric(void *camera_device);
    ~ArvGeneric();

    bool is_connected();
    bool is_exposing();
    bool connect();
    bool disconnect();
    const char *vendor_name();
    const char *model_name();
    const char *device_id();
    int get_frame_byte_size();
    min_max_property<int> get_bin_x();
    min_max_property<int> get_bin_y();
    min_max_property<int> get_x_offset();
    min_max_property<int> get_y_offset();
    min_max_property<int> get_width();
    min_max_property<int> get_height();
    min_max_property<int> get_bpp();
    min_max_property<double> get_pixel_pitch();
    min_max_property<double> get_exposure();
    min_max_property<double> get_gain();
    min_max_property<double> get_frame_rate();

    void set_bin(int const bin_x, int const bin_y);
    void set_geometry(int const x, int const y, int const w, int const h);
    void update_geometry(void);
    void set_exposure_time(double const val);
    void set_gain(double const val);

    void exposure_start(void);
    void exposure_abort(void);
    ARV_EXPOSURE_STATUS exposure_poll(void (*fn_image_callback)(void *const, uint8_t const *const, size_t),
                                      void *const usr_ptr);

  protected:
    void _init(void);
    bool _configure(void);
    void _test_exposure_and_abort(void);
    template <typename T>
    bool _get_bounds(void (*fn_arv_bounds)(::ArvCamera *, T *min, T *max, GError**), min_max_property<T> *prop);
    template <typename T>
    void _set_cam_exposure_property(void (*arv_set)(::ArvCamera *, T, GError**), min_max_property<T> *prop, T const new_val);

    const char *_str_val(const char *s);
    bool _get_initial_config();
    bool _set_initial_config();
    void _get_image(void (*fn_image_callback)(void *const, uint8_t const *const, size_t), void *const usr_ptr);

    /* aravis library state variables */
    ::ArvCamera *camera;
    ::ArvDevice *dev;
    ::ArvStream *stream;
    ::ArvBuffer *buffer;
    ::GError *error;

    /* streaming, capturing functions */
    ::ArvStream *_stream_create(void);
    ::ArvBuffer *_buffer_create(void);
    bool _stream_active();
    void _stream_start();
    void _stream_stop();
    void _trigger_exposure();

    bool stream_active;

    /* Camera properties */
    struct
    {
        min_max_property<gint> bin_x;
        min_max_property<gint> bin_y;
        min_max_property<gint> x_offset;
        min_max_property<gint> y_offset;
        min_max_property<gint> width;
        min_max_property<gint> height;

        min_max_property<double> pixel_pitch;

        min_max_property<double> exposure;
        min_max_property<double> gain;
        min_max_property<double> frame_rate;

        const char *vendor_name;
        const char *model_name;
        const char *device_id;
    } cam;
};

#endif /*CPP_ARV_CAMERA_H*/
