/*
 * Copyright (c) 2009 The openGion Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package org.opengion.hayabusa.servlet;

import java.net.URI;
// import java.io.IOException; 

import javax.websocket.ClientEndpoint;
import javax.websocket.ContainerProvider;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.CloseReason;
import javax.websocket.EndpointConfig; 
import javax.websocket.WebSocketContainer;

import javax.websocket.ClientEndpointConfig;
// import javax.websocket.ClientEndpointConfig;
import javax.websocket.Endpoint;
import javax.xml.bind.DatatypeConverter;
import java.util.Map;
import java.util.List;
import java.util.Arrays;

/**
 * Websocket Endpoint implementation class WebSocketClient
 *
 * Client を実行するには、%CATALINA_HOME%/lib/websocket-api.jar ではだめです。
 * META-INF\services\javax.websocket.ContainerProvider に、Provider を
 * 記述しておく必要があるそうです。
 *
 * 方法としては、
 *  ① tyrus-standalone-client-jdk-1.13.1.jar を使用する。
 *  ② %CATALINA_HOME%/lib/tomcat-websocket.jar を使用する。
 *       この場合、依存関係で、/lib/tomcat-util.jar 、bin/tomcat-juli.jar も
 *       使用します。
 *     ※ 今現在、java Client は動いていません。
 *
 */

@ClientEndpoint
public class WebSocketClient extends Endpoint {

	/**
	 * デフォルトコンストラクター
	 *
	 */
	public WebSocketClient() { super(); }	// これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。

	/**
	 * サーバーからの通知受信のためのコールバック
	 * 
	 * 引数は以下が設定可能だが、メソッド内で使用しないなら省略できる。
	 * 
	 * @param session サーバーの接続情報
	 * @param config 設定情報
	 */
	@OnOpen
	public void onOpen( final Session session, final EndpointConfig config ) {
		/* セッション確立時の処理 */
		System.out.println("[セッション確立]");
	}

	/**
	 * 5.テキストメッセージ受信時の処理
	 * 
	 * 引数は使用しなければ省略可能。
	 * 
	 * @param message サーバーから送信されたテキスト
	 * @param session 接続情報
	 */
	@OnMessage
	public void onMessage( final String message , final Session session ) {
		/* メッセージ受信時の処理 */
		System.out.println("[受信]:" + message);
	}

	/**
	 * 4.エラー時にコールされる。
	 * 
	 * 引数は使用しなければ省略可能。
	 * 
	 * @param session サーバーの接続情報
	 * @param th エラー
	 */
	@OnError
	public void onError( final Session session , final Throwable th ) {
		/* エラー発生時の処理 */
		System.out.println("[エラー発生]");
	}

	/**
	 * 3.切断時にコールされる。
	 * 
	 * 引数は使用しなければ省略可能。
	 * 
	 * @param session サーバーの接続情報
	 * @param reason 切断理由
	 */
	@OnClose
	public void onClose( final Session session, final CloseReason reason ) {
		/* セッション解放時の処理 */
		System.out.println("[セッション解放]");
	}

	/**
	 * メインメソッド。
	 * 
	 * @param args 引数
	 */
	public static void main( final String[] args ) throws Exception {
		// BASIC認証対応
		final ClientEndpointConfig.Configurator configurator = new ClientEndpointConfig.Configurator() {
			public void beforeRequest( final Map<String, List<String>> headers ) {
				headers.put("Authorization", Arrays.asList("Basic " + DatatypeConverter.printBase64Binary("admin:admin".getBytes())));
			}
		};

		final ClientEndpointConfig clientConfig = ClientEndpointConfig.Builder.create()
				.configurator(configurator)
				.build();

		// 初期化のため WebSocket コンテナのオブジェクトを取得する
		final WebSocketContainer container = ContainerProvider.getWebSocketContainer();
		// サーバー・エンドポイントの URI
		final URI uri = URI.create( "ws://localhost:8826/gf/wsdemo?AAA=BBB" );
		// サーバー・エンドポイントとのセッションを確立する
//		final Session session = container.connectToServer( new WebSocketClient(),uri );
		final Session session = container.connectToServer( new WebSocketClient(),clientConfig,uri );		// BASIC認証対応

		session.getBasicRemote().sendText("こんにちは");

		// 仮想マシンのシャットダウン・フックを登録(Ctrl-C で正常終了します)
		Runtime.getRuntime().addShutdownHook(
			new Thread( WebSocketClient.class.getName() ) {
				public void run() {
					// シャットダウン中は、LOGGER が実行されないようです。
					System.out.println( "Shutdown WebSocketClient ..." );
					try {
						session.close();
					}
					catch( final Throwable th ) {
						th.printStackTrace();
					}
				}
			}
		);

		int cnt = 0;
		while( session.isOpen() ) {
			Thread.sleep( 10 * 1000 );
			System.out.println( "open " + cnt );
			session.getBasicRemote().sendText( "カウンター:" +  (cnt++) );
		}

		System.out.println( "Session closed." );
		session.close();
	}
}
