/***************************************************************************
                          INDI Driver
                             -------------------
    begin                : Wed May 7th 2003
    copyright            : (C) 2001 by Jasem Mutlaq
    email                : mutlaqja@ikarustech.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.                                   *
 *                                                                         *
 ***************************************************************************/

#include "indidriver.h"
#include "indimenu.h"
#include "indihostconf.h"
#include "devicemanager.h"
#include "indidevice.h"
#include "indi/indicom.h"

#include "kstars.h"
#include "kstarsdata.h"
#include "ksutils.h"

#include <tqfile.h>
#include <tqvaluelist.h>
#include <tqcstring.h>
#include <tqradiobutton.h>
#include <tqtextedit.h>

#include <kiconloader.h>
#include <tdelistview.h>
#include <tdepopupmenu.h>
#include <kprocess.h>
#include <tdemessagebox.h>
#include <kpushbutton.h>
#include <klineedit.h>
#include <kstandarddirs.h>
#include <tdeaction.h>

#include <kextsock.h>
#include <unistd.h>

/*
 *  The dialog will by default be modeless, unless you set 'modal' to
 *  TRUE to construct a modal dialog.
 */
INDIDriver::INDIDriver(TQWidget *parent) : devManager( parent )

{

    lastPort = 7263;
    lastGroup = NULL;
    lastDevice = NULL;

    ksw = (KStars *) parent;

    //FormLayout =  makeVBoxMainWidget();

    localListView->setSorting(-1);
    clientListView->setSorting(-1);

    TDEIconLoader *icons = TDEGlobal::iconLoader();
    runningPix = icons->loadIcon( "application-x-executable", TDEIcon::Small);
    stopPix    = icons->loadIcon( "button_cancel", TDEIcon::Small);
    localMode  = icons->loadIcon( "network_local", TDEIcon::Small);
    serverMode = icons->loadIcon( "network", TDEIcon::Small);

    LocalpopMenu = new TDEPopupMenu(localListView);
    LocalpopMenu->insertItem( runningPix, i18n("Run Service") , 0);
    LocalpopMenu->insertItem( stopPix, i18n("Stop Service"), 1);

    localListView->setRootIsDecorated(true);

  connected           = icons->loadIcon( "connect_established", TDEIcon::Small);
  disconnected        = icons->loadIcon( "connect_no", TDEIcon::Small);
  establishConnection = icons->loadIcon( "connect_creating", TDEIcon::Small);

  ClientpopMenu = new TDEPopupMenu(clientListView);
  ClientpopMenu->insertItem( establishConnection, i18n("Connect") , 0);
  ClientpopMenu->insertItem( disconnected, i18n("Disconnect"), 1);


  for (uint i = 0; i < ksw->data()->INDIHostsList.count(); i++)
  {
  	TQListViewItem *item = new TQListViewItem(clientListView, lastGroup);
	lastGroup = item;
	item->setPixmap(0, disconnected);
        item->setText(1, ksw->data()->INDIHostsList.at(i)->name);
	item->setText(2, ksw->data()->INDIHostsList.at(i)->portnumber);

  }

  lastGroup = NULL;

  TQObject::connect(addB, TQT_SIGNAL(clicked()), this, TQT_SLOT(addINDIHost()));
  TQObject::connect(modifyB, TQT_SIGNAL(clicked()), this, TQT_SLOT(modifyINDIHost()));
  TQObject::connect(removeB, TQT_SIGNAL(clicked()), this, TQT_SLOT(removeINDIHost()));

  TQObject::connect(clientListView, TQT_SIGNAL(rightButtonPressed ( TQListViewItem *, const TQPoint &, int )), this, TQT_SLOT(ClientprocessRightButton( TQListViewItem *, const TQPoint &, int )));

TQObject::connect(ClientpopMenu, TQT_SIGNAL(activated(int)), this, TQT_SLOT(processHostStatus(int)));

TQObject::connect(localListView, TQT_SIGNAL(rightButtonPressed ( TQListViewItem *, const TQPoint &, int )), this, TQT_SLOT(LocalprocessRightButton( TQListViewItem *, const TQPoint &, int )));

TQObject::connect(LocalpopMenu, TQT_SIGNAL(activated(int)), this, TQT_SLOT(processDeviceStatus(int)));

TQObject::connect(ksw->getINDIMenu(), TQT_SIGNAL(driverDisconnected(int)), this, TQT_SLOT(shutdownHost(int)));

TQObject::connect(connectHostB, TQT_SIGNAL(clicked()), this, TQT_SLOT(activateHostConnection()));
TQObject::connect(disconnectHostB, TQT_SIGNAL(clicked()), this, TQT_SLOT(activateHostDisconnection()));

TQObject::connect(runServiceB, TQT_SIGNAL(clicked()), this, TQT_SLOT(activateRunService()));
TQObject::connect(stopServiceB, TQT_SIGNAL(clicked()), this, TQT_SLOT(activateStopService()));

TQObject::connect(localListView, TQT_SIGNAL(selectionChanged()), this, TQT_SLOT(updateLocalButtons()));
TQObject::connect(clientListView, TQT_SIGNAL(selectionChanged()), this, TQT_SLOT(updateClientButtons()));

readXMLDriver();
resize( 500, 300);

}

