/*  INDI Element
    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-01-15	INDI element is the most basic unit of the INDI KStars client.
 */
 
#include "indielement.h"
#include "indiproperty.h"
#include "indigroup.h"
#include "indidevice.h"

#include "indi/indicom.h"

#include <tqcheckbox.h>
#include <tqlabel.h>
#include <tqlayout.h>
#include <tqstring.h>
#include <tqptrlist.h>
#include <tqslider.h>
#include <tqdir.h>

#include <kurl.h>
#include <tdefiledialog.h>
#include <kled.h>
#include <ksqueezedtextlabel.h> 
#include <klineedit.h>
#include <kpushbutton.h>
#include <tdelocale.h>
#include <kdebug.h>
#include <kcombobox.h>
#include <knuminput.h>
#include <kdialogbase.h>

/* search element for attribute.
 * return XMLAtt if find, else NULL with helpful info in errmsg.
 */
XMLAtt * findAtt (XMLEle *ep, const char *name, char errmsg[])
{
	XMLAtt *ap = findXMLAtt (ep, name);
	if (ap)
	    return (ap);
	if (errmsg)
	    snprintf (errmsg, ERRMSG_SIZE, "INDI: <%.64s> missing attribute '%.64s'", tagXMLEle(ep),name);
	return NULL;
}

/* search element for given child. pp is just to build a better errmsg.
 * return XMLEle if find, else NULL with helpful info in errmsg.
 */
XMLEle * findEle (XMLEle *ep, INDI_P *pp, const char *child, char errmsg[])
{
	XMLEle *cp = findXMLEle (ep, child);
	if (cp)
	    return (cp);
	if (errmsg)
	    snprintf (errmsg, ERRMSG_SIZE, "INDI: <%.64s %.64s %.64s> missing child '%.64s'", tagXMLEle(ep),
						pp->pg->dp->name.ascii(), pp->name.ascii(), child);
	return (NULL);
}

/*******************************************************************
** INDI Element
*******************************************************************/
INDI_E::INDI_E(INDI_P *parentProperty, TQString inName, TQString inLabel)
{
  name = inName;
  label = inLabel;

  pp = parentProperty;

  EHBox     = new TQHBoxLayout(0, 0, KDialog::spacingHint());
  label_w   = NULL;
  read_w    = NULL;
  write_w   = NULL;
  spin_w    = NULL;
  slider_w  = NULL;
  push_w    = NULL;
  browse_w  = NULL;
  check_w   = NULL;
  led_w     = NULL;
  hSpacer   = NULL;

}

INDI_E::~INDI_E()
{
    delete (EHBox);
    delete (label_w);
    delete (read_w);
    delete (write_w);
    delete (spin_w);
    delete (slider_w);
    delete (push_w);
    delete (browse_w);
    delete (check_w);
    delete (led_w);
    delete (hSpacer);
}

void INDI_E::setupElementLabel()
{
label_w = new KSqueezedTextLabel(pp->pg->propertyContainer);
label_w->setMinimumWidth(ELEMENT_LABEL_WIDTH);
label_w->setMaximumWidth(ELEMENT_LABEL_WIDTH);
label_w->setFrameShape( KSqueezedTextLabel::Box );
label_w->setPaletteBackgroundColor( TQColor( 224, 232, 238 ) );
label_w->setTextFormat( TQLabel::RichText );
label_w->setAlignment( int( TQLabel::WordBreak | TQLabel::AlignCenter ) );

if (label.length() > MAX_LABEL_LENGTH)
{
  TQFont tempFont(  label_w->font() );
  tempFont.setPointSize( tempFont.pointSize() - MED_INDI_FONT );
  label_w->setFont( tempFont );
}

label_w->setText(label);

EHBox->addWidget(label_w);
}

