/***************************************************************************
                          voiceconversion.cpp  -  description
                             -------------------
    begin                : 1230 2003
    copyright            : (C) 2003 by Mike K. Bennett (C)2004 by Steve gigijoe
    email                : mkb137b@hotmail.com, stevegigijoe@hotmail.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 "sipconnection.h"

#include <qsettings.h>
#include <qtimer.h>

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/soundcard.h>
#include <sys/ioctl.h>

#ifdef HAVE_CONFIG_H
 #include "config.h"
#endif

#ifdef HAS_KPHONE
  #include "dissipate2/sipmessage.h"
  #include "dissipate2/sipclient.h"
  #include "dissipate2/sipuser.h"
  #include "dissipate2/sipcall.h"
  #include "kphone/callaudio.h"
#endif

UserAgent::UserAgent(QString localIP, unsigned sipListenPort, unsigned rtpListenPort)
: client(NULL), user(NULL), call(NULL), member(NULL), audio(NULL)
{
#ifdef HAS_KPHONE

  QSettings settings;
  settings.writeEntry("/kphone/STUN/UseStun", "No");
  settings.writeEntry("/kphone/Media/MinPort", (int)rtpListenPort);
  settings.writeEntry("/kphone/Media/MaxPort", (int)rtpListenPort);

  Sip::setLocalAddress(localIP);

  QString uristr = Sip::getLocalAddress();
  if(uristr.isEmpty())
    return;

  //Listen on local address port 5060, but tell the remote External IP address port mapped
  client = new SipClient(0, 0, sipListenPort, false, false, "UDP");

  SipUri localuri(uristr);
  localuri.setFullname("gigijoe");
  user = new SipUser(client, localuri);

  audio = new CallAudio;
  audio->readAudioSettings();
  //audio->readVideoSettings();

  audio->setCodec(codecULAW);

  QObject::connect(audio, SIGNAL(outputDead()), this, SLOT(audioOutputDead()));
#endif
}

UserAgent::~UserAgent()
{
  releaseCall();
}

bool UserAgent::audioCheck()
{
#ifdef HAS_KPHONE
  int audio_fd;
  QSettings settings;
  QString audioDevice = settings.readEntry( "/kphone/audio/oss-filename", "/dev/dsp");

  audio_fd = ::open(audioDevice.latin1(), O_WRONLY | O_NONBLOCK );
  if(audio_fd)
  {
    ::close(audio_fd);
    return true;
  }
  else
#endif
    return false;
}

void UserAgent::outgoingCall(QString strRemoteUri)
{
#ifdef HAS_KPHONE
  call = new SipCall(user, QString::null, SipCall::StandardCall );

  QString subject = user->getUri().uri();
  call->setSubject(subject);

  audio->setBodyMask(call->getSdpMessageMask());

  SipUri remoteuri(strRemoteUri);
  audio->setRtpCodec(codecUnknown);
  audio->setVideoRtpCodec(codecUnknown);

  member = new SipCallMember(call, remoteuri);

  QObject::connect(member, SIGNAL(statusUpdated(SipCallMember *)), this, SLOT(callMemberStatusUpdated()));

  audio->setCurrentCall(call);

  client->updateIdentity(user, "");
                                                                             //audio->getVideoRtpCodec()
  member->requestInvite(audio->audioOut().message( audio->getRtpCodec(), codecUnknown, audio->getBodyMask()),  MimeContentType("application/sdp"));

  audio->attachToCallMember(member);
  
  QTimer *socketEventTimer = new QTimer(this);
  QObject::connect(socketEventTimer, SIGNAL(timeout()), this, SLOT(socketEventHandler()));
  socketEventTimer->start(1);
  
#endif
}

void UserAgent::incomingCall()
{
#ifdef HAS_KPHONE
  
  QObject::connect(client, SIGNAL(incomingCall(SipCall *, QString)), this, SLOT(incomingCall(SipCall *, QString )));
  
  QTimer *socketEventTimer = new QTimer(this);
  connect(socketEventTimer, SIGNAL(timeout()), this, SLOT(socketEventHandler()));
  socketEventTimer->start(1);
  
#endif
}

void UserAgent::socketEventHandler()
{
#ifdef HAS_KPHONE
    if(client)  
      client->doSelect(false);  //None bolck
#endif
}

void UserAgent::releaseCall()
{
#ifdef HAS_KPHONE
  if(call)
  {
    if(member->getState() == SipCallMember::state_RequestingInvite)
      member->declineInvite();
    else if(call->getCallStatus() != SipCall::callDead)
    {
      if(member->getState() == SipCallMember::state_Connected)
        member->requestDisconnect();
      else
      {
        member->cancelTransaction();
        if(audio->getCurrentCall() == call)
          audio->detachFromCall();
      }
    }
  }
  destructCall();
#endif
}

void UserAgent::incomingCall(SipCall *_call, QString body )
{
#ifdef HAS_KPHONE
  call = (SipCall *)_call;
  if(call->getSubject() == QString::null)
  {
    call->setSdpMessageMask(body);
    call->setSubject("Incoming call");
  }

//Accept call now

  if(member)
    QObject::disconnect(member, 0, this, 0);
  member = call->getMemberList().toFirst();
  if(member)
  {
    QObject::connect(member, SIGNAL(statusUpdated(SipCallMember *)), this, SLOT(callMemberStatusUpdated()));

    if(audio->checkCodec(member))
    {
      audio->setCurrentCall(call);
      audio->attachToCallMember(member);                                     //audio->getVideoRtpCodec()
      member->acceptInvite(audio->audioOut().message(audio->getRtpCodec(), codecUnknown, audio->getBodyMask()), MimeContentType("application/sdp"));
    }
    else
    {
      member->notAcceptableHere();
    }
  }
#endif
}

void UserAgent::callMemberStatusUpdated()
{
#ifdef HAS_KPHONE
  if(member->getState() == SipCallMember::state_Disconnected)
    releaseCallForce();
#endif
}

void UserAgent::releaseCallForce()
{
#ifdef HAS_KPHONE
  if(audio->getCurrentCall() == call)
    audio->detachFromCall();

  if(member)
    QObject::disconnect(member, 0, this, 0);

  destructCall();
#endif
}

void UserAgent::destructCall()
{
#ifdef HAS_KPHONE
    
  delete client;
  client = 0;

  delete call;
  call = 0;
  
  delete user;
  user = 0;
  
  delete audio;
  audio = 0;

#endif
}

void UserAgent::audioOutputDead()
{
#ifdef HAS_KPHONE
  //Broken output pipe, disconnecting unpolitely
  releaseCallForce();
#endif
}


#include "sipconnection.moc"