void INDIDriver::shutdownHost(int mgrID)
{
  TQListViewItem *affectedItem;

for (uint i=0; i < ksw->data()->INDIHostsList.count(); i++)
{
     if (ksw->data()->INDIHostsList.at(i)->mgrID == mgrID)
     {
        affectedItem = clientListView->itemAtIndex(i);
	ksw->data()->INDIHostsList.at(i)->mgrID = -1;
	ksw->data()->INDIHostsList.at(i)->isConnected = false;
        affectedItem->setPixmap(0, disconnected);
	connectHostB->setEnabled(true);
        disconnectHostB->setEnabled(false);
	return;
     }
 }
 
  for (uint i=0; i < devices.size(); i++)
  {
    if (devices[i]->mgrID == mgrID)
    {
      affectedItem = localListView->findItem(devices[i]->label, 0);
      if (!affectedItem) return;
      affectedItem->setPixmap(1, stopPix);
      affectedItem->setPixmap(2, NULL);
      affectedItem->setText(4, TQString(""));
      runServiceB->setEnabled(true);
      stopServiceB->setEnabled(false);
      devices[i]->managed = false;
      devices[i]->restart();
      return;
	
    }
  }
      
          
}

void INDIDriver::ClientprocessRightButton( TQListViewItem *item, const TQPoint &p, int column)
{

  column = 0;

  if (item && item->childCount() == 0)
  	ClientpopMenu->popup(p);
}

void INDIDriver::LocalprocessRightButton( TQListViewItem *item, const TQPoint &p, int column)
{

  column = 0;

  if (item && item->childCount() == 0)
  	LocalpopMenu->popup(p);
}

void INDIDriver::activateRunService()
{
  processDeviceStatus(0);
}

void INDIDriver::activateStopService()
{
  processDeviceStatus(1);
}

void INDIDriver::activateHostConnection()
{
  processHostStatus(0);
}

void INDIDriver::activateHostDisconnection()
{
  processHostStatus(1);
}
    
void INDIDriver::updateLocalButtons()
{
  
  if (localListView->selectedItem() == NULL)
   return;
 
  for (uint i=0; i < devices.size(); i++)
     if (localListView->selectedItem()->text(0) == devices[i]->label)
     {
	runServiceB->setEnabled(devices[i]->state == 0);
	stopServiceB->setEnabled(devices[i]->state == 1);
	
	serverLogText->clear();
	
	for ( TQStringList::Iterator it = devices[i]->serverBuffer.begin(); it != devices[i]->serverBuffer.end(); ++it )
	   serverLogText->insert(*it);
	
	break;
     }

}