int INDI_E::buildTextGUI(TQString initText)
{

  setupElementLabel();  
  
  text = initText;
  
  switch (pp->perm)
  {
    case PP_RW:
    setupElementRead(ELEMENT_READ_WIDTH);
    setupElementWrite(ELEMENT_WRITE_WIDTH);
    
    break;
    
    case PP_RO:
    setupElementRead(ELEMENT_FULL_WIDTH);
    break;
    
    case PP_WO:
    setupElementWrite(ELEMENT_FULL_WIDTH);
    break;
  }
  
  pp->PVBox->addLayout(EHBox);
  return (0);
    
}

int INDI_E::buildBLOBGUI()
{

  setupElementLabel();  
  
  text = "INDI DATA STREAM";
  
  switch (pp->perm)
  {
    case PP_RW:
      setupElementRead(ELEMENT_READ_WIDTH);
      setupElementWrite(ELEMENT_WRITE_WIDTH);
      setupBrowseButton();
    
      break;
    
    case PP_RO:
      setupElementRead(ELEMENT_FULL_WIDTH);
      break;
    
    case PP_WO:
      setupElementWrite(ELEMENT_FULL_WIDTH);
      setupBrowseButton();
      break;
  }
  
  pp->PVBox->addLayout(EHBox);
  return (0);
    
}

int INDI_E::buildNumberGUI  (double initValue)
{
  bool scale = false;
  
  updateValue(initValue);
  setupElementLabel();
  
  if (step != 0 && (max - min)/step <= MAXSCSTEPS)
    scale = true;
  
  switch (pp->perm)
  {
    case PP_RW:
     setupElementRead(ELEMENT_READ_WIDTH);
     if (scale)
       setupElementScale(ELEMENT_WRITE_WIDTH);
     else
       setupElementWrite(ELEMENT_WRITE_WIDTH);
       
       pp->PVBox->addLayout(EHBox);
     break;
     
    case PP_RO:
    setupElementRead(ELEMENT_READ_WIDTH);
    pp->PVBox->addLayout(EHBox);
    break;
    
    case PP_WO:
    if (scale)
     setupElementScale(ELEMENT_FULL_WIDTH);
    else
     setupElementWrite(ELEMENT_FULL_WIDTH);
     
     pp->PVBox->addLayout(EHBox);
    
    break;
  }
  
  return (0);
    
}

int INDI_E::buildLightGUI()
{

        led_w = new KLed (pp->pg->propertyContainer);
	led_w->setMaximumSize(16,16);
	led_w->setLook( KLed::Sunken );
	drawLt();
	
	EHBox->addWidget(led_w);
	
	setupElementLabel();
	
	pp->PVBox->addLayout(EHBox);
	
	return (0);
}

void INDI_E::drawLt()
{
        /* set state light */
	switch (state)
	{
	  case PS_IDLE:
	  led_w->setColor(TQt::gray);
	  break;

	  case PS_OK:
	  led_w->setColor(TQt::green);
	  break;

	  case PS_BUSY:
	  led_w->setColor(TQt::yellow);
	  break;

	  case PS_ALERT:
	  led_w->setColor(TQt::red);
	  break;

	  default:
	  break;

	}
}


void INDI_E::updateValue(double newValue)
{
  char iNumber[32];
  
  value = newValue; 

  numberFormat(iNumber, format.ascii(), value);
  text = iNumber;

}

void INDI_E::setupElementScale(int length)
{

int steps = (int) ((max - min) / step);
spin_w    = new KDoubleSpinBox(min, max, step, value, 2, pp->pg->propertyContainer );
slider_w  = new TQSlider(0, steps, 1, (int) ((value - min) / step),  TQt::Horizontal, pp->pg->propertyContainer );

connect(spin_w, TQ_SIGNAL(valueChanged(double)), this, TQ_SLOT(spinChanged(double )));
connect(slider_w, TQ_SIGNAL(sliderMoved(int)), this, TQ_SLOT(sliderChanged(int )));

//kdDebug() << "For element " << label << " we have step of " << step << endl;

  if (length == ELEMENT_FULL_WIDTH)
	spin_w->setSizePolicy( TQSizePolicy( (TQSizePolicy::SizeType)7, (TQSizePolicy::SizeType)0, 0, 0, spin_w->sizePolicy().hasHeightForWidth() ) );
  else
	spin_w->setSizePolicy( TQSizePolicy( (TQSizePolicy::SizeType)0, (TQSizePolicy::SizeType)0, 0, 0, spin_w->sizePolicy().hasHeightForWidth() ) );
	
spin_w->setMinimumWidth( (int) (length * 0.45) );
slider_w->setMinimumWidth( (int) (length * 0.55) );

EHBox->addWidget(slider_w);
EHBox->addWidget(spin_w);
}

