#include "mainView.h"
#include "mainView.moc"
#include <stdio.h>
#include <kapp.h> 				/* klocale is defined there */
#include <kiconloader.h>
#include <ktablistbox.h>
#include <qaccel.h>
#include <stdlib.h>
#include <qcolor.h>
extern KApplication* TemplateApplication; 	/* defined in main.cpp */

#define LPC_STATUS 	1
#define LPC_PRINTCAP 	2
#define LPC_HOLDALL 	3
#define LPC_NOHOLDALL   4
#define LPC_RELEASE     5
#define LPC_HOLD	6


////#include "../../config.h"
//#define LPC_BIN "/usr/local/bin/lpc"
//#define LPQ_BIN "/usr/local/bin/lpq"
//#define LPRM_BIN "/usr/local/bin/lprm"

// TODO LPC_* are absolute PATH replace with QStrings !!

mainView::mainView(QWidget *parent=0, const char *name=0) : QWidget(parent, name)
{
    MultiLineEdit = 0; 
    selectedPrinter="all";
    lpqbuf=0L;
#define LPQBUF_SIZE 32*1024
    lpqbuf = (char *)malloc(LPQBUF_SIZE); // Hope this long enough
    lpqbufrun = lpqbuf;

    MultiLineEdit = new QMultiLineEdit(this);

    ListBox = SetupListBox();
    
    /* Keyboard functions */
    accel = new QAccel (ListBox);
    accel->connectItem( accel->insertItem( Key_Delete ), this, SLOT(RemoveJob()) );
    accel->connectItem( accel->insertItem( Key_Backspace ),this, SLOT(RemoveJob()) );

    /* Start a lpq Proces in Order to get something into the Queue ListBox */
    
    lpq = new KProcess;
    *lpq << "lpq";
    connect( lpq, SIGNAL(receivedStdout(KProcess *, char *, int)), 
   	     this,  SLOT(LpqReadStdout( KProcess *, char *, int)) );
    connect( lpq, SIGNAL(processExited(KProcess *)), 
             this,  SLOT(LpqProcessExited(KProcess *)) );
	
    *lpq << "-Pall";
    if( lpq->start( KProcess::Block, KProcess::Stdout ) )
      {
      }	

    /* lpc is used for finding out which Printer instaled on the local System
     */
    lpc = new KProcess;
    *lpc << "lpc";
    connect( lpc, SIGNAL(receivedStdout(KProcess *, char *, int)),
   	     this, SLOT(LpcReadStdout(KProcess *, char *, int)) );
    connect( lpc, SIGNAL(processExited(KProcess *)), 
	     this, SLOT(LpcProcessExited(KProcess *)) );
	
    *lpc << "printcap";
    *lpc << "all";

    LpcCommand = LPC_PRINTCAP;
    if( lpc->start( KProcess::Block, KProcess::Stdout ) )
      {
      }	

    lprm = new KProcess;
    *lprm << "lprm";
    holdall=0;  	// holdall = false
    HoldAllStatus();
    this->show();

	buggy = new QTimer;
	connect(buggy, 
		SIGNAL(timeout()), this, SLOT(ListPrintQueue()));
	buggy->start(4000);  // Self Init I know no better way *sigh* 

}

/**
 *  lpc_execute
 */

