/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/***************************************************************************
 *            camera.cc
 *
 *  Fri Oct 29 12:46:38 CEST 2004
 *  Copyright  2004 Bent Bisballe
 *  deva@aasimon.org
 ****************************************************************************/

/*
 *  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 Library 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.
 */
#include <config.h>
#ifdef USE_GUI

#include "camera.h"

Camera::Camera()
{
}

void Camera::connect(const char *ip, const int port)
{
  errorstatus = new Error();
  initialized = false;

  pthread_mutex_init (&mutex, NULL);
  //mutex = PTHREAD_MUTEX_INITIALIZER;
  /*  
	AVFormatContext *ifmtctx;
	AVFormatContext *ofmtctx;
  */
  running = 1;

	int channel = 0;
	char *device = "/dev/dv1394";

	av_register_all();

	encode_queue = new Queue<DVFrame>(); // infinite size
	player_queue = new Queue<FFFrame>(1); // fixed size of 1

	sem_init(&encode_sem, 0, 0);
	sem_init(&player_sem, 0, 0);

	decoder = new Decoder(errorstatus,
                        device, 
                        channel,
                        &encode_sem,
                        &player_sem,
                        encode_queue,
                        player_queue,
                        &mutex,
                        &running);
  if(errorstatus->hasError()) {
    errorstatus->pushError("Camera initialization failed (decoder).");
    return;
  }

	encoder = new Encoder(errorstatus, 
                        ip, port,
                        &encode_sem,
                        encode_queue,
                        &mutex,
                        &running);
  if(errorstatus->hasError()) {
    errorstatus->pushError("Camera initialization failed (encoder).");
    return;
  }

	player = new Player(errorstatus,
                      &running,
                      &player_sem,
                      player_queue,
                      &mutex);
  if(errorstatus->hasError()) {
    errorstatus->pushError("Camera initialization failed (player).");
    return;
  }

  pthread_create (&decodetid, NULL, thread_run, decoder);
  if(errorstatus->hasError()) {
    errorstatus->pushError("Camera initialization failed (decoder thread).");
    return;
  }
  pthread_create (&encodetid, NULL, thread_run, encoder);
  if(errorstatus->hasError()) {
    errorstatus->pushError("Camera initialization failed (encoder thread).");
    return;
  }
  pthread_create (&playertid, NULL, thread_run, player);
  if(errorstatus->hasError()) {
    errorstatus->pushError("Camera initialization failed (player thread).");
    return;
  }

  initialized = true;
}

Camera::~Camera()
{
  // Signal to the threads to stop
  running = 0;

	pthread_join(decodetid, NULL);
	pthread_join(playertid, NULL);
  pthread_join(encodetid, NULL);

	delete decoder;
	delete encoder;
	delete player;

	sem_destroy(&encode_sem);
	sem_destroy(&player_sem);

	delete player_queue;
	delete encode_queue;

  delete errorstatus;
}

void Camera::setCpr(char *newcpr)
{
  
  if(initialized) encoder->setCpr(newcpr);
  else errorstatus->pushError("Camera not initialized.");

}


void Camera::start()
{
  if(initialized) encoder->start();
  else errorstatus->pushError("Camera not initialized.");
}

void Camera::stop()
{
  if(initialized) encoder->stop();
  else errorstatus->pushError("Camera not initialized.");
}

void Camera::freeze()
{
  // FIXME: Ensure they freeze the same frame, i.e. the player 
  //        shows the same frame that is actually frozen on the server.
  if(initialized) {
    player->stop();
    encoder->freeze();
  } else {
    errorstatus->pushError("Camera not initialized.");
  }
}

void Camera::unfreeze()
{
  if(initialized) player->start();
  else errorstatus->pushError("Camera not initialized.");
}

void Camera::snapshot()
{
  if(initialized) encoder->shoot();
  else errorstatus->pushError("Camera not initialized.");
}

Error *Camera::errorObject()
{
  return errorstatus;
}

#endif/* USE_GUI */