/*  Stream Widget
    Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com)

    This application 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.
    
    2004-03-16: A class to handle video streaming.
 */
 
#include "streamwg.h"
#include "indistd.h"
#include "Options.h"

#include <tdemessagebox.h>
#include <tdelocale.h>
#include <kdebug.h>
#include <kpushbutton.h>
#include <kiconloader.h>
#include <tdetempfile.h>
#include <tdeio/netaccess.h>
#include <tdefiledialog.h>
#include <kcombobox.h>
#include <kurl.h>

#include <tqsocketnotifier.h>
#include <tqimage.h>
#include <tqpainter.h>
#include <tqstringlist.h>
#include <tqdir.h>
#include <tqlayout.h>


#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>

#define STREAMBUFSIZ		1024

FILE *wfp;

 StreamWG::StreamWG(INDIStdDevice *inStdDev, TQWidget * parent, const char * name) : streamForm(parent, name)
 {
 
   stdDev         = inStdDev;
//   streamBuffer   = NULL;
   streamWidth    = streamHeight = -1;
//   streamFD       = -1;
   processStream  = colorFrame = false;
   
   //videoFrameLayout = new TQVBoxLayout(videoFrame, 0, 0); 
   streamFrame      = new VideoWG(videoFrame);
      
  TDEIconLoader *icons = TDEGlobal::iconLoader();
  
  playPix    = icons->loadIcon( "media-playback-start", TDEIcon::Toolbar );
  pausePix   = icons->loadIcon( "media-playback-pause", TDEIcon::Toolbar );
  capturePix = icons->loadIcon( "frame_image", TDEIcon::Toolbar );
  
  playB->setPixmap(pausePix);	
  captureB->setPixmap(capturePix);
  
  imgFormatCombo->insertStrList(TQImage::outputFormats());
  
  connect(playB, TQ_SIGNAL(clicked()), this, TQ_SLOT(playPressed()));
  connect(captureB, TQ_SIGNAL(clicked()), this, TQ_SLOT(captureImage()));
   
 }
 
StreamWG::~StreamWG()
{
//  delete streamBuffer;
}

void StreamWG::closeEvent ( TQCloseEvent * e )
{
  stdDev->streamDisabled();
  processStream = false;
  e->accept();
}

void StreamWG::setColorFrame(bool color)
{
  colorFrame = color;
}

/*void StreamWG::establishDataChannel(TQString host, int port)
{
        TQString errMsg;
	struct sockaddr_in pin;
	struct hostent *serverHostName = gethostbyname(host.ascii());
	errMsg = TQString("Connection to INDI host at %1 on port %2 failed.").arg(host).arg(port);
	
	memset(&pin, 0, sizeof(pin));
	pin.sin_family 		= AF_INET;
	pin.sin_addr.s_addr 	= ((struct in_addr *) (serverHostName->h_addr))->s_addr;
	pin.sin_port 		= htons(port);

	if ( (streamFD = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	{
	 KMessageBox::error(0, i18n("Cannot create socket."));
	 return;
	}

	if ( ::connect(streamFD, (struct sockaddr*) &pin, sizeof(pin)) == -1)
	{
	  KMessageBox::error(0, errMsg);
	  streamFD = -1;
	  return;
	}

	// callback notified
	sNotifier = new TQSocketNotifier( streamFD, TQSocketNotifier::Read, this);
        TQObject::connect( sNotifier, TQ_SIGNAL(activated(int)), this, TQ_SLOT(streamReceived()));
}*/

void StreamWG::enableStream(bool enable)
{
  if (enable)
  {
    processStream = true;
    show();
  }
  else
  {
    processStream = false;
    playB->setPixmap(pausePix);
    hide();
  }
  
}

void StreamWG::setSize(int wd, int ht)
{
  streamWidth  = wd;
  streamHeight = ht;
  
  streamFrame->totalBaseCount = wd * ht;
  
  resize(wd + layout()->margin() * 2 , ht + playB->height() + layout()->margin() * 2 + layout()->spacing());  
  streamFrame->resize(wd, ht);
}