void INDIDriver::updateClientButtons()
{
 INDIHostsInfo *hostInfo;
 if (clientListView->currentItem() == NULL)
  return;


for (uint i=0; i < ksw->data()->INDIHostsList.count(); i++)
   {
     hostInfo = ksw->data()->INDIHostsList.at(i);
     if (clientListView->currentItem()->text(1) == hostInfo->name && clientListView->currentItem()->text(2) == hostInfo->portnumber)
     {
       connectHostB->setEnabled(!hostInfo->isConnected);
       disconnectHostB->setEnabled(hostInfo->isConnected);
       break;
     }
    }
   
}

    
void INDIDriver::processDeviceStatus(int id)
{
  if (localListView->selectedItem() == NULL)
    return;

   for (uint i=0; i < devices.size(); i++)
     if (localListView->selectedItem()->text(0) == devices[i]->label)
     {
	devices[i]->state = (id == 0) ? 1 : 0;
	if (devices[i]->state)
	{

	  ksw->getINDIMenu()->setCustomLabel(devices[i]->label);
	  devices[i]->label = ksw->getINDIMenu()->currentLabel;

	  devices[i]->serverBuffer.clear();
	  
	  if (!runDevice(devices[i]))
	  {
	   devices[i]->restart();
	   return;
	  }

	  if (devices[i]->mode == IDevice::M_LOCAL)
	  {
	       //Allow time for the INDI server to listen
	  	usleep(50000);

	  	if (!ksw->getINDIMenu()->processServer())
	  	{
	   		devices[i]->restart();
	   		return;
	  	}
	  }

	  localListView->selectedItem()->setPixmap(1, runningPix);
	  localListView->selectedItem()->setText(4, TQString("%1").arg(devices[i]->indiPort));
	  runServiceB->setEnabled(false);
	  stopServiceB->setEnabled(true);
	  
	  return;
	}
	
	  if (devices[i]->mode == IDevice::M_LOCAL)
	  	ksw->getINDIMenu()->processServer();
		
	  localListView->selectedItem()->setPixmap(1, stopPix);
	  localListView->selectedItem()->setPixmap(2, NULL);
	  localListView->selectedItem()->setText(4, TQString(""));
	  runServiceB->setEnabled(true);
	  stopServiceB->setEnabled(false);
	  devices[i]->restart();
	  updateMenuActions();
	  return;
     }
}

void INDIDriver::processHostStatus(int id)
{
   int mgrID;
   bool toConnect = (id == 0);
   TQListViewItem *currentItem = clientListView->selectedItem();
   if (!currentItem) return;
   INDIHostsInfo *hostInfo;

   for (uint i=0; i < ksw->data()->INDIHostsList.count(); i++)
   {
     hostInfo = ksw->data()->INDIHostsList.at(i);
     if (currentItem->text(1) == hostInfo->name && currentItem->text(2) == hostInfo->portnumber)
     {
        // Nothing changed, return
        if (hostInfo->isConnected == toConnect)
	 return;

	// connect to host
	if (toConnect)
	{
	   // if connection successful
          if ( (mgrID = ksw->getINDIMenu()->processClient(hostInfo->hostname, hostInfo->portnumber)) >= 0)
	  {
	    currentItem->setPixmap(0, connected);
	    hostInfo->isConnected = true;
	    hostInfo->mgrID = mgrID;
	    connectHostB->setEnabled(false);
	    disconnectHostB->setEnabled(true);
	  }
	}
	else
	{
	  ksw->getINDIMenu()->removeDeviceMgr(hostInfo->mgrID);
	  hostInfo->mgrID = mgrID = -1;
	  hostInfo->isConnected = false;
	  currentItem->setPixmap(0, disconnected);
	  connectHostB->setEnabled(true);
	  disconnectHostB->setEnabled(false);
	  updateMenuActions();
	}
	
	

       }
    }
}

void INDIDriver::updateMenuActions()
{
  // We iterate over devices, we enable INDI Control Panel if we have any active device
  // We enable capture image sequence if we have any imaging device
  
  TDEAction *tmpAction;
  INDIMenu *devMenu = ksw->getINDIMenu();
  bool activeDevice = false;
  bool activeImaging = false;
  INDI_P *imgProp = NULL;
  
  if (devMenu == NULL)
     return;
  
  if (devMenu->mgr.count() > 0)
   activeDevice = true;
   
  for (uint i=0; i < devMenu->mgr.count(); i++)
  {
	for (uint j=0; j < devMenu->mgr.at(i)->indi_dev.count(); j++)
	{
  		        imgProp = devMenu->mgr.at(i)->indi_dev.at(j)->findProp("CCD_EXPOSE_DURATION");
			if (imgProp && devMenu->mgr.at(i)->indi_dev.at(j)->isOn())
			{
			  activeImaging = true;
			  break;
			}
	}
  }
   
  tmpAction = ksw->actionCollection()->action("indi_control_panel");
  if (!tmpAction)
  	kdDebug() << "Warning: indi_control_panel action not found" << endl;
  else
  	tmpAction->setEnabled(activeDevice);
  
  tmpAction = ksw->actionCollection()->action("capture_sequence");
  if (!tmpAction)
  	kdDebug() << "Warning: capture_sequence action not found" << endl;
  else
  	tmpAction->setEnabled(activeImaging);
  
}

