package com.videonext;

import java.util.ArrayList;
import java.util.Map;

public class MediaClient {
    static {
        System.loadLibrary("VNMediaClient-jni");
    }

    private long nativeHandle = 0;

    public MediaClient(String host, short port, boolean ssl, long timeout) {
        nativeHandle = nativeInit(host, port, ssl, timeout);
    }

    public AsynchResult<Map<String, Object>> login(String username, String password) {
        return nativeLogin(nativeHandle, username, password);
    }

    /**
     * Get roles
     *
     * @return HashMap of ID->Name
     */
    public AsynchResult<Map<String, String>> getRoles() {
        return nativeGetRoles(nativeHandle);
    }

    /**
     * Get sets
     *
     * @param roleId Role ID (null means all roles accessible by user)
     * @return HashMap of ID->Name
     */
    public AsynchResult<Map<String, String>> getSets(String roleId) {
        return nativeGetSets(nativeHandle, roleId);
    }

    /**
     * Get objects
     *
     * @param setId Set ID (null means all sets accessible by user)
     * @return
     */
    public AsynchResult<Map<String/*id*/, Entity>> getObjects(String setId) {
        return nativeGetObjects(nativeHandle, setId);
    }

    /**
     * Get events
     *
     * @param count
     * @param objId  (null means all objects accessible by user)
     * @param filter comma separated list of events ids or null
     * @return
     */
    public AsynchResult<Map<Integer/*id*/, Entity>> getEvents(String role_id, String filter) {
        return nativeGetEvents(nativeHandle, role_id, filter);
    }

    /**
     * Get JPG snapshot
     *
     * @param objid     Object Id
     * @param ts        Unix timestamp (0 for live snapshot)
     * @param streamNum Number of stream (0 - LowRes, 1 - NormRes, ...)
     * @param metadata  If true - include metadata to jpeg
     * @return
     */
    public AsynchResult<byte[]> getSnapshot(String objid, long ts, int streamNum, boolean metadata) {
        return nativeGetSnapshot(nativeHandle, objid, ts, streamNum, metadata);
    }

    /**
     * Get media URL
     *
     * @param videoObjId
     * @param audioObjId          Can be 0
     * @param tsStart             Archive start time (UTC timestamp) or 0 (live)
     * @param tsEnd               Archive end time (UTC timestamp) or 0 (live)
     * @param transcodeCodec      Optional transcode to different media format. Only "h264" currently supported. null if none transode needed
     * @param transcodeResolution If transcoding enabled frame dimensions in form "WxH", ex: "320x240"
     * @param analytics
     * @return
     */
    public AsynchResult<String> getMediaURL(String videoObjId, String audioObjId,
                                            long tsStart, long tsEnd,
                                            String transcodeCodec, String transcodeResolution,
                                            int analytics) {
        return nativeGetMediaURL(nativeHandle, videoObjId, audioObjId, tsStart, tsEnd,
                transcodeCodec, transcodeResolution, analytics);
    }

    /**
     * Register mobile device as camera iStream type in Stratus
     *
     * @param hwid
     * @param name
     * @return
     */
    public AsynchResult<String> addObject(String hwid, String name) {
        return nativeAddObject(nativeHandle, hwid, name);
    }

    /**
     * Performs ptz command
     *
     * @param objid Object ID
     * @param mode  PTZ mode
     * @param cmd   command in verbal form "left|right|up|down|downleft|upright|downright|upleft|in|out"
     * @return
     */
    public AsynchResult<Integer> performPTZCommand(String objid, String mode, String cmd) {
        return nativePerformPTZCommand(nativeHandle, objid, mode, cmd);
    }

    /**
     * Get GEO positions
     *
     * @param objIds Array of Objects IDs. Return positions only for dynamic cameras if array is empty
     * @return HashMap of [OBJID]->[POSITION JSON]
     */
    public AsynchResult<Map<String, String>> getGEO(String objIds[]) {
        return nativeGetGEO(nativeHandle, objIds);
    }

    /**
     * Get announcements
     *
     * @param count number of announcements to return
     * @return HashMap[eventid, HashMap[time_t, HashMap[attr, value]]]
     */
    public AsynchResult<Map<Integer, Map<Integer, Map<String, String>>>> getAnnouncements(int count) {
        return nativeGetAnnouncements(nativeHandle, count);
    }

    /**
     * Get announce role and user lists
     *
     * @return ArrayList of 2 HashMap [attr]->[value]. 1st is a Role list, 2nd is a User list
     */
    public AsynchResult<ArrayList<Map<String, String>>> getAnnounceRoleUserList() {
        return nativeGetAnnounceRoleUserList(nativeHandle);
    }

    public AsynchResult<Integer> markAnnounceEventAsRead(String postData) {
        return nativeMarkAnnounceEventAsRead(nativeHandle, postData);
    }

    public AsynchResult<Integer> announceEventToRole(String postData) {
        return nativeAnnounceEventToRole(nativeHandle, postData);
    }

    public AsynchResult<Integer> announceEventToUsers(String postData) {
        return nativeAnnounceEventToUsers(nativeHandle, postData);
    }

    public AsynchResult<Integer> submitAction(int eventId, String action, String roleId, String postData) {
        return nativeSubmitAction(nativeHandle, eventId, action, roleId, postData);
    }

    public AsynchResult<Map<String, String>> getServerInfo() {
        return nativeGetServerInfo(nativeHandle);
    }

    private native long nativeInit(String host, short port, boolean ssl, long timeout);
    private native AsynchResult<Map<String, Object>> nativeLogin(long nativeHandle, String username, String password);
    private native AsynchResult<Map<String, String>> nativeGetRoles(long nativeHandle);
    private native AsynchResult<Map<String, String>> nativeGetSets(long nativeHandle, String roleId);
    private native AsynchResult<Map<String, Entity>> nativeGetObjects(long nativeHandle, String setId);
    private native AsynchResult<Map<Integer, Entity>> nativeGetEvents(long nativeHandle, String role_id, String filter);
    private native AsynchResult<byte[]> nativeGetSnapshot(long nativeHandle, String objid, long ts, int streamNum, boolean metadata);
    private native AsynchResult<String> nativeGetMediaURL(long nativeHandle, String videoObjId, String audioObjId,
                                                          long tsStart, long tsEnd,
                                                          String transcodeCodec, String transcodeResolution,
                                                          int analytics);
    private native AsynchResult<String> nativeAddObject(long nativeHandle, String hwid, String name);
    private native AsynchResult<Integer> nativePerformPTZCommand(long nativeHandle, String objid, String mode, String cmd);
    private native AsynchResult<Map<String, String>> nativeGetGEO(long nativeHandle, String objIds[]);
    private native AsynchResult<Map<Integer, Map<Integer, Map<String, String>>>> nativeGetAnnouncements(long nativeHandle, int count);
    private native AsynchResult<ArrayList<Map<String, String>>> nativeGetAnnounceRoleUserList(long nativeHandle);
    private native AsynchResult<Integer> nativeMarkAnnounceEventAsRead(long nativeHandle, String postData);
    private native AsynchResult<Integer> nativeAnnounceEventToRole(long nativeHandle, String postData);
    private native AsynchResult<Integer> nativeAnnounceEventToUsers(long nativeHandle, String postData);
    private native AsynchResult<Integer> nativeSubmitAction(long nativeHandle, int eventId, String action, String roleId, String postData);
    private native AsynchResult<Map<String, String>> nativeGetServerInfo(long nativeHandle);
    private native long nativeDestroy(long nativeHandle);
}