void StreamWG::resizeEvent(TQResizeEvent *ev)
{

  streamFrame->resize(ev->size().width() - layout()->margin() * 2, ev->size().height() - playB->height() - layout()->margin() * 2 - layout()->spacing());

}
 /*
void StreamWG::allocateStreamBuffer()
{
  if (streamWidth < 0 || streamHeight < 0) return;
  
  fprintf(stderr, "In allocate stream buffer \n");
  
  delete (streamBuffer);
  
  if (colorFrame)
    frameTotalBytes = streamWidth * streamHeight * 4;
  else
    frameTotalBytes = streamWidth * streamHeight;
  
   streamBuffer = new unsigned char[frameTotalBytes];
   
   fprintf(stderr, "We have a %s frame. width: %d -- height: %d -- totalBytes: %d\n", colorFrame ? "color" : "grey", streamWidth, streamHeight, frameTotalBytes);
  
}

void StreamWG::streamReceived()
{

	char msg[1024];
	int nr=0, n=0;
	
	for (nr = 0; nr < frameTotalBytes; nr+=n)
	{
           n = read (streamFD, streamBuffer + nr, frameTotalBytes - nr);
	   if (n <= 0)
	   {
	    	if (n < 0)
			sprintf (msg, "INDI: input error.");
	    	else
			sprintf (msg, "INDI: agent closed connection.");

	    stdDev->sNotifier->disconnect();
	    close(stdDev->streamFD);
	    KMessageBox::error(0, TQString(msg));
            return;
	   }
	}
	
	if (!processStream)
	  return;
	
	streamFrame->newFrame(streamBuffer, streamWidth, streamHeight, colorFrame);

}*/

void StreamWG::playPressed()
{

 if (processStream)
 {
  playB->setPixmap(playPix);	
  processStream = false;
 }
 else
 {
  playB->setPixmap(pausePix);	
  processStream = true;
 }
 
}

void StreamWG::captureImage()
{
  TQString fname;
  TQString fmt;
  KURL currentFileURL;
  TQString currentDir = Options::fitsSaveDirectory();
  KTempFile tmpfile;
  tmpfile.setAutoDelete(true);

  fmt = imgFormatCombo->currentText();

  currentFileURL = KFileDialog::getSaveURL( currentDir, fmt );
  
  if (currentFileURL.isEmpty()) return;

  if ( currentFileURL.isValid() )
  {
	currentDir = currentFileURL.directory();

	if ( currentFileURL.isLocalFile() )
  	   fname = currentFileURL.path();
	else
	   fname = tmpfile.name();

	if (fname.right(fmt.length()).lower() != fmt.lower()) 
	{
	  fname += ".";
	  fname += fmt.lower();
	}
	  
	streamFrame->qPix.save(fname, fmt.ascii());
	
	//set rwx for owner, rx for group, rx for other
	chmod( fname.ascii(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH );

	if ( tmpfile.name() == fname )
	{ //need to upload to remote location
	
	  if ( ! TDEIO::NetAccess::upload( tmpfile.name(), currentFileURL, (TQWidget*) 0 ) )
	  {
		TQString message = i18n( "Could not upload image to remote location: %1" ).arg( currentFileURL.prettyURL() );
		KMessageBox::sorry( 0, message, i18n( "Could not upload file" ) );
	  }
	}
  }
  else
  {
		TQString message = i18n( "Invalid URL: %1" ).arg( currentFileURL.url() );
		KMessageBox::sorry( 0, message, i18n( "Invalid URL" ) );
  }

}


VideoWG::VideoWG(TQWidget * parent, const char * name) : TQFrame(parent, name, TQt::WNoAutoErase)
{
  streamImage    = NULL;
  grayTable=new TQRgb[256];
  for (int i=0;i<256;i++)
        grayTable[i]=tqRgb(i,i,i);
}
      
VideoWG::~VideoWG() 
{
 delete (streamImage);
 delete [] (grayTable);
}

void VideoWG::newFrame(unsigned char *buffer, int buffSiz, int w, int h)
{
   //delete (streamImage);
   //streamImage = NULL;
  
  //if (color)
  if (buffSiz > totalBaseCount)
     streamImage = new TQImage(buffer, w, h, 32, 0, 0, TQImage::BigEndian);
   else
   
    streamImage = new TQImage(buffer, w, h, 8, grayTable, 256, TQImage::IgnoreEndian);
    
   update();
    
}

void VideoWG::paintEvent(TQPaintEvent */*ev*/)
{
  	
   if (streamImage)
   {
	if (streamImage->isNull()) return;
  	//qPix = kPixIO.convertToPixmap(*streamImage);/*streamImage->smoothScale(width(), height()));*/
	qPix = kPixIO.convertToPixmap(streamImage->scale(width(), height()));
	delete (streamImage);
	streamImage = NULL;
   }
   
   bitBlt(this, 0, 0, &qPix);
   
}

#include "streamwg.moc"
