// WS-POS version 1.3 参照実装
// 
// 実装 version 0.6 

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace WSPOSInitiative.Common
{
    /// <summary>
    /// セッションコンテキストの実装
    /// Implementation of the session context
    /// </summary>
    class SessionContextDefaultImpl : ISessionContext
    {
        protected IList<string> _tempFileNamesForDeleteWhenCloseDevice = new SynchronizedCollection<string>();
        protected Queue<TempFileUploadUriPair> _tempFileUploadUriPairs = new Queue<TempFileUploadUriPair>();

        /// <summary>
        /// ログ出力用
        /// この実装ではログ出力はしないが、派生クラスで使用するかもしれないため保持しておく
        /// Log output.
        /// A log does not output in this class. However, the log interface is held in order to use it by an inherited class. 
        /// </summary>
        protected ILog _log;

        /// <summary>
        /// デフォルトコンストラクタ 使用できないようprivate
        /// Default constractor, It is declared as private so that it cannot call.
        /// </summary>
        private SessionContextDefaultImpl() { }

        /// <summary>
        /// コンストラクタ
        /// Constructor
        /// </summary>
        /// <param name="sessionID">セッションID | Session ID</param>
        /// <param name="device">POSのデバイス | POS Device</param>
        /// <param name="consumerEventPort">双方向通信時のコンシューマイベントポートのチャネル | The channel of the consumer event port at the time of bi-directional communication</param>
        /// <param name="devicename">POSfor.NET,OpenPOSのデバイス名 | Device Name of POS for .NET or OpenPOS </param>
        /// <param name="log">ログインスタンス | log instance </param>
        public SessionContextDefaultImpl(string sessionID, Microsoft.PointOfService.PosDevice device, object consumerEventPort, ILog log, string devicename)
        {
            _log = log;

            LastAccessDateTime = DateTime.Now;
            ConsumerID = sessionID;
            Device = device;
            ConsumerEventPort = consumerEventPort;
            DeviceName = devicename;
            IsPollingNow = false;
            DeviceThread = new WorkerThreadHolder();

            if (consumerEventPort == null)
            {
                this.SetEventResponseCalled = new EventWait();
                this.DeviceEventHappened = new EventWait();
                this.OtherPollForUPOSEventCalled = new EventWait();
                this.PreviousPollForUPOSEventEnded = new EventWait();
            }

            UPOSEventHandlingOnGoing = false;
        }

        /// <summary>
        /// POSのデバイス
        /// The POS device
        /// </summary>
        public Microsoft.PointOfService.PosDevice Device { get; set; }

        /// <summary>
        /// POS for.NET,OpenPOSのデバイス名
        /// the device name of OpenPOS and POS for .NET
        /// </summary>
        public string DeviceName { get; set; }

        /// <summary>
        /// このセッションに関連付けられたデバイスのDataEventをハンドリングする
        /// DataEvent of the device related with this session is handled. 
        /// </summary>
        public void DeviceDataEventHandler(object sender, Microsoft.PointOfService.DataEventArgs e)
        {
            ServiceDataEvent(this, e);
        }

        /// <summary>
        /// このセッションに関連付けられたデバイスのDirectIOEventをハンドリングする
        /// DirectIOEvent of the device related with this session is handled. 
        /// </summary>
        public void DeviceDirectIOEventHandler(object sender, Microsoft.PointOfService.DirectIOEventArgs e)
        {
            ServiceDirectIOEvent(this, e);
        }

        /// <summary>
        /// このセッションに関連付けられたデバイスのErrorEventをハンドリングする
        /// ErrorEvent of the device related with this session is handled. 
        /// </summary>
        public void DeviceErrorEventHandler(object sender, Microsoft.PointOfService.DeviceErrorEventArgs e)
        {
            ServiceErrorEvent(this, e);
        }

        /// <summary>
        /// このセッションに関連付けられたデバイスのOutputCompleteEventをハンドリングする
        /// OutputCompleteEvent of the device related with this session is handled. 
        /// </summary>
        public void DeviceOutputCompleteEventHandler(object sender, Microsoft.PointOfService.OutputCompleteEventArgs e)
        {
            ServiceOutputCompleteEvent(this, e);
        }

        /// <summary>
        /// このセッションに関連付けられたデバイスのStatusUpdateEventをハンドリングする
        /// StatusUpdateEvent of the device related with this session is handled. 
        /// </summary>
        public void DeviceStatusUpdateEventHandler(object sender, Microsoft.PointOfService.StatusUpdateEventArgs e)
        {
            ServiceStatusUpdateEvent(this, e);
        }

        /// <summary>
        /// セッションID
        /// Session ID
        /// </summary>
        public string ConsumerID { get; private set; }

        /// <summary>
        /// サービスプロバイダに通知するDataEventハンドラ
        ///  The DataEvent handler notified to a service provider
        /// </summary>
        public event EventHandler<Microsoft.PointOfService.DataEventArgs> ServiceDataEvent;

        /// <summary>
        /// サービスプロバイダに通知するDirectIOEventハンドラ
        ///  The DirectIOEvent handler notified to a service provider
        /// </summary>
        public event EventHandler<Microsoft.PointOfService.DirectIOEventArgs> ServiceDirectIOEvent;

        /// <summary>
        /// サービスプロバイダに通知するErrorEventハンドラ
        ///  The ErrorEvent handler notified to a service provider
        /// </summary>
        public event EventHandler<Microsoft.PointOfService.DeviceErrorEventArgs> ServiceErrorEvent;

        /// <summary>
        /// サービスプロバイダに通知するOutputCompleteEventハンドラ
        ///  The OutputCompleteEvent handler notified to a service provider
        /// </summary>
        public event EventHandler<Microsoft.PointOfService.OutputCompleteEventArgs> ServiceOutputCompleteEvent;

        /// <summary>
        /// サービスプロバイダに通知するStatusUpdateEventハンドラ
        ///  The StatusUpdateEvent handler notified to a service provider
        /// </summary>
        public event EventHandler<Microsoft.PointOfService.StatusUpdateEventArgs> ServiceStatusUpdateEvent;

        /// <summary>
        /// 双方向通信時のコンシューマイベントポートのチャネル
        /// The channel of the consumer event port at the time of bi-directional communication
        /// </summary>
        public object ConsumerEventPort { get; private set; }

        /// <summary>
        /// このコンテキストをサービスマネージャが最後に取得した際の日時
        /// Date and time when the session manager was the last capture this context
        /// </summary>
        public DateTime LastAccessDateTime { get; set; }

        /// <summary>
        /// ロングポーリング用のデバイスからのイベント待機カーネルイベント
        /// The kernel event resource from the device for long polling 
        /// </summary>
        public IEventWait DeviceEventHappened { get; private set; }

        /// <summary>
        /// ロングポーリング用のコンシューマからのイベントレスポンス待機カーネルイベント
        /// /// The kernel event resource from the device for long polling (response)
        /// </summary>
        public IEventWait SetEventResponseCalled { get; private set; }

        /// <summary>
        /// ロングポーリング時に別スレッドから同じロングポーリングが呼ばれたことを
        /// 前に待機していたスレッドに通知する待機イベント
        /// The standby event to notify the thread which was waiting in front that the same long polling was called from another thread at the time of long polling.
        /// </summary>
        public IEventWait OtherPollForUPOSEventCalled { get; private set; }

        /// <summary>
        /// ロングポーリング時に別スレッドから同じロングポーリングが呼ばれた際に
        /// 前に待機していたスレッドの終了を待つための待機イベント
        /// The standby event to wait for the end of the thread which was waiting in front, when the same long polling was called from another thread at the time of long polling.
        /// </summary>
        public IEventWait PreviousPollForUPOSEventEnded { get; private set; }

        /// <summary>
        /// ロングポーリング用のデバイスイベント引数保存
        /// Save deivce event argument for long polling
        /// </summary>
        public object DeviceEventArgs { get; set; }

        /// <summary>
        /// ロングポーリング用のデバイスイベント応答引数保存
        /// Save deivce event response argument for long polling
        /// </summary>
        public object DeviceEventResponse { get; set; }

        /// <summary>
        /// ロングポーリング用のイベント待ち状態を示す
        /// Indicates the event waiting state for long polling
        /// </summary>
        public bool IsPollingNow { get; set; }

        /// <summary>
        /// セッションが閉じられたか否かを示す
        /// That indicates whether the session is closed
        /// </summary>
        public bool IsClosed { get; set; }
    
        /// <summary>
        /// このセッションで用いるワーカースレッド
        /// The worker thread used for device access in this session 
        /// </summary>
        public WorkerThreadHolder DeviceThread { get; set; }

        /// <summary>
        /// プロバイダのセッションタイムアウト値(秒)
        /// provider sessioin timeout
        /// </summary>
        public int ProviderSessionTimeout { get; set; }

        /// <summary>
        /// ロングポーリング用のイベント待ちタイムアウト値
        /// timeout value for event long polling.
        /// </summary>
        public int EventPollingTimeout { get; set; }

        /// <summary>
        /// ロングポーリング/自己ホスト両用のイベント処理終了待ちタイムアウト値(秒)
        /// timeout value for event response.
        /// </summary>
        public int EventResponseTimeout { get; set; }

        /// <summary>
        /// CloseDevice時に、未削除のファイルを改めて削除する
        /// A temporary file name is held in the case of asynchronous operation. 
        /// </summary>
        public IList<string> TempFileNamesForDeleteWhenCloseDevice
        {
            get
            {
                return _tempFileNamesForDeleteWhenCloseDevice;
            }
        }

        /// <summary>
        /// 非同期動作の際に、テンポラリファイルのアップロード先を保持する
        /// A temporary file upload uri is held in the case of asynchronous operation. 
        /// </summary>
        public Queue<TempFileUploadUriPair> TempFileUploadUriPairs 
        { 
            get
            {
                return _tempFileUploadUriPairs;
            }
        }

        /// <summary>
        /// UPOS(OPOS)のイベントハンドリングが実行中か否かを保持する
        /// Is event handling of UPOS(OPOS) on going?
        /// </summary>
        public bool UPOSEventHandlingOnGoing { get; set; }

        /// <summary>
        /// DataContainedEventの際にClearInputPropertiesを呼び出すか否かを保持する
        /// Whether or not call the ClearInputProperties method DataContainedEvent in response to the keep.
        /// </summary>
        public bool CallClearInputProperties { get; set; }

        /// <summary>
        /// DataContainedEventの際にDataEventEnabledをtrueにするか否かを保持する
        /// Whether or not DataEventEnabled to true in response to DataContainedEvent to hold.
        /// </summary>
        public bool SetDataEventEnabled { get; set; }

        /// <summary>
        /// DataContainedEventの際に通知するプロパティのリスト
        /// The list of properties to notify DataContainedEvent
        /// </summary>
        public IList<string> EventRequestProperties { get; set; }

        /// <summary>
        /// OpenしているデバイスがLegacy(OPOS)であるか否か
        /// Whether or not the device is a legacy (OPOS)
        /// </summary>
        public bool IsLegacySO { get; set; }

        /// <summary>
        /// OPOS SO とのやりとりで 文字列をNIBBLE化する際に コードページの変換をするか否か
        /// Whether or not the code page conversion to string a NIBBLE in interacting with OPOS SO
        /// </summary>
        public bool CodePageConversion { get; set; }
    }
}
