//------------------------------------------------------------------------
//  Copyright 2007-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
//
//  This file is part of the ZBar Bar Code Reader.
//
//  The ZBar Bar Code Reader is free software; you can redistribute it
//  and/or modify it under the terms of the GNU Lesser Public License as
//  published by the Free Software Foundation; either version 2.1 of
//  the License, or (at your option) any later version.
//
//  The ZBar Bar Code Reader 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 Public License for more details.
//
//  You should have received a copy of the GNU Lesser Public License
//  along with the ZBar Bar Code Reader; if not, write to the Free
//  Software Foundation, Inc., 51 Franklin St, Fifth Floor,
//  Boston, MA  02110-1301  USA
//
//  http://sourceforge.net/projects/zbar
//------------------------------------------------------------------------
#ifndef _ZBAR_VIDEO_H_
#define _ZBAR_VIDEO_H_

/// @file
/// Video Input C++ wrapper

#ifndef _ZBAR_H_
#error "include zbar.h in your application, **not** zbar/Video.h"
#endif

#include "Image.h"

namespace zbar
{
/// mid-level video source abstraction.
/// captures images from a video device

class Video
{
public:
    /// constructor.
    Video(zbar_video_t *video = NULL)
    {
	if (video)
	    _video = video;
	else
	    _video = zbar_video_create();
    }

    /// constructor.
    Video(std::string &device)
    {
	_video = zbar_video_create();
	open(device);
    }

    ~Video()
    {
	zbar_video_destroy(_video);
    }

    /// cast to C video object.
    operator zbar_video_t *() const
    {
	return (_video);
    }

    /// open and probe a video device.
    void open(std::string &device)
    {
	if (zbar_video_open(_video, device.c_str()))
	    throw_exception(_video);
    }

    /// close video device if open.
    void close()
    {
	if (zbar_video_open(_video, NULL))
	    throw_exception(_video);
    }

    /// initialize video using a specific format for debug.
    /// see zbar_video_init()
    void init(unsigned long fourcc)
    {
	if (zbar_video_init(_video, fourcc))
	    throw_exception(_video);
    }

    /// initialize video using a specific format for debug.
    /// see zbar_video_init()
    void init(std::string &format)
    {
	unsigned int fourcc = zbar_fourcc_parse(format.c_str());
	if (zbar_video_init(_video, fourcc))
	    throw_exception(_video);
    }

    /// retrieve file descriptor associated with open *nix video device.
    /// see zbar_video_get_fd()
    int get_fd()
    {
	return (zbar_video_get_fd(_video));
    }

    /// retrieve current output image width.
    /// see zbar_video_get_width()
    int get_width()
    {
	return (zbar_video_get_width(_video));
    }

    /// retrieve current output image height.
    /// see zbar_video_get_height()
    int get_height()
    {
	return (zbar_video_get_height(_video));
    }

    /// start/stop video capture.
    /// see zbar_video_enable()
    void enable(bool enable = true)
    {
	if (zbar_video_enable(_video, enable))
	    throw_exception(_video);
    }

    /// retrieve next captured image.
    /// see zbar_video_next_image()
    Image next_image()
    {
	zbar_image_t *img = zbar_video_next_image(_video);
	if (!img)
	    throw_exception(_video);
	return (Image(img));
    }

    /// request a preferred size for the video image from the device.
    /// see zbar_video_request_size()
    /// @since 0.6
    void request_size(int width, int height)
    {
	zbar_video_request_size(_video, width, height);
    }

    /// request a preferred driver interface version for debug/testing.
    /// see zbar_video_request_interface()
    /// @since 0.6
    void request_interface(int version)
    {
	zbar_video_request_interface(_video, version);
    }

    /// request a preferred I/O mode for debug/testing.
    /// see zbar_video_request_iomode()
    /// @since 0.7
    void request_iomode(int iomode)
    {
	if (zbar_video_request_iomode(_video, iomode))
	    throw_exception(_video);
    }

    /// get the information about a control at a given index
    /// see zbar_video_get_controls()
    /// @since 0.11
    struct video_controls_s *get_controls(int index)
    {
	return (zbar_video_get_controls(_video, index));
    }

    /// set the value on an integer control
    /// see zbar_video_set_control_n()
    /// @since 0.11
    int set_control(const char *name, int value)
    {
	return zbar_video_set_control(_video, name, value);
    }

    /// set the value on a boolean control
    /// see zbar_video_set_control_b()
    /// @since 0.11
    int set_control(const char *name, bool value)
    {
	return zbar_video_set_control(_video, name, value ? 1 : 0);
    }

    /// get the value on a boolean control
    /// see zbar_video_get_control_b()
    /// @since 0.11
    int get_control(const char *name, int *value)
    {
	return zbar_video_get_control(_video, name, value);
    }

    /// get the value on an integer control
    /// see zbar_video_get_control_n()
    /// @since 0.11
    int get_control(const char *name, bool *value)
    {
	int __value;
	int ret = zbar_video_get_control(_video, name, &__value);

	*value = __value ? true : false;

	return ret;
    }

    /// get the information about a control at a given index
    /// see zbar_video_get_resolutions()
    /// @since 0.22
    struct video_resolution_s *get_resolution(int index)
    {
	return (zbar_video_get_resolutions(_video, index));
    }

private:
    zbar_video_t *_video;
};

} // namespace zbar

#endif