bool INDIDriver::runDevice(IDevice *dev)
{
  dev->indiPort = getINDIPort();

  if (dev->indiPort < 0)
  {
   KMessageBox::error(0, i18n("Cannot start INDI server: port error."));
   return false;
  }

  dev->proc = new TDEProcess;
  
  *dev->proc << "indiserver";
  *dev->proc << "-v" << "-r" << "0" << "-p" << TQString("%1").arg(dev->indiPort) << dev->driver;
  
  // Check Mode
  dev->mode = localR->isChecked() ? IDevice::M_LOCAL : IDevice::M_SERVER;
  
  if (dev->mode == IDevice::M_LOCAL)
    localListView->selectedItem()->setPixmap(2, localMode);
  else
    localListView->selectedItem()->setPixmap(2, serverMode);

  connect(dev->proc, TQT_SIGNAL(receivedStderr (TDEProcess *, char *, int)),  dev, TQT_SLOT(processstd(TDEProcess *, char*, int)));

  dev->proc->start(TDEProcess::NotifyOnExit, TDEProcess::Stderr);
  //dev->proc->start();
  
  return (dev->proc->isRunning());
}

void INDIDriver::removeDevice(IDevice *dev)
{

  for (unsigned int i=0 ; i < devices.size(); i++)
     if (dev->label == devices[i]->label)
     	devices[i]->restart();
}

void INDIDriver::removeDevice(TQString deviceLabel)
{
  for (unsigned int i=0 ; i < devices.size(); i++)
     if (deviceLabel == devices[i]->label)
     	devices[i]->restart();

}

void INDIDriver::saveDevicesToDisk()
{

 TQFile file;
 TQString elementData;

 file.setName( locateLocal( "appdata", "drivers.xml" ) ); //determine filename in local user KDE directory tree.

 if ( !file.open( IO_WriteOnly))
 {
  TQString message = i18n( "unable to write to file 'drivers.xml'\nAny changes to INDI device drivers will not be saved." );
 KMessageBox::sorry( 0, message, i18n( "Could Not Open File" ) );
  return;
 }

 TQTextStream outstream(&file);

 // Let's write drivers first
 outstream << "<ScopeDrivers>" << endl;
 for (unsigned int i=0; i < driversList.count(); i++)
  outstream << "       <driver>" << driversList[i] << "</driver>" << endl;
 outstream << "</ScopeDrivers>" << endl;

 // Next we write devices, in the following order:
 // Telescopes, CCDs, Filter Wheels, Video, Dome, GPS

  // #1 Telescopes
  outstream << "<devGroup group='Telescopes'>" << endl;
  for (unsigned i=0; i < devices.size(); i++)
  {
     if (devices[i]->deviceType == KSTARS_TELESCOPE)
     {
	outstream << TQString("<device label='%1' focal_length='%2' aperture='%3'>").arg(devices[i]->label).arg(devices[i]->focal_length > 0 ? devices[i]->focal_length : -1).arg(devices[i]->aperture > 0 ? devices[i]->aperture : -1) << endl;

	outstream << "       <driver>" << devices[i]->driver << "</driver>" << endl;
	outstream << "       <version>" << devices[i]->version << "</version>" << endl;
        outstream << "</device>" << endl;
      }
   }
   outstream << "</devGroup>" << endl;

   // #2 CCDs
   outstream << "<devGroup group='CCDs'>" << endl;
   for (unsigned i=0; i < devices.size(); i++)
   {
     if (devices[i]->deviceType == KSTARS_CCD)
     {
	outstream << TQString("<device label='%1'>").arg(devices[i]->label) << endl;
	outstream << "       <driver>" << devices[i]->driver << "</driver>" << endl;
	outstream << "       <version>" << devices[i]->version << "</version>" << endl;
        outstream << "</device>" << endl;
     }
  }
  outstream << "</devGroup>" << endl;

  // #3 Filter wheels
  outstream << "<devGroup group='Filter Wheels'>" << endl;
   for (unsigned i=0; i < devices.size(); i++)
   {
     if (devices[i]->deviceType == KSTARS_FILTER)
     {
	outstream << TQString("<device label='%1'>").arg(devices[i]->label) << endl;
	outstream << "       <driver>" << devices[i]->driver << "</driver>" << endl;
	outstream << "       <version>" << devices[i]->version << "</version>" << endl;
        outstream << "</device>" << endl;
     }
  }
  outstream << "</devGroup>" << endl;

   // #4 Video
   outstream << "<devGroup group='Video'>" << endl;
   for (unsigned i=0; i < devices.size(); i++)
   {
     if (devices[i]->deviceType == KSTARS_VIDEO)
     {
	outstream << TQString("<device label='%1'>").arg(devices[i]->label) << endl;
	outstream << "       <driver>" << devices[i]->driver << "</driver>" << endl;
	outstream << "       <version>" << devices[i]->version << "</version>" << endl;
        outstream << "</device>" << endl;
     }
   }
   outstream << "</devGroup>" << endl;

   file.close();

}

