package net.northking.cctp.upperComputer.driver.agent.command;

import net.northking.cctp.upperComputer.driver.agent.command.protocol.ProtocolCommand;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;

public class MotionEventCommand implements ProtocolCommand<Object> {
    private int source;
    private int action;
    private float x;
    private float y;
    /**
     * 触摸编号，-1表示不是触摸设备输入
     */
    private int touchId = -1;
    private float pressure = 0f;
    private int buttonState = 0;
    private float wheelX = 0;
    private float wheelY = 0;

    public static final int ACTION_DOWN = 0;
    public static final int ACTION_UP = 1;
    public static final int ACTION_MOVE = 2;
    public static final int ACTION_POINTER_DOWN = 5;
    public static final int ACTION_POINTER_UP = 6;
    public static final int ACTION_HOVER_MOVE = 7;
    public static final int ACTION_SCROLL = 8;
    public static final int ACTION_HOVER_ENTER = 9;
    public static final int ACTION_HOVER_EXIT = 10;
    public static final int ACTION_BUTTON_PRESS = 11;
    public static final int ACTION_BUTTON_RELEASE = 12;
    public static final int ACTION_POINTER_INDEX_MASK = 0xff00;
    public static final int ACTION_POINTER_INDEX_SHIFT = 8;

    public static final int BUTTON_PRIMARY = 1;

    public static final int BUTTON_SECONDARY = 1 << 1;

    public static final int BUTTON_TERTIARY = 1 << 2;

    public static final int BUTTON_BACK = 1 << 3;

    public static final int BUTTON_FORWARD = 1 << 4;

    public static final int BUTTON_STYLUS_PRIMARY = 1 << 5;

    public static final int BUTTON_STYLUS_SECONDARY = 1 << 6;

    /**
     * A mask for input source classes.
     * <p>
     * Each distinct input source constant has one or more input source class bits set to
     * specify the desired interpretation for its input events.
     */
    public static final int SOURCE_CLASS_MASK = 0x000000ff;

    /**
     * The input source has no class.
     * <p>
     * It is up to the application to determine how to handle the device based on the device type.
     */
    public static final int SOURCE_CLASS_NONE = 0x00000000;

    /**
     * The input source has buttons or keys.
     * Examples: {@link #SOURCE_KEYBOARD}, {@link #SOURCE_DPAD}.
     */
    public static final int SOURCE_CLASS_BUTTON = 0x00000001;

    /**
     * The input source is a pointing device associated with a display.
     * Examples: {@link #SOURCE_TOUCHSCREEN}, {@link #SOURCE_MOUSE}.
     */
    public static final int SOURCE_CLASS_POINTER = 0x00000002;

    /**
     * The input source is a trackball navigation device.
     * Examples: {@link #SOURCE_TRACKBALL}.
     */
    public static final int SOURCE_CLASS_TRACKBALL = 0x00000004;

    /**
     * The input source is an absolute positioning device not associated with a display
     * (unlike {@link #SOURCE_CLASS_POINTER}).
     */
    public static final int SOURCE_CLASS_POSITION = 0x00000008;

    /**
     * The input source is a joystick.
     */
    public static final int SOURCE_CLASS_JOYSTICK = 0x00000010;

    /**
     * The input source is unknown.
     */
    public static final int SOURCE_UNKNOWN = 0x00000000;

    /**
     * The input source is a keyboard.
     *
     * @see #SOURCE_CLASS_BUTTON
     */
    public static final int SOURCE_KEYBOARD = 0x00000100 | SOURCE_CLASS_BUTTON;

    /**
     * The input source is a DPad.
     *
     * @see #SOURCE_CLASS_BUTTON
     */
    public static final int SOURCE_DPAD = 0x00000200 | SOURCE_CLASS_BUTTON;

    /**
     * The input source is a game pad.
     * (It may also be a {@link #SOURCE_JOYSTICK}).
     *
     * @see #SOURCE_CLASS_BUTTON
     */
    public static final int SOURCE_GAMEPAD = 0x00000400 | SOURCE_CLASS_BUTTON;

    /**
     * The input source is a touch screen pointing device.
     *
     * @see #SOURCE_CLASS_POINTER
     */
    public static final int SOURCE_TOUCHSCREEN = 0x00001000 | SOURCE_CLASS_POINTER;