void
mainView::LpcExecute()
{
  LpcBuffer = "";

  lpc->clearArguments ();
  *lpc << "lpc";
  QApplication::setOverrideCursor (waitCursor);

  switch (LpcCommand) {
  case LPC_STATUS:
    *lpc << "-P";
    *lpc << selectedPrinter.data ();
    *lpc << "status";
    break;

  case LPC_PRINTCAP:
    *lpc << "printcap";
    *lpc << "all";
    break;

  case LPC_RELEASE:
    *lpc << "release";
    *lpc << selectedPrinter.data ();
    *lpc << "all";
    break;

  case LPC_HOLD:
    *lpc << "hold";
    *lpc << selectedPrinter.data ();
    *lpc << "all";
    break;

  case LPC_HOLDALL:
    *lpc << "-P";
    *lpc << selectedPrinter.data ();
    *lpc << "holdall";
    break;

  case LPC_NOHOLDALL:
    *lpc << "-P";
    *lpc << selectedPrinter.data ();
    *lpc << "noholdall";
    break;
  }
  lpc->start (KProcess:: Block, KProcess::Stdout);
  QApplication::restoreOverrideCursor ();
}
void
mainView::HoldAll()
{
  LpcCommand = LPC_HOLDALL;
  LpcExecute();
  LpcCommand = LPC_HOLD;
  LpcExecute();
  ListPrintQueue();
}
void 
mainView::ReleaseAll()
{
  LpcCommand = LPC_NOHOLDALL;
  LpcExecute();
  HoldAllStatus();
  LpcCommand = LPC_RELEASE;
  LpcExecute();
  ListPrintQueue();
}
void
mainView::HoldAllStatus()
{
  // feststellen mit lpc ob printer im holdall stehen
  //
  LpcCommand = LPC_STATUS;
  LpcExecute();
 // QString pixdir; // = TemplateApplication->kdedir() +
 // QString("/share/apps/klpc/toolbar/");  
    if (holdall == 0)
    {
	//QPixmap play_pixmap((pixdir + "play.xpm").data());
	//toolbar->setButtonPixmap(PMBUTTON2, play_pixmap);
    	//FIXME
	//statusbar->changeItem("Druckerstatus: bereit", ID_LINE_COLUMN);
	}
      else
	{
	//QPixmap pause_pixmap((pixdir + "pause.xpm").data());
	//toolbar->setButtonPixmap(PMBUTTON2, pause_pixmap);
    	//FIXME
	//statusbar->changeItem("Druckerstatus: angehalten", ID_LINE_COLUMN);
	}	
	
}


void
mainView::RemoveJob()
{
  char buffer[256];

  /* No selection no remove job */
  if (ListBox->currentItem () == -1)
    return;
  /* Change to a wait-cursor (in case it takes some time)*/
  QApplication::setOverrideCursor (waitCursor);

  /* Now we must now what printer and which job number */
  QString printername = ListBox->text (ListBox->currentItem (), 0);
  QString jobnumber   = ListBox->text (ListBox->currentItem (), 4);
  
  lprm->clearArguments ();
  /* FIXME: we should use a configured path for lprm here */
  *lprm << "lprm" << "-P" << printername.data () << jobnumber.data ();
  
  /* Start the lprm Remove */
  lprm->start (KProcess:: Block, KProcess::Stdout);
  
  ListPrintQueue ();

  /* Restore our Cursor that we changed to wait before */
  QApplication::restoreOverrideCursor ();

}


void
mainView::ListPrintQueue ()
{
  /* Test if there is another lpq (which was started from us) is running */
  if ( lpqrunning == 1 ) 
  	return;

  lpqrunning=1;
  LpqBuffer = "";
  lpqbufrun = lpqbuf;
  memset (lpqbuf, 0, LPQBUF_SIZE);
  
  lpq->clearArguments ();

  /* FIXME: we should use a configured path for lpq here */
  *lpq << "lpq" << "-P" << selectedPrinter.data ();

  if (lpq->start (KProcess:: Block, KProcess::Stdout)) {
 //   printf ("Fehler!\n");
  }
  
  buggy->start(4000);
  lpqrunning=0;
  // HoldAllStatus();

}

/*
 * Read Stdout of lpq
 */

void 
mainView::LpqReadStdout(KProcess *, char *buffer, int len)
{
/* There is a timing problem here. When this routine is executed
   too long ->SEGFAULT
*/

	/* Copy lightining fast */
	strncpy(lpqbufrun, buffer, len);
	lpqbufrun+=len;
	

}

/*
 + We get notified if lpq-Process exits
 */