bool INDIDriver::isDeviceRunning(TQString deviceLabel)
{

    for (unsigned int i=0 ; i < devices.size(); i++)
     if (deviceLabel == devices[i]->label)
     {
       if (!devices[i]->proc)
        return false;
       else return (devices[i]->proc->isRunning());
     }

    return false;

}

int INDIDriver::getINDIPort()
{

  lastPort+=5;

  KExtendedSocket ks(TQString(), lastPort, KExtendedSocket::passiveSocket | KExtendedSocket::noResolve);

  for (uint i=0 ; i < 10; i++)
  {
    if (ks.listen() < 0)
    {
      lastPort+=5;
      ks.setPort(lastPort);
    }
    else
     return lastPort;
  }

   return -1;
}

bool INDIDriver::readXMLDriver()
{
  TQString indiFile("drivers.xml");
  TQFile file;
  char errmsg[1024];

  if ( !KSUtils::openDataFile( file, indiFile ) )
  {
     KMessageBox::error(0, i18n("Unable to find device driver file 'drivers.xml'. Please locate the file and place it in one of the following locations:\n\n \t$(TDEDIR)/share/apps/kstars/%1 \n\t~/.trinity/share/apps/kstars/%1"));

    return false;
 }

 signed char c;
 LilXML *xmlParser = newLilXML();
 XMLEle *root = NULL;

 while ( (c = (signed char) file.getch()) != -1)
 {
    root = readXMLEle(xmlParser, c, errmsg);

    if (root)
    {
      if (!buildDeviceGroup(root, errmsg))
         prXMLEle(stderr, root, 0);

      delXMLEle(root);
    }
    else if (errmsg[0])
    {
      kdDebug() << TQString(errmsg);
      return false;
    }
  }

 delLilXML(xmlParser);
 return true;

}

bool INDIDriver::buildDriversList( XMLEle *root, char* /*errmsg[]*/)
{

  XMLEle *ep;

  for (ep = nextXMLEle (root, 1); ep != NULL; ep = nextXMLEle (root, 0))
      driversList << pcdataXMLEle(ep);

  return true;

}

bool INDIDriver::buildDeviceGroup(XMLEle *root, char errmsg[])
{

  XMLAtt *ap;
  XMLEle *ep;
  TQString groupName;
  int groupType = KSTARS_TELESCOPE;

  if (!strcmp(tagXMLEle(root), "ScopeDrivers"))
    return buildDriversList(root, errmsg);
 
  // avoid overflow
  if (strlen(tagXMLEle(root)) > 1024)
   return false;

  // Get device grouping name
  ap = findXMLAtt(root, "group");

  if (!ap)
  {
    snprintf(errmsg, ERRMSG_SIZE, "Tag %.64s does not have a group attribute", tagXMLEle(root));
    return false;
  }

  groupName = valuXMLAtt(ap);
  
  if (groupName.find("Telescopes") != -1)
    groupType = KSTARS_TELESCOPE;
  else if (groupName.find("CCDs") != -1)
    groupType = KSTARS_CCD;
  else if (groupName.find("Filter") != -1)
    groupType = KSTARS_FILTER;
  else if (groupName.find("Video") != -1)
    groupType = KSTARS_VIDEO;
  else if (groupName.find("Focusers") != -1)
    groupType = KSTARS_FOCUSER;
  else if (groupName.find("Domes") != -1)
    groupType = KSTARS_DOME;
  else if (groupName.find("GPS") != -1)
    groupType = KSTARS_GPS;


  //TDEListViewItem *group = new TDEListViewItem(topItem, lastGroup);
  TQListViewItem *group = new TQListViewItem(localListView, lastGroup);
  group->setText(0, groupName);
  lastGroup = group;
  //group->setOpen(true);


  for (ep = nextXMLEle(root, 1) ; ep != NULL ; ep = nextXMLEle(root, 0))
  /*for (int i = 0; i < root->nel; i++)*/
	if (!buildDriverElement(ep, group, groupType, errmsg))
	  return false;

  return true;
}