    /**
     * The input source is a mouse pointing device.
     * This code is also used for other mouse-like pointing devices such as trackpads
     * and trackpoints.
     *
     * @see #SOURCE_CLASS_POINTER
     */
    public static final int SOURCE_MOUSE = 0x00002000 | SOURCE_CLASS_POINTER;

    /**
     * The input source is a stylus pointing device.
     *
     * @see #SOURCE_CLASS_POINTER
     */
    public static final int SOURCE_STYLUS = 0x00004000 | SOURCE_CLASS_POINTER;

    /**
     * The input source is a trackball.
     *
     * @see #SOURCE_CLASS_TRACKBALL
     */
    public static final int SOURCE_TRACKBALL = 0x00010000 | SOURCE_CLASS_TRACKBALL;

    /**
     * The input source is a touch pad or digitizer tablet that is not
     * associated with a display (unlike {@link #SOURCE_TOUCHSCREEN}).
     *
     * @see #SOURCE_CLASS_POSITION
     */
    public static final int SOURCE_TOUCHPAD = 0x00100000 | SOURCE_CLASS_POSITION;

    /**
     * The input source is a touch device whose motions should be interpreted as navigation events.
     * <p>
     * For example, an upward swipe should be as an upward focus traversal in the same manner as
     * pressing up on a D-Pad would be. Swipes to the left, right and down should be treated in a
     * similar manner.
     *
     * @see #SOURCE_CLASS_NONE
     */
    public static final int SOURCE_TOUCH_NAVIGATION = 0x00200000 | SOURCE_CLASS_NONE;

    /**
     * The input source is a joystick.
     * (It may also be a {@link #SOURCE_GAMEPAD}).
     *
     * @see #SOURCE_CLASS_JOYSTICK
     */
    public static final int SOURCE_JOYSTICK = 0x01000000 | SOURCE_CLASS_JOYSTICK;

    /**
     * The input source is a device connected through HDMI-based bus.
     * <p>
     * The key comes in through HDMI-CEC or MHL signal line, and is treated as if it were
     * generated by a locally connected DPAD or keyboard.
     */
    public static final int SOURCE_HDMI = 0x02000000 | SOURCE_CLASS_BUTTON;

    /**
     * A special input source constant that is used when filtering input devices
     * to match devices that provide any type of input source.
     */
    public static final int SOURCE_ANY = 0xffffff00;

    public MotionEventCommand(int source, int action, float x, float y) {
        this(source, action, x, y, 0);
    }

    public MotionEventCommand(int source, int action, float x, float y, int buttonState) {
        this.source = source;
        this.action = action;
        this.x = x;
        this.y = y;
        this.buttonState = buttonState;
    }

    @Override
    public int getCommandId() {
        return 12;
    }

    @Override
    public void doSend(DataOutput output) throws IOException {
        output.writeInt(source);
        output.writeInt(action);
        output.writeFloat(x);
        output.writeFloat(y);
        output.writeInt(buttonState);
        if (source == SOURCE_TOUCHSCREEN) {
            output.writeInt(touchId);
            output.writeFloat(pressure);
        }
        if (action == ACTION_SCROLL) {
            output.writeFloat(wheelX);
            output.writeFloat(wheelY);
        }
    }

    @Override
    public Object buildReceive(DataInput input) throws IOException {
        return null;
    }

    public int getSource() {
        return source;
    }

    public void setSource(int source) {
        this.source = source;
    }

    public int getAction() {
        return action;
    }

    public void setAction(int action) {
        this.action = action;
    }

    public float getX() {
        return x;
    }

    public void setX(float x) {
        this.x = x;
    }

    public float getY() {
        return y;
    }

    public void setY(float y) {
        this.y = y;
    }

    public int getTouchId() {
        return touchId;
    }

    public void setTouchId(int touchId) {
        this.touchId = touchId;
    }

    public float getPressure() {
        return pressure;
    }

    public void setPressure(float pressure) {
        this.pressure = pressure;
    }

    public int getButtonState() {
        return buttonState;
    }

    public void setButtonState(int buttonState) {
        this.buttonState = buttonState;
    }

    public float getWheelX() {
        return wheelX;
    }

    public void setWheelX(float wheelX) {
        this.wheelX = wheelX;
    }

    public float getWheelY() {
        return wheelY;
    }

    public void setWheelY(float wheelY) {
        this.wheelY = wheelY;
    }
}