void INDI_E::spinChanged(double value)
{
  int slider_value = (int) ((value - min) / step);
  slider_w->setValue(slider_value);
}

void INDI_E::sliderChanged(int value)
{

 double spin_value = (value * step) + min;
 spin_w->setValue(spin_value);  

}
   
void INDI_E::setMin (double inMin)
{
  min = inMin;
  if (spin_w)
  {
    spin_w->setMinValue(min);
    spin_w->setValue(value);
  }
  if (slider_w)
  {
    slider_w->setMaxValue((int) ((max - min) / step));
    slider_w->setMinValue(0);
    slider_w->setPageStep(1);
    slider_w->setValue( (int) ((value - min) / step ));
  }
  
}
   
void INDI_E::setMax (double inMax)
{
 max = inMax;
 if (spin_w)
 {
   spin_w->setMaxValue(max);
   spin_w->setValue(value);
 }
 if (slider_w)
 {
    slider_w->setMaxValue((int) ((max - min) / step));
    slider_w->setMinValue(0);
    slider_w->setPageStep(1);
    slider_w->setValue( (int) ((value - min) / step ));
 }
 
}
   
void INDI_E::setupElementWrite(int length)
{
    write_w = new KLineEdit( pp->pg->propertyContainer);
    write_w->setSizePolicy( TQSizePolicy( (TQSizePolicy::SizeType)0, (TQSizePolicy::SizeType)0, 0, 0, write_w->sizePolicy().hasHeightForWidth() ));
    write_w->setMinimumWidth( length );
    write_w->setMaximumWidth( length);
    
    TQObject::connect(write_w, TQ_SIGNAL(returnPressed()), pp, TQ_SLOT(newText()));
    EHBox->addWidget(write_w);
}


void INDI_E::setupElementRead(int length)
{

  read_w = new KLineEdit( pp->pg->propertyContainer );
  read_w->setMinimumWidth( length );
  read_w->setFocusPolicy( TQWidget::NoFocus );
  read_w->setFrameShape( KLineEdit::GroupBoxPanel );
  read_w->setFrameShadow( KLineEdit::Plain );
  read_w->setCursorPosition( 0 );
  read_w->setAlignment( int( KLineEdit::AlignHCenter ) );
  read_w->setReadOnly( TRUE );
  read_w->setText(text);
  
  EHBox->addWidget(read_w);

}

void INDI_E::setupBrowseButton()
{
   browse_w = new KPushButton("...", pp->pg->propertyContainer);
   browse_w->setSizePolicy( TQSizePolicy( (TQSizePolicy::SizeType)5, (TQSizePolicy::SizeType)0, 0, 0, browse_w->sizePolicy().hasHeightForWidth() ) );
   browse_w->setMinimumWidth( MIN_SET_WIDTH );
   browse_w->setMaximumWidth( MAX_SET_WIDTH );

   EHBox->addWidget(browse_w);
   TQObject::connect(browse_w, TQ_SIGNAL(clicked()), this, TQ_SLOT(browseBlob()));
}


void INDI_E::initNumberValues(double newMin, double newMax, double newStep, char * newFormat)
{
  min = newMin;
  max = newMax;
  step = newStep;
  format = newFormat;
}

void INDI_E::browseBlob()
{

  KURL currentURL;

  currentURL = KFileDialog::getOpenURL( TQDir::homeDirPath(), "*");

  // if user presses cancel
  if (currentURL.isEmpty())
		  return;

  if ( currentURL.isValid() )
    write_w->setText(currentURL.path());

}


#include "indielement.moc"
