using System;
using System.Threading;
using System.ServiceModel;

//サンプルコードでは、個々のクラスがどの名前空間・アセンブリに
//属しているのか表現するため、あえてusingは使用しない。
//using UnifiedPOS.POSPrinter;

namespace Console_POSPrinterConsumerBiDirectionSample
{
    /// <summary>
    /// POSPrinterの使用方法を説明する
    /// </summary>
    class POSPrinterTest
    {
        // このアプリケーションのためのコンシューマIDを定義する
        string consumerID = Guid.NewGuid().ToString();

        /// <summary>
        /// POSPrinterの使用方法を説明する
        /// </summary>
        public void Test()
        {
            // WS-POSを利用するための準備
            // チャネルの作成、イベント受信の準備、
            // WS-POSセッションの開始、KeepAliveの開始


            // 自己ホストとして、イベント受信クラスを実行する。
            // イベントはPOSPrinterEventServiceクラスで受信される。
            var posprinterEventServiceHost = new ServiceHost(typeof(POSPrinterEventService));
            posprinterEventServiceHost.Open();

            // WCFを使用してWS-POSサービスプロバイダに接続するための準備
            var channelFactory = new ChannelFactory<UnifiedPOS.POSPrinter.V1_2.POSPrinter>("POSPrinterPort");

            // POSPrinter WS-POSサービスプロバイダへのチャネル
            var posprinterChannel = channelFactory.CreateChannel();

            // WS-POS プロバイダのセッションを開始する。双方向通信のため、Endpointにイベント受信用エンドポイントを渡す
            // （ロングポーリングでは、nullを渡す）
            var eventEndpoint = posprinterEventServiceHost.BaseAddresses[0];
            posprinterChannel.OpenSession(consumerID, eventEndpoint.AbsoluteUri);

            // Keep AliveのためにWS-POSサービスプロバイダのセッションタイムアウト時間(秒)を取得
            var providerSessionTimoutSec = posprinterChannel.GetProviderSessionTimeout(consumerID);

            // Keep Aliveを開始する。タイマーのPeriodには、サービスプロバイダセッションタイムアウトの半分の指定を推奨
            var keepAliveTimer = new Timer(new TimerCallback(KeepAliveTimer_TimerCallback), posprinterChannel, 0, providerSessionTimoutSec * 1000 / 2);

            // これ以降は、OPOS / POS for .NET でのシーケンスと
            // 非常に似ている

            Console.WriteLine("Press ENTER to OpenDevice, Claim, Enable.");
            Console.ReadLine();

            // WS-POS プロバイダのデバイスをOpen, Claim, Enable
            posprinterChannel.OpenDevice(consumerID);
            posprinterChannel.Claim(consumerID, 1000);
            posprinterChannel.SetDeviceEnabled(consumerID, true);

            posprinterChannel.SetAsyncMode(consumerID, true);

            Console.WriteLine("Press ENTER to PrintNormal");
            Console.ReadLine();

            posprinterChannel.PrintNormal(consumerID, UnifiedPOS.POSPrinter.V1_2.PrinterStation.Receipt, "WS-POS Test Print\r\n");

            Console.WriteLine("Press ENTER to PrintBimtap");
            Console.ReadLine();

            try
            {
                posprinterChannel.PrintBitmap(consumerID, UnifiedPOS.POSPrinter.V1_2.PrinterStation.Receipt, "http://localhost/w-brand.png", 0, 0);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }

            Console.WriteLine("Press ENTER to Disable, Release, Close");
            Console.ReadLine();

            // UPOSの仕様では、デバイスをCloseすると、Release, Disableも行われる。
            // ネットワークトラフィックを軽減するため、連続して呼び出す場合は
            // CloseDeviceのみ呼び出すことを推奨
            // posprinterChannel.SetDeviceEnabled(consumerID, false);
            // posprinterChannel.Release(consumerID);
            posprinterChannel.CloseDevice(consumerID);

            // WS-POSの後始末
            // KeepAliveの停止、
            // WS-POSセッションの終了、イベント受信クラスの終了
            keepAliveTimer.Dispose();
            posprinterChannel.CloseSession(consumerID);
            posprinterEventServiceHost.Close();

        }

        /// <summary>
        /// WS-POS KeepAliveを行う
        /// </summary>
        void KeepAliveTimer_TimerCallback(object o)
        {
            var posprinterChannel = o as UnifiedPOS.POSPrinter.V1_2.POSPrinter;

            try
            {
                posprinterChannel.KeepAlive(consumerID);
            }
            catch (TimeoutException)
            {
                // サービスプロバイダとの通信がオフラインとなった場合は、
                // 再度 OpenSessionからやりなおす。
                // ただし、サービスプロバイダ側がセッションタイムアウトする前は、
                // OpenSessionできない。
                // このサンプルプログラムでは、何も処理をしていない

                Console.WriteLine("WS-POS KeepAlive Timeout happend.");
            }
        }


    }
}