bool INDIDriver::buildDriverElement(XMLEle *root, TQListViewItem *DGroup, int groupType, char errmsg[])
{
  XMLAtt *ap;
  XMLEle *el;
  IDevice *dv;
  TQString label;
  TQString driver;
  TQString version;
  double focal_length (-1), aperture (-1);

  ap = findXMLAtt(root, "label");
  if (!ap)
  {
    snprintf(errmsg, ERRMSG_SIZE, "Tag %.64s does not have a label attribute", tagXMLEle(root));
    return false;
  }

  label = valuXMLAtt(ap);

  // Let's look for telescope-specfic attributes: focal length and aperture
  ap = findXMLAtt(root, "focal_length");
  if (ap)
   focal_length = TQString(valuXMLAtt(ap)).toDouble();

  ap = findXMLAtt(root, "aperture");
  if (ap)
   aperture = TQString(valuXMLAtt(ap)).toDouble();


  el = findXMLEle(root, "driver");

  if (!el)
   return false;

  driver = pcdataXMLEle(el);
  
  el = findXMLEle(root, "version");

  if (!el)
   return false;

  version = pcdataXMLEle(el);

  TQListViewItem *device = new TQListViewItem(DGroup, lastDevice);

  device->setText(0, TQString(label));
  device->setPixmap(1, stopPix);
  device->setText(3, TQString(version));

  lastDevice = device;

  dv = new IDevice(label, driver, version);
  dv->deviceType = groupType;
  connect(dv, TQT_SIGNAL(newServerInput()), this, TQT_SLOT(updateLocalButtons()));
  if (focal_length > 0)
   dv->focal_length = focal_length;
  if (aperture > 0)
   dv->aperture = aperture;
  
  devices.push_back(dv);

  // SLOTS/SIGNAL, pop menu, indi server logic
  return true;
}

int INDIDriver::activeDriverCount()
{
  int count = 0;

  for (uint i=0; i < devices.size(); i++)
    if (devices[i]->state && devices[i]->mode == IDevice::M_LOCAL)
      count++;

  for (uint i=0; i < ksw->data()->INDIHostsList.count(); i++)
    if (ksw->data()->INDIHostsList.at(i)->isConnected)
      count++;


  return count;

}

void INDIDriver::addINDIHost()
{
  INDIHostConf hostConf(this);
  hostConf.setCaption(i18n("Add Host"));
  bool portOk = false;

  if (hostConf.exec() == TQDialog::Accepted)
  {
    INDIHostsInfo *hostItem = new INDIHostsInfo;
    hostItem->name        = hostConf.nameIN->text();
    hostItem->hostname    = hostConf.hostname->text();
    hostItem->portnumber  = hostConf.portnumber->text();
    hostItem->isConnected = false;
    hostItem->mgrID       = -1;

    hostItem->portnumber.toInt(&portOk);

    if (portOk == false)
    {
     KMessageBox::error(0, i18n("Error: the port number is invalid."));
     return;
    }

    //search for duplicates
    for (uint i=0; i < ksw->data()->INDIHostsList.count(); i++)
     if (hostItem->name   == ksw->data()->INDIHostsList.at(i)->name &&
         hostItem->portnumber == ksw->data()->INDIHostsList.at(i)->portnumber)
     {
       KMessageBox::error(0, i18n("Host: %1 Port: %2 already exists.").arg(hostItem->name).arg(hostItem->portnumber));
       return;
     }

    ksw->data()->INDIHostsList.append(hostItem);

    TQListViewItem *item = new TQListViewItem(clientListView);
    item->setPixmap(0, disconnected);
    item->setText(1, hostConf.nameIN->text());
    item->setText(2, hostConf.portnumber->text());

  }

    saveHosts();
}



