/*
 * Copyright (c) 2013, 2020 Oracle and/or its affiliates and others.
 * All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0, which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception, which is available at
 * https://www.gnu.org/software/classpath/license.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 */

package com.sun.ts.tests.websocket.common.client;

import static com.sun.ts.tests.websocket.common.client.WebSocketCommonClient.logMsg;
import static com.sun.ts.tests.websocket.common.client.WebSocketCommonClient.logTrace;

import java.io.IOException;
import java.nio.ByteBuffer;

import com.sun.ts.tests.websocket.common.client.WebSocketCommonClient.Entity;
import com.sun.ts.tests.websocket.common.impl.StringPingMessage;
import com.sun.ts.tests.websocket.common.util.IOUtil;

import jakarta.websocket.EndpointConfig;
import jakarta.websocket.PongMessage;
import jakarta.websocket.RemoteEndpoint;
import jakarta.websocket.Session;

/**
 * The default {@link EndpointCallback} that is used in tests. This callback
 * sends an entity on onOpen to a server endpoint set by
 * {@link WebSocketCommonClient#setEntity(Object...)} or by
 * 
 * <pre>
 * setProperty(Property.CONTENT, ...)
 * </pre>
 * 
 * </p>
 * Note that no callback is used when no entity is defined to be sent to a
 * server side
 */
public class SendMessageCallback extends EndpointCallback {
  protected Entity entity;

  public SendMessageCallback(Entity entity) {
    super();
    this.entity = entity;
  }

  @Override
  public void onOpen(Session session, EndpointConfig config) {
    super.onOpen(session, config);
    logMsg("Sending entity", entity);
    RemoteEndpoint.Basic endpoint = session.getBasicRemote();
    try {
      if (entity.isInstance(String.class))
        sendString(endpoint, entity, 0);
      else if (entity.isInstance(ByteBuffer.class))
        sendBytes(endpoint, entity, 0);
      else if (entity.isInstance(PongMessage.class))
        sendPingPong(endpoint, entity.getEntityAt(PongMessage.class, 0));
      else
        sendObject(endpoint, entity.getEntityAt(Object.class, 0));
    } catch (Exception i) {
      throw new RuntimeException(i);
    }
  }

  protected void sendString(RemoteEndpoint.Basic endpoint, Entity entity,
      int index) throws IOException {
    String message = entity.getEntityAt(String.class, index);
    if (entity.length() - 1 > index) {
      endpoint.sendText(message, false);
      logTrace("RemoteEndpoint.Basic.sendText(", message, ", false)");
      sendString(endpoint, entity, index + 1);
    } else if (index > 0) {
      endpoint.sendText(message, true);
      logTrace("RemoteEndpoint.Basic.sendText(", message, ", true)");
    } else {
      endpoint.sendText(message);
      logTrace("RemoteEndpoint.Basic.sendText(", message, ")");
    }
  }

  protected void sendBytes(RemoteEndpoint.Basic endpoint, Entity entity,
      int index) throws IOException {
    ByteBuffer msg = entity.getEntityAt(ByteBuffer.class, index);
    String bytes = new String(msg.array());
    if (entity.length() - 1 > index) {
      endpoint.sendBinary(msg, false);
      logTrace("RemoteEndpoint.Basic.sendBinary(", bytes, ", false)");
      sendBytes(endpoint, entity, index + 1);
    } else if (index > 0) {
      endpoint.sendBinary(msg, true);
      logTrace("RemoteEndpoint.Basic.sendBinary(", bytes, ", true)");
    } else {
      endpoint.sendBinary(msg);
      logTrace("RemoteEndpoint.Basic.sendBinary(", bytes, ")");
    }
  }

  protected void sendPingPong(RemoteEndpoint.Basic endpoint, PongMessage pong)
      throws Exception {
    ByteBuffer buffer = pong.getApplicationData();
    String msg = IOUtil.byteBufferToString(buffer);
    if (StringPingMessage.class.isInstance(pong)) {
      endpoint.sendPing(buffer);
      logTrace("RemoteEndpoint.Basic.sendPing(", msg, ")");
    } else {
      endpoint.sendPong(buffer);
      logTrace("RemoteEndpoint.Basic.sendPong(", msg, ")");
    }
  }

  protected void sendObject(RemoteEndpoint.Basic endpoint, Object message)
      throws Exception {
    String entity = null;
    if (message.getClass().getName().equals("[B"))
      entity = new String((byte[]) message);
    else
      entity = message.toString();
    logTrace("RemoteEndpoint.Basic.sendObject(", entity, ")");
    endpoint.sendObject(message);
  }

}
