/*
 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
 * agreements. See the NOTICE file distributed with this work for additional information regarding
 * copyright ownership. The ASF licenses this file to You 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.apache.geode.redis.internal.netty;

import java.nio.channels.SocketChannel;
import java.util.List;
import java.util.stream.Collectors;

import io.netty.channel.ChannelHandlerContext;

import org.apache.geode.redis.internal.RedisCommandType;
import org.apache.geode.redis.internal.data.ByteArrayWrapper;
import org.apache.geode.redis.internal.executor.RedisResponse;

/**
 * The command class is used in holding a received Redis command. Each sent command resides in an
 * instance of this class. This class is designed to be used strictly by getter and setter methods.
 */
public class Command {

  private final List<byte[]> commandElems;
  private final RedisCommandType commandType;
  private String key;
  private ByteArrayWrapper bytes;

  /**
   * Constructor used to create a static marker Command for shutting down executors.
   */
  Command() {
    commandElems = null;
    commandType = null;
  }

  /**
   * Constructor for {@link Command}. Must initialize Command with a {@link SocketChannel} and a
   * {@link List} of command elements
   *
   * @param commandElems List of elements in command
   */
  public Command(List<byte[]> commandElems) {
    if (commandElems == null || commandElems.isEmpty()) {
      throw new IllegalArgumentException(
          "List of command elements cannot be empty -> List:" + commandElems);
    }
    this.commandElems = commandElems;

    RedisCommandType type;
    try {
      byte[] charCommand = commandElems.get(0);
      String commandName = Coder.bytesToString(charCommand).toUpperCase();
      type = RedisCommandType.valueOf(commandName);
    } catch (Exception e) {
      type = RedisCommandType.UNKNOWN;
    }
    this.commandType = type;
  }

  public boolean isSupported() {
    return commandType.isSupported();
  }

  public boolean isUnsupported() {
    return commandType.isUnsupported();
  }

  public boolean isUnimplemented() {
    return commandType.isUnimplemented();
  }

  public boolean isUnknown() {
    return commandType.isUnknown();
  }

  /**
   * Used to get the command element list
   *
   * @return List of command elements in form of {@link List}
   */
  public List<byte[]> getProcessedCommand() {
    return this.commandElems;
  }

  /**
   * Used to get the command element list
   *
   * @return List of command elements in form of {@link List}
   */
  public List<ByteArrayWrapper> getProcessedCommandWrappers() {
    return this.commandElems.stream().map(ByteArrayWrapper::new).collect(Collectors.toList());
  }

  /**
   * Getter method for the command type
   *
   * @return The command type
   */
  public RedisCommandType getCommandType() {
    return this.commandType;
  }

  /**
   * Convenience method to get a String representation of the key in a Redis command, always at the
   * second position in the sent command array
   *
   * @return Returns the second element in the parsed command list, which is always the key for
   *         commands indicating a key
   */
  public String getStringKey() {
    if (this.commandElems.size() > 1) {
      if (this.bytes == null) {
        this.bytes = new ByteArrayWrapper(this.commandElems.get(1));
        this.key = this.bytes.toString();
      } else if (this.key == null) {
        this.key = this.bytes.toString();
      }
      return this.key;
    } else {
      return null;
    }
  }

  public ByteArrayWrapper getKey() {
    if (this.commandElems.size() > 1) {
      if (this.bytes == null) {
        this.bytes = new ByteArrayWrapper(this.commandElems.get(1));
      }
      return this.bytes;
    } else {
      return null;
    }
  }

  @Override
  public String toString() {
    StringBuilder b = new StringBuilder();
    for (byte[] rawCommand : this.commandElems) {
      b.append(getHexEncodedString(rawCommand));
      b.append(' ');
    }
    return b.toString();
  }

  public static String getHexEncodedString(byte[] data) {
    return getHexEncodedString(data, data.length);
  }

  public static String getHexEncodedString(byte[] data, int size) {
    StringBuilder builder = new StringBuilder();
    for (int i = 0; i < size; i++) {
      byte aByte = data[i];
      if (aByte > 31 && aByte < 127) {
        builder.append((char) aByte);
      } else {
        if (aByte == 0x0a) {
          builder.append("\\n");
        } else if (aByte == 0x0d) {
          builder.append("\\r");
        } else {
          builder.append(String.format("\\x%02x", aByte));
        }
      }
    }

    return builder.toString();
  }

  public RedisResponse execute(ExecutionHandlerContext executionHandlerContext) {
    RedisCommandType type = getCommandType();
    return type.executeCommand(this, executionHandlerContext);
  }

  public boolean isOfType(RedisCommandType type) {
    return type == getCommandType();
  }

  public String wrongNumberOfArgumentsErrorMessage() {
    String result;
    result = String.format("wrong number of arguments for '%s' command",
        getCommandType().toString().toLowerCase());
    return result;
  }

  private long asyncStartTime;

  public void setAsyncStartTime(long start) {
    asyncStartTime = start;
  }

  public long getAsyncStartTime() {
    return asyncStartTime;
  }

  private ChannelHandlerContext channelHandlerContext;

  public void setChannelHandlerContext(ChannelHandlerContext ctx) {
    channelHandlerContext = ctx;
  }

  public ChannelHandlerContext getChannelHandlerContext() {
    return channelHandlerContext;
  }
}