void INDIDriver::modifyINDIHost()
{

  INDIHostConf hostConf(this);
  hostConf.setCaption(i18n("Modify Host"));

  TQListViewItem *currentItem = clientListView->currentItem();

  if (currentItem == NULL)
   return;

  for (uint i=0; i < ksw->data()->INDIHostsList.count(); i++)
     if (currentItem->text(1) == ksw->data()->INDIHostsList.at(i)->name &&
         currentItem->text(2) == ksw->data()->INDIHostsList.at(i)->portnumber)
     {

        hostConf.nameIN->setText(ksw->data()->INDIHostsList.at(i)->name);
  	hostConf.hostname->setText(ksw->data()->INDIHostsList.at(i)->hostname);
  	hostConf.portnumber->setText(ksw->data()->INDIHostsList.at(i)->portnumber);

  	if (hostConf.exec() == TQDialog::Accepted)
  	{
    	INDIHostsInfo *hostItem = new INDIHostsInfo;
	hostItem->name       = hostConf.nameIN->text();
    	hostItem->hostname   = hostConf.hostname->text();
    	hostItem->portnumber = hostConf.portnumber->text();

    	currentItem->setText(1, hostConf.nameIN->text());
    	currentItem->setText(2, hostConf.portnumber->text());

    	ksw->data()->INDIHostsList.replace(clientListView->itemIndex(currentItem), hostItem);

    	saveHosts();
  	}

     }
}

void INDIDriver::removeINDIHost()
{

 if (clientListView->currentItem() == NULL)
  return;

 for (uint i=0; i < ksw->data()->INDIHostsList.count(); i++)
     if (clientListView->currentItem()->text(1) == ksw->data()->INDIHostsList.at(i)->name &&
         clientListView->currentItem()->text(2) == ksw->data()->INDIHostsList.at(i)->portnumber)
   {
        if (ksw->data()->INDIHostsList.at(i)->isConnected)
        {
           KMessageBox::error( 0, i18n("You need to disconnect the client before removing it."));
           return;
        }

        if (KMessageBox::warningContinueCancel( 0, i18n("Are you sure you want to remove the %1 client?").arg(clientListView->currentItem()->text(1)), i18n("Delete Confirmation"),KStdGuiItem::del())!=KMessageBox::Continue)
           return;
	   
 	ksw->data()->INDIHostsList.remove(i);
	clientListView->takeItem(clientListView->currentItem());
	break;
   }

 

 saveHosts();

}

void INDIDriver::saveHosts()
{

 TQFile file;
 TQString hostData;

 file.setName( locateLocal( "appdata", "indihosts.xml" ) ); //determine filename in local user KDE directory tree.

 if ( !file.open( IO_WriteOnly))
 {
  TQString message = i18n( "unable to write to file 'indihosts.xml'\nAny changes to INDI hosts configurations will not be saved." );
 KMessageBox::sorry( 0, message, i18n( "Could Not Open File" ) );
  return;
 }

 TQTextStream outstream(&file);

 for (uint i= 0; i < ksw->data()->INDIHostsList.count(); i++)
 {

 hostData  = "<INDIHost name='";
 hostData += ksw->data()->INDIHostsList.at(i)->name;
 hostData += "' hostname='";
 hostData += ksw->data()->INDIHostsList.at(i)->hostname;
 hostData += "' port='";
 hostData += ksw->data()->INDIHostsList.at(i)->portnumber;
 hostData += "' />\n";

 outstream << hostData;

 }

  file.close();

}

INDIDriver::~INDIDriver()
{

  for (uint i=0; i < devices.size(); i++)
   delete (devices[i]);

}

IDevice::IDevice(TQString inLabel, TQString inDriver, TQString inVersion)
{
  label = inLabel;;
  driver = inDriver;;
  version = inVersion;

  // Initially off
  state = 0;

  // No port initially
  indiPort = -1;

  // not yet managed by DeviceManager
  managed = false;

  mgrID = -1;

  focal_length = -1;
  aperture = -1;

  proc = NULL;

}

void IDevice::processstd(TDEProcess* /*proc*/, char* buffer, int /*buflen*/)
{
  serverBuffer.append(buffer);
  emit newServerInput();
}


IDevice::~IDevice()
{
  if (proc)
      proc->kill();

}

void IDevice::restart()
{

  mgrID = -1;

  state = 0;

  indiPort = -1;

  if (proc)
  	proc->kill();

  proc = NULL;

}

#include "indidriver.moc"