void 
mainView::LpqProcessExited(KProcess *)
{
  const char *start = (const char *) lpqbuf;
  LpqBuffer = QString (lpqbuf, lpqbufrun - lpqbuf);
  const char *end = start;
  int len = 0;
  char buffer[256];
  int search = 1;

  ListBox->clear();

  // Do something against flickering
  // Draw new information into a second ListBox
  // an after completion lay the new ListBox over the old one
  // this does help a bit against this flickering update
  // of KTabListbox
  KTabListBox *ktlb = SetupListBox();
  ktlb->hide();

  MultiLineEdit->clear ();
  MultiLineEdit->append ((const char *) LpqBuffer);
  
  QString actualPrinter;
  while (*end != 0) {
    while (*end++ != '\n')
      len++;
    strncpy ((char *) &buffer, start, len);
    //printf("***%s\n",(char *)&buffer);
    buffer[len] = 0;
    start = end;
    len = 0;

    char dummy[128];
    char printername[32];

    sscanf ((char *) &buffer, "%s%s", (char *) &dummy, (char *) &printername);
    
    if (QString (dummy) == "Printer:") {
      actualPrinter = QString (printername);
    }

    //FIXME we should handle bounce queues special
    // because "lpq" shows them special
    if (strstr ((char *) &buffer, "bounce") != 0L && search) {
 //     printf ("***found bounce queue\n");
      search = 0;		// Stop search 

    }

    // Keine Spaces, keine [P]rinter und keine Leerzeilen
    // FIXME this place memory leaks!!!
    if (buffer[0] != ' ' && buffer[0] != 'P' && buffer[0] != 0) {
      QString *tmp;
      tmp = new QString(); // FIXME Memory Leak (nowhere deleted)
      tmp->append(actualPrinter.data());
      tmp->append(" ");
      tmp->append(buffer);
      ktlb->insertItem (tmp->data ());
      if ( QString( ktlb->text(ktlb->count()-1,1) )== "hold" )
      		 ktlb->changeItemColor (red);
      else 
      if ( QString( ktlb->text(ktlb->count()-1,1) )== "active" )
      		 ktlb->changeItemColor (blue);
    }
  }

 //FIXME We should check if the ListBox-Content has changed 
 // 	 if not we can skip the update (Fight the Flickering Part 2)
  
 ktlb->setGeometry(	ListBox->x(), ListBox->y(), ListBox->width(),
 			ListBox->height());
 
 ktlb->show();
 ListBox->hide();
 KTabListBox *tmplb = ListBox;
 ListBox=ktlb;
 delete tmplb;
 
  buffer[256];
  int lbcount;

  lbcount = ListBox->count ();

  switch (lbcount) {
  case 0:
    sprintf ((char *) &buffer, klocale->translate ("Kein Auftrag in der Warteschlange"),
	     lbcount);
    break;

  case 1:
    sprintf ((char *) &buffer, "%i Auftrag in der Warteschlange",
	     lbcount);
    break;

  default:
    sprintf ((char *) &buffer, "%i Aufträge in der Warteschlange",
	     lbcount);
    break;
  }
  //FIXME
  //statusbar->changeItem((char*) &buffer, ID_GENERAL);

}


void 
mainView::LpcReadStdout(KProcess *, char *buffer, int len)
{
/* Es scheint timing-Probleme zu geben, falls diese Routine zu lange
   ist
*/
	for ( int i= 0; i < len; i++ )
		LpcBuffer += *(buffer+i);

}

/*
 + We get notified if lpq-Process exits
 */

void 
mainView::LpcProcessExited(KProcess *)
{

	const char *start = (const char *) LpcBuffer;
	const char *end = start;
	int len = 0;
	char buffer[256];

	while (*end != 0)
	{
		while (*end++ != '\n')
			len++;
		strncpy ((char *) &buffer, start, len);
		buffer[len] = 0;
		start = end;
		len = 0;
		switch (LpcCommand)
		{
		case LPC_PRINTCAP:
			{	// Extract Printers 

				if (buffer[0] != ' ')
				{
					QString *dummy = new QString (buffer);

					PrinterList.append (dummy);
				}
			}
			break;

		case LPC_STATUS:
			{
				if (buffer[0] != ' ')
					if (strstr ((char *) &buffer, "(holdall)") == NULL)
						holdall = 0;
					else
						holdall = 1;
			}
			break;
		case LPC_RELEASE:
		case LPC_HOLDALL:
			break;
		}
	}

}


KTabListBox*
mainView::SetupListBox()
{ 
  KTabListBox *ListBox = new KTabListBox(this, "ListBox", 8);
  ListBox->setSeparator(' ');
  ListBox->setColumn(0,"Printer",100);
  ListBox->setColumn(1,"Rank",50);
  ListBox->setColumn(2,"Owner/ID",140);
  ListBox->setColumn(3,"Class",50);
  ListBox->setColumn(4,"Job",50);
  ListBox->setColumn(5,"Files",100);
  ListBox->setColumn(6,"Size",50);
  ListBox->setColumn(7,"Time",50);
  ListBox->setGeometry( 0, 0, 597, 224 );
  return(ListBox);
}
void
mainView::DestroyListBox()
{
  delete ListBox;
}

mainView::~mainView()
{
  free(lpqbuf);
  delete accel;
  delete lprm;
  delete lpq;
  delete lpc;
  delete ListBox;
}
void
mainView::resizeEvent( QResizeEvent *)
{
  if (ListBox != 0)
    ListBox->setGeometry (0, 0, this->width (), this->height () / 2);
  if (MultiLineEdit != 0)
    MultiLineEdit->setGeometry (0, this->height () / 2, this->width (), this->height () / 2);
}
