context: /* 
   * Copyright (C) 2008 Sasa Coh <sasacoh@gmail.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.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
   * 
   * WaveLib library sources http://www.codeproject.com/KB/graphics/AudioLib.aspx
   * 
   * Visit SipekSDK page at http://voipengine.googlepages.com/
   * 
   * Visit SIPek's home page at http://sipekphone.googlepages.com/ 
   * 
   */
  
  using System;
  using System.Collections.Generic;
  using System.Text;
  using System.Threading;
  using System.Threading.Tasks;
  using System.Timers;
  using System.Runtime.InteropServices;
  using System.Media;
  using System.Windows.Threading;
  using Sipek.Common;
  using Sipek.Common.CallControl;
  using System.ComponentModel;
  using System.Collections.Specialized;
  using ContactPoint.Common.Audio;
  using ContactPoint.Common;
  
  namespace Sipek.Sip
  {
      /// <summary>
      /// ConcreteFactory 
      /// Implementation of AbstractFactory. 
      /// </summary>
      public class SipekResources : IAbstractFactory
      {
          private readonly ICore _core; // reference to MainForm to provide timer context
          private readonly SipekConfigurator _config;
          private readonly ManualResetEvent _syncThreadFlag = new ManualResetEvent(false);
          private pjsipStackProxy _stackProxy;
  
          #region Constructor
          public SipekResources(ICore core)
          {
              _core = core;
  
              var syncThread = new Thread(SyncThread) {IsBackground = true};
              syncThread.SetApartmentState(ApartmentState.STA);
              syncThread.Start();
  
              if (!_syncThreadFlag.WaitOne(TimeSpan.FromSeconds(30)))
                  throw new InvalidOperationException("Can't start PjSIP sync thread! Timeout exceeded");
  
              _config = new SipekConfigurator(_core);
  
              _stackProxy = pjsipStackProxy.Instance;
              _callManager = CCallManager.Instance;
              _messenger = pjsipPresenceAndMessaging.Instance;
              _registrar = pjsipRegistrar.Instance;
  
              // initialize sip struct at startup
              SipConfigStruct.Instance.stunServer = this.Configurator.StunServerAddress;
              SipConfigStruct.Instance.publishEnabled = this.Configurator.PublishEnabled;
              SipConfigStruct.Instance.expires = this.Configurator.Expires;
              SipConfigStruct.Instance.VADEnabled = this.Configurator.VADEnabled;
              SipConfigStruct.Instance.ECTail = this.Configurator.ECTail;
              SipConfigStruct.Instance.nameServer = this.Configurator.NameServer;
  
  #if !DEBUG
              SipConfigStruct.Instance.logLevel = Logger.LogLevel*5;
  #endif
  
              // initialize modules
              _callManager.StackProxy = _stackProxy;
              _callManager.Config = _config;
              _callManager.Factory = this;
              _stackProxy.Config = _config;
              _registrar.Config = _config;
              _messenger.Config = _config;
  
              _core.SettingsManager["cfgSipAccountState"] = "0";
              _core.SettingsManager["cfgSipAccountIndex"] = "0";
          }
          #endregion Constructor
  
          #region AbstractFactory methods
          public ITimer CreateTimer()
          {
              return new GUITimer();
          }
  
          public IStateMachine CreateStateMachine()
          {
              return new CStateMachine();
          }
  
          public IStateMachine createStateMachine(ISynchronizeInvoke syncInvoke)
          {
              return new CStateMachine();
          }
  
          #endregion
  
          #region Other Resources
          public ICore Core
          {
              get { return _core; }
          }
  
          public pjsipStackProxy StackProxy
          {
              get { return _stackProxy; }
              set { _stackProxy = value; }
          }
  
          public SipekConfigurator Configurator
          {
              get { return _config; }
              set { }
          }
  
          private IRegistrar _registrar;
          public IRegistrar Registrar
          {
              get { return _registrar; }
          }
  
          private IPresenceAndMessaging _messenger;
          public IPresenceAndMessaging Messenger
          {
              get { return _messenger; }
          }
  
          private CCallManager _callManager;
          public CCallManager CallManager
          {
              //get { return CCallManager.Instance; }
              get { return _callManager; }
          }
  
          #endregion
  
          #region Sync thread
  
          private void SyncThread()
          {
              CommonDelegates.Initialize(Dispatcher.CurrentDispatcher);
  
              _syncThreadFlag.Set();
              Dispatcher.Run();
          }
  
          #endregion
      }
  
      #region Concrete implementations
  
      public class GUITimer : ITimer
      {
          System.Timers.Timer _guiTimer;
  
          public GUITimer()
          {
              _guiTimer = new System.Timers.Timer();
              if (this.Interval > 0) _guiTimer.Interval = this.Interval;
              _guiTimer.Interval = 100;
              _guiTimer.Enabled = true;
              _guiTimer.Elapsed += new ElapsedEventHandler(_guiTimer_Tick);
          }
  
          void _guiTimer_Tick(object sender, EventArgs e)
          {
              _guiTimer.Stop();
              //_elapsed(sender, e);
              // Synchronize thread with GUI because SIP stack works with GUI thread only
  
              // TODO: check! May occur disposing problems
              //if (/*(_form.Form.IsDisposed) || (_form.Form.Disposing) ||*/ (!_core.IsInitialized))
              //    return;
  
              CommonDelegates.SafeBeginInvoke(() => { if (_elapsed != null) _elapsed.Invoke(sender, e); });
          }
  
          public bool Start()
          {
              _guiTimer.Start();
              return true;
          }
  
          public bool Stop()
          {
              _guiTimer.Stop();
              return true;
          }
  
          private int _interval;
          public int Interval
          {
              get { return _interval; }
              set { _interval = value; _guiTimer.Interval = value; }
          }
  
          private TimerExpiredCallback _elapsed;
          public TimerExpiredCallback Elapsed
          {
              set
              {
                  _elapsed = value;
              }
          }
      }
  
  
      // Accounts
      public class SipekAccount : IAccount
      {
          private readonly ICore _core;
  
          public bool Enabled
          {
              get
              {
                  // Deperecated option
                  return true;
  
                  //bool value;
                  //if (this._core.SettingsManager["cfgSipAccountEnabled"] != null && Boolean.TryParse(this._core.SettingsManager["cfgSipAccountEnabled"].ToString(), out value))
                  //{
                  //    return value;
                  //}
                  //return false;
              }
  
              set
              {
                  //this._core.SettingsManager["cfgSipAccountEnabled"] = value;
              }
          }
  
          /// <summary>
          /// Temp storage!
          /// The account index assigned by voip stack
          /// </summary>
          public int Index
          {
              get
              {
                  int value;
                  if (this._core.SettingsManager["cfgSipAccountIndex"] != null && Int32.TryParse(this._core.SettingsManager["cfgSipAccountIndex"].ToString(), out value))
                  {
                      return value;
                  }
                  return -1;
              }
              set 
              {
                  this._core.SettingsManager["cfgSipAccountIndex"] = value;
              }
          }
  
          /// <summary>
          /// 
          /// </summary>
          /// <param name="index">the account identification used by configuration (values 0..4)</param>
          public SipekAccount(ICore core)
          {
              _core = core;
          }
  
          #region Properties
  
          public string AccountName
          {
              get
              {
                  if (this._core.SettingsManager["cfgSipAccountName"] != null)
                      return this._core.SettingsManager["cfgSipAccountName"].ToString();
                  else
                      return "";
              }
              set
              {
                  this._core.SettingsManager["cfgSipAccountName"] = value;
              }
          }
  
          public string HostName
          {
              get
              {
                  if (this._core.SettingsManager["cfgSipAccountAddress"] != null)
                      return this._core.SettingsManager["cfgSipAccountAddress"].ToString();
                  else
                      return "";
              }
              set
              {
                  this._core.SettingsManager["cfgSipAccountAddress"] = value;
              }
          }
  
          public string Id
          {
              get
              {
                  if (this._core.SettingsManager["cfgSipAccountId"] != null)
                      return this._core.SettingsManager["cfgSipAccountId"].ToString();
                  else
                      return "";
              }
              set
              {
                  this._core.SettingsManager["cfgSipAccountId"] = value;
              }
          }
  
          public string UserName
          {
              get
              {
                  if (this._core.SettingsManager["cfgSipAccountUsername"] != null)
                      return this._core.SettingsManager["cfgSipAccountUsername"].ToString();
                  else
                      return "";
              }
              set
              {
                  this._core.SettingsManager["cfgSipAccountUsername"] = value;
              }
          }
  
          public string Password
          {
              get
              {
                  if (this._core.SettingsManager["cfgSipAccountPassword"] != null)
                      return this._core.SettingsManager["cfgSipAccountPassword"].ToString();
                  else
                      return "";
              }
              set
              {
                  this._core.SettingsManager["cfgSipAccountPassword"] = value;
              }
          }
  
          public string DisplayName
          {
              get
              {
                  if (this._core.SettingsManager["cfgSipAccountDisplayName"] != null)
                      return this._core.SettingsManager["cfgSipAccountDisplayName"].ToString();
  
                  return "";
              }
              set
              {
                  this._core.SettingsManager["cfgSipAccountDisplayName"] = value;
              }
          }
  
          public string DomainName
          {
              get
              {
                  if (this._core.SettingsManager["cfgSipAccountDomain"] != null)
                      return this._core.SettingsManager["cfgSipAccountDomain"].ToString();
  
                  return "";
              }
              set
              {
                  this._core.SettingsManager["cfgSipAccountDomain"] = value;
              }
          }
  
          public int RegState
          {
              get
              {
                  int value;
                  if (this._core.SettingsManager["cfgSipAccountState"] != null && int.TryParse(this._core.SettingsManager["cfgSipAccountState"].ToString(), out value))
                  {
                      return value;
                  }
                  return 0;
              }
              set
              {
                  this._core.SettingsManager["cfgSipAccountState"] = value;
              }
          }
  
          public string ProxyAddress
          {
              get
              {
                  if (this._core.SettingsManager["cfgSipAccountProxyAddress"] != null)
                      return this._core.SettingsManager["cfgSipAccountProxyAddress"].ToString();
                  else
                      return "";
              }
              set
              {
                  this._core.SettingsManager["cfgSipAccountProxyAddress"] = value;
              }
          }
  
          public ETransportMode TransportMode
          {
              get
              {
                  int value;
                  if (this._core.SettingsManager["cfgSipAccountTransport"] != null && int.TryParse(this._core.SettingsManager["cfgSipAccountTransport"].ToString(), out value))
                  {
                      return (ETransportMode)value;
                  }
                  return (ETransportMode.TM_UDP); // default
              }
              set
              {
                  this._core.SettingsManager["cfgSipAccountTransport"] = (int)value;
              }
          }
          #endregion
  
      }
  
      /// <summary>
      /// 
      /// </summary>
      public class SipekConfigurator : IConfiguratorInterface
      {
          private ICore _core;
          private int _defaultAccountIndex = -1;
  
          public SipekConfigurator(ICore core)
          {
              this._core = core;
          }
  
          public int DefaultAccountIndex
          {
  
gt:             get { return _defaultAccountIndex; }