/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#+
#+     Internet Radio Automation & Encoding Toolkit
#+
#+     Copyright (C) 2018, 2019, 2020, 2021 by Kevin C. O'Kane
#+
#+     Kevin C. O'Kane
#+     kc.okane@gmail.com
#+     https://www.cs.uni.edu/~okane
#+     https://threadsafebooks.com/
#+
#+ This program is free software; you can redistribute it and/or modify
#+ it under the terms of the GNU General Public License as published by
#+ the Free Software Foundation; either version 2 of the License, or
#+ (at your option) any later version.
#+
#+ This program 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 General Public License for more details.
#+
#+ You should have received a copy of the GNU General Public License
#+ along with this program; if not, write to the Free Software
#+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#+
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

//	May 30, 2021

//------------------------------------------------------------------
//	This is the root file for the Linux version of the player
//------------------------------------------------------------------

#define _GNU_SOURCE

#include "includes.h"
#include "../common/common-externs.h"


#define SLASH '/'

#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/videodev2.h>
#include <string.h>
#include <sys/mman.h>

static void* buffer_start = NULL;
static struct v4l2_buffer bufferinfo;
static int fd;

int	cam_start() {

	static int flag = 0;

	if (flag) goto grab;

	flag = 1;

	if( (fd = open("/dev/video0", O_RDWR)) < 0) {
		perror("open");
		return 0;
		}

	static struct v4l2_capability cap;

	if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0) {
		perror("VIDIOC_QUERYCAP");
		return 0;
		}

	if(!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
		fprintf(stderr, "The device does not handle single-planar video capture.\n");
		return 0;
		}

	printf("Video card detected: %s\n", cap.card);

	static struct v4l2_format format;

//----------------------------------------------------------
//	v4l2-ctl -d /dev/video0 --list-formats-ext > modes
//----------------------------------------------------------

	format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

	if(ioctl(fd, VIDIOC_G_FMT, &format) < 0) { // get format
		perror("VIDIOC_G_FMT");
		return 0;
		}

	printf("width %d\n", format.fmt.pix.width);
	printf("height %d\n", format.fmt.pix.height);
	printf("colorspace %d\n", format.fmt.pix.colorspace);
	printf("sizeimage %d\n", format.fmt.pix.sizeimage);
	printf("pixelformat %x\n", format.fmt.pix.pixelformat);
	printf("bytesperline %d\n", format.fmt.pix.bytesperline);

	format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	format.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;

	format.fmt.pix.width = 640;
	format.fmt.pix.height = 360;

	if (ioctl(fd, VIDIOC_S_FMT, &format) < 0) {
		perror("VIDIOC_S_FMT");
		return 0;
		}

//	struct v4l2_captureparm streamparm;

	struct v4l2_streamparm streamparm;
	memset(&streamparm, 0, sizeof(streamparm));

	streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

	if (ioctl(fd, VIDIOC_G_PARM, &streamparm) != 0) {
		return 0;
		}

	printf("FR numerator %d\n", streamparm.parm.capture.timeperframe.numerator);
	printf("FR denominator %d\n", streamparm.parm.capture.timeperframe.denominator);

//	streamparm.capturemode |= V4L2_CAP_TIMEPERFRAME;

	streamparm.parm.capture.timeperframe.numerator = 1;
	streamparm.parm.capture.timeperframe.denominator = 30;

	if(ioctl(fd,VIDIOC_S_PARM, &streamparm) !=0) {
		return 0;
		}

	static struct v4l2_requestbuffers bufrequest;

	bufrequest.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	bufrequest.memory = V4L2_MEMORY_MMAP;
	bufrequest.count = 1;
	bufrequest.count = 10;

	if (ioctl(fd, VIDIOC_REQBUFS, &bufrequest) < 0) {
		perror("VIDIOC_REQBUFS");
		return 0;
		}

	memset(&bufferinfo, 0, sizeof(bufferinfo));

	bufferinfo.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	bufferinfo.memory = V4L2_MEMORY_MMAP;
	bufferinfo.index = 0; /* Queueing buffer index 0. */
	bufferinfo.index = 9; /* Queueing buffer index 0. */

	if (ioctl(fd, VIDIOC_QUERYBUF, &bufferinfo) < 0) {
		perror("VIDIOC_QUERYBUF");
		return 0;
		}

	if (buffer_start == NULL)
		buffer_start = mmap(
		                   NULL,
		                   bufferinfo.length,
		                   PROT_READ | PROT_WRITE,
		                   MAP_SHARED,
		                   fd,
		                   bufferinfo.m.offset
		               );

	if (buffer_start == MAP_FAILED) {
		perror("mmap");
		return 0;
		}

	memset(buffer_start, 0, bufferinfo.length);

//------------------------
//	Activate streaming
//------------------------

	static int type;
	type = bufferinfo.type;

	if(ioctl(fd, VIDIOC_STREAMON, &type) < 0) {
		perror("VIDIOC_STREAMON");
		return 0;
		}
grab:

//----------------------------------------------
//----------------------------------------------
//	Put the buffer in the incoming queue.
//----------------------------------------------
//----------------------------------------------

	if(ioctl(fd, VIDIOC_QBUF, &bufferinfo) < 0) {
		perror("VIDIOC_QBUF");
		return 0;
		}

//--------------------------------------------------
//	The buffer's waiting in the outgoing queue.
//--------------------------------------------------

	if(ioctl(fd, VIDIOC_DQBUF, &bufferinfo) < 0) {
		perror("VIDIOC_QBUF");
		return 0;
		}

	static int jpgfile =0;

	if((jpgfile = open("/tmp/myimage.jpeg", O_WRONLY | O_CREAT, 0660)) < 0) {
		perror("open");
		return 0;
		}

	write(jpgfile, buffer_start, bufferinfo.length);
	close(jpgfile);

	return 1;

	}


gboolean	camera0(cairo_t *cr) {

	GError *err = NULL;

	if (cam_start() == 0) return FALSE;

	cambuf = gdk_pixbuf_new_from_file ("/tmp/myimage.jpeg", &err);

	if (cambuf == NULL) return TRUE;

	/*******************
		int xx, yy;
		gdk_window = gdk_window_at_pointer(&xx, &yy);
		if (gdk_window == NULL) return TRUE;
		gdk_cairo_set_source_window(cr, gdk_window, 1,1);
		cairo_paint (cr);
	****************/

	gtk_image_set_from_pixbuf(GTK_IMAGE(cam0_image), cambuf);

	g_object_unref(cambuf); /* no longer needed - free it */

	cambuf = NULL;

//	while (gtk_events_pending ()) gtk_main_iteration ();

	return TRUE;
	}

gboolean on_camdraw_draw (GtkDrawingArea *widget, cairo_t *cr) {

	camera0(cr);

//	static int i=0; printf("%d\n",i); i++;

	return FALSE;
	}

gboolean	camera0timer() {

	if (gtk_stack_get_visible_child(GTK_STACK(stack1)) != Cam0) return TRUE;

//	static int i=0; printf("%d\n",i); i++;

	gtk_widget_queue_draw (camdraw);

	return TRUE; // keep the timer running
	}
